Navigation

    Backtrader Community

    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/

    BackTrader, algorithm, buy if price decreasing

    General Code/Help
    4
    9
    214
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • Y
      YELNAr last edited by

      In result, didn't print self.dataclose[-2], can not identify it

          if self.datastatus and len(self.orderid) < 1:
              print('0 STEPPP')
              if self.dataclose[0] < self.dataclose[-1]:
                  print("1 Step", self.dataclose[0], self.dataclose[-1])
                  if self.dataclose[-1] < self.dataclose[-2]:
                      print("YEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEES")
                      # BUY, BUY, BUY!!! (with default parameters)
                      self.log('BUY CREATE, %.2f' % self.dataclose[0])
      
                      # Keep track of the created order to avoid a 2nd order
                      self.order = self.buy()
              else:
                  print("NOOO")
      1 Reply Last reply Reply Quote 0
      • S
        scottz1 last edited by

        What is your question? There isn't a print statement for dataclose[-2].

        1 Reply Last reply Reply Quote 1
        • Y
          YELNAr last edited by

          if self.dataclose[-1] < self.dataclose[-2]:
          self.dataclose[-2] can not identify it

          1 Reply Last reply Reply Quote 0
          • S
            scottz1 last edited by

            I'd suggest to show all your code. If the example is long, try to eliminate parts that are not required to repro the error. Also, include the exact error message.

            1 Reply Last reply Reply Quote 2
            • Y
              YELNAr last edited by

              from future import (absolute_import, division, print_function,
              unicode_literals)

              import datetime # For datetime objects
              import os.path # To manage paths
              import sys # To find out the script name (in argv[0])

              import argparse
              import datetime
              import backtrader as bt

              from backtrader.utils import flushfile

              Create a Stratey

              class TestStrategy(bt.Strategy):
              params = dict(
                  # smaperiod=5,
                  trade=False,
                  stake=10,
                  exectype=bt.Order.Market,
                  stopafter=0,
                  valid=None,
              
                  upper=2.1,
                  cancel=0,
                  donotsell=False,
              )
              
              def __init__(self):
                  # Keep a reference to the "close" line in the data[0] dataseries
                  self.orderid = list()
                  self.order = None
                  self.dataclose = self.datas[0].close
                  self.upper_limit = self.p.upper
                  # self.counttostop = 0
                  self.datastatus = 0
                  self.bar_executed = 0
              
              def log(self, txt, dt=None):
                  ''' Logging function fot this strategy'''
                  dt = dt or self.datas[0].datetime.date(0)
                  print('%s, %s' % (dt.isoformat(), txt))
              
              def notify_data(self, data, status, *args, **kwargs):
                  print('*' * 5, 'DATA NOTIF:', data._getstatusname(status), *args)
                  if status == data.LIVE:
                      # self.counttostop = self.p.stopafter
                      self.datastatus = 1
              
              def notify_store(self, msg, *args, **kwargs):
                  print('*' * 5, 'STORE NOTIF:', msg)
              
              def notify_order(self, order):
                  if order.status in [order.Completed, order.Cancelled, order.Rejected]:
                      self.order = None
              
                  # Check if an order has been completed
                  # Attention: broker could reject order if not enough cash
              
                  # if order.status in [order.Completed]:
                  #     if order.isbuy():
                  #         self.log('BUY EXECUTED, %.2f' % order.executed.price)
                  #     elif order.issell():
                  #         self.log('SELL EXECUTED, %.2f' % order.executed.price)
              
                  #     self.bar_executed = len(self)
                  print('-' * 50, 'ORDER BEGIN', datetime.datetime.now())
                  print(order)
                  print('-' * 50, 'ORDER END')
              
                  # elif order.status in [order.Canceled, order.Margin, order.Rejected]:
                  #     self.log('Order Canceled/Margin/Rejected')
              
                  # Write down: no pending order
                  # self.order = None
              
              def notify_trade(self, trade):
                  print('-' * 50, 'TRADE BEGIN', datetime.datetime.now())
                  print(trade)
                  print('-' * 50, 'TRADE END')
              
              def prenext(self):
                  self.next(frompre=True)
              
              def next(self, frompre=False):
                  # Simply log the closing price of the series from the reference
                  txt = list()
                  txt.append('%04d' % len(self))
                  dtfmt = '%Y-%m-%dT%H:%M:%S.%f'
                  txt.append('%s' % self.data.datetime.datetime(0).strftime(dtfmt))
                  txt.append('{}'.format(self.data.close[0]))
                  txt.append('{}'.format(self.data.close[-1]))
                  print(', '.join(txt))
              
                  # if len(self.datas) > 1:
                  #     txt = list()
                  #     txt.append('%04d' % len(self))
                  #     dtfmt = '%Y-%m-%dT%H:%M:%S.%f'
                  #     txt.append('%s' % self.data1.datetime.datetime(0).strftime(dtfmt))
                  #     txt.append('{}'.format(self.data1.close[0]))
                  #     # txt.append('{}'.format(self.data.close[-1]))
                  #     # txt.append('{}'.format(self.data.close[-2]))
                  #     txt.append('{}'.format(float('NaN')))
                  #     print(', '.join(txt))
              
                  # if self.counttostop:  # stop after x live lines
                  #     self.counttostop -= 1
                  #     if not self.counttostop:
                  #         self.env.runstop()
                  #         return
              
                  if not self.p.trade:
                      return
              
                  if self.datastatus and len(self.orderid) < 1:
                      print('0 STEPPP')
                      if self.dataclose[0] < self.dataclose[-1]:
                          print("1 Step", self.dataclose[0], self.dataclose[-1])
                          if self.dataclose[-1] < self.upper_limit:
                              print("YEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEES")
                              # BUY, BUY, BUY!!! (with default parameters)
                              self.log('BUY CREATE, %.2f' % self.dataclose[0])
              
                              # Keep track of the created order to avoid a 2nd order
                              self.order = self.buy()
                      else:
                          print("NOOO")
              
                  # elif self.position.size > 0 and not self.p.donotsell:
                  #     if self.order is None:
                  #         self.order = self.sell(size=self.p.stake // 2,
                  #                                exectype=bt.Order.Market,
                  #                                price=self.data0.close[0])
                  #     self.cancel(self.order)
                  # elif self.order is not None and self.p.cancel:
                  #     if self.datastatus > self.p.cancel:
                  #         self.cancel(self.order)
              
              
                  if self.datastatus:
                      self.datastatus += 1
              
              def start(self):
                  if self.data0.contractdetails is not None:
                      print('Timezone from ContractDetails: {}'.format(
                          self.data0.contractdetails.m_timeZoneId))
                  #
                  # header = ['Datetime', 'Open', 'High', 'Low', 'Close', 'Volume',
                  #           'OpenInterest']
                  header = ['Datetime', 'Close']
                  print(', '.join(header))
              
                  self.done = False
              

              def runstrategy():
              args = parse_args()

              # Create a cerebro
              cerebro = bt.Cerebro()
              
              storekwargs = dict(
                  host=args.host, port=args.port,
                  clientId=args.clientId, timeoffset=not args.no_timeoffset,
                  reconnect=args.reconnect, timeout=args.timeout,
                  notifyall=args.notifyall, _debug=args.debug
              )
              
              if args.usestore:
                  ibstore = bt.stores.IBStore(**storekwargs)
              
              if args.broker:
                  if args.usestore:
                      broker = ibstore.getbroker()
                  else:
                      broker = bt.brokers.IBBroker(**storekwargs)
              
                  cerebro.setbroker(broker)
              
              timeframe = bt.TimeFrame.TFrame(args.timeframe)
              if args.resample or args.replay:
                  datatf = bt.TimeFrame.Ticks
                  datacomp = 1
              else:
                  datatf = timeframe
                  datacomp = args.compression
              
              fromdate = None
              if args.fromdate:
                  dtformat = '%Y-%m-%d' + ('T%H:%M:%S' * ('T' in args.fromdate))
                  fromdate = datetime.datetime.strptime(args.fromdate, dtformat)
              
              IBDataFactory = ibstore.getdata if args.usestore else bt.feeds.IBData
              
              datakwargs = dict(
                  timeframe=datatf, compression=datacomp,
                  historical=args.historical, fromdate=fromdate,
                  rtbar=args.rtbar,
                  qcheck=args.qcheck,
                  what=args.what,
                  backfill_start=not args.no_backfill_start,
                  backfill=not args.no_backfill,
                  latethrough=args.latethrough,
                  tz=args.timezone
              )
              
              if not args.usestore and not args.broker:  # neither store nor broker
                  datakwargs.update(storekwargs)  # pass the store args over the data
              
              data0 = IBDataFactory(dataname=args.data0, **datakwargs)
              
              data1 = None
              if args.data1 is not None:
                  data1 = IBDataFactory(dataname=args.data1, **datakwargs)
              
              rekwargs = dict(
                  timeframe=timeframe, compression=args.compression,
                  bar2edge=not args.no_bar2edge,
                  adjbartime=not args.no_adjbartime,
                  rightedge=not args.no_rightedge,
                  takelate=not args.no_takelate,
              )
              
              if args.replay:
                  cerebro.replaydata(dataname=data0, **rekwargs)
              
                  if data1 is not None:
                      cerebro.replaydata(dataname=data1, **rekwargs)
              
              elif args.resample:
                  cerebro.resampledata(dataname=data0, **rekwargs)
              
                  if data1 is not None:
                      cerebro.resampledata(dataname=data1, **rekwargs)
              
              else:
                  cerebro.adddata(data0)
                  if data1 is not None:
                      cerebro.adddata(data1)
              
              if args.valid is None:
                  valid = None
              else:
                  datetime.timedelta(seconds=args.valid)
              # Add the strategy
              cerebro.addstrategy(TestStrategy,
                                  # smaperiod=args.smaperiod,
                                  trade=args.trade,
                                  exectype=bt.Order.ExecType(args.exectype),
                                  stake=args.stake,
                                  stopafter=args.stopafter,
                                  valid=valid,
                                  cancel=args.cancel,
                                  donotsell=args.donotsell)
              
              print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
              
              # Live data ... avoid long data accumulation by switching to "exactbars"
              cerebro.run(exactbars=args.exactbars)
              
              # Print out the final result
              print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
              
              if args.plot and args.exactbars < 1:  # plot if possible
                  cerebro.plot()
              

              def parse_args():
              parser = argparse.ArgumentParser(
              formatter_class=argparse.ArgumentDefaultsHelpFormatter,
              description='Test Interactive Brokers integration')

              parser.add_argument('--exactbars', default=1, type=int,
                                  required=False, action='store',
                                  help='exactbars level, use 0/-1/-2 to enable plotting')
              
              parser.add_argument('--plot',
                                  required=False, action='store_true',
                                  help='Plot if possible')
              
              parser.add_argument('--stopafter', default=0, type=int,
                                  required=False, action='store',
                                  help='Stop after x lines of LIVE data')
              
              parser.add_argument('--usestore',
                                  required=False, action='store_true',
                                  help='Use the store pattern')
              
              parser.add_argument('--notifyall',
                                  required=False, action='store_true',
                                  help='Notify all messages to strategy as store notifs')
              
              parser.add_argument('--debug',
                                  required=False, action='store_true',
                                  help='Display all info received form IB')
              
              parser.add_argument('--host', default='127.0.0.1',
                                  required=False, action='store',
                                  help='Host for the Interactive Brokers TWS Connection')
              
              parser.add_argument('--qcheck', default=0.5, type=float,
                                  required=False, action='store',
                                  help=('Timeout for periodic '
                                        'notification/resampling/replaying check'))
              
              parser.add_argument('--port', default=7496, type=int,
                                  required=False, action='store',
                                  help='Port for the Interactive Brokers TWS Connection')
              
              parser.add_argument('--clientId', default=None, type=int,
                                  required=False, action='store',
                                  help='Client Id to connect to TWS (default: random)')
              
              parser.add_argument('--no-timeoffset',
                                  required=False, action='store_true',
                                  help=('Do not Use TWS/System time offset for non '
                                        'timestamped prices and to align resampling'))
              
              parser.add_argument('--reconnect', default=3, type=int,
                                  required=False, action='store',
                                  help='Number of recconnection attempts to TWS')
              
              parser.add_argument('--timeout', default=3.0, type=float,
                                  required=False, action='store',
                                  help='Timeout between reconnection attempts to TWS')
              
              parser.add_argument('--data0', default=None,
                                  required=True, action='store',
                                  help='data 0 into the system')
              
              parser.add_argument('--data1', default=None,
                                  required=False, action='store',
                                  help='data 1 into the system')
              
              parser.add_argument('--timezone', default=None,
                                  required=False, action='store',
                                  help='timezone to get time output into (pytz names)')
              
              parser.add_argument('--what', default=None,
                                  required=False, action='store',
                                  help='specific price type for historical requests')
              
              parser.add_argument('--no-backfill_start',
                                  required=False, action='store_true',
                                  help='Disable backfilling at the start')
              
              parser.add_argument('--latethrough',
                                  required=False, action='store_true',
                                  help=('if resampling replaying, adjusting time '
                                        'and disabling time offset, let late samples '
                                        'through'))
              
              parser.add_argument('--no-backfill',
                                  required=False, action='store_true',
                                  help='Disable backfilling after a disconnection')
              
              parser.add_argument('--rtbar', default=False,
                                  required=False, action='store_true',
                                  help='Use 5 seconds real time bar updates if possible')
              
              parser.add_argument('--historical',
                                  required=False, action='store_true',
                                  help='do only historical download')
              
              parser.add_argument('--fromdate',
                                  required=False, action='store',
                                  help=('Starting date for historical download '
                                        'with format: YYYY-MM-DD[THH:MM:SS]'))
              
              # parser.add_argument('--smaperiod', default=5, type=int,
              #                     required=False, action='store',
              #                     help='Period to apply to the Simple Moving Average')
              
              pgroup = parser.add_mutually_exclusive_group(required=False)
              
              pgroup.add_argument('--replay',
                                  required=False, action='store_true',
                                  help='replay to chosen timeframe')
              
              pgroup.add_argument('--resample',
                                  required=False, action='store_true',
                                  help='resample to chosen timeframe')
              
              parser.add_argument('--timeframe', default=bt.TimeFrame.Names[0],
                                  choices=bt.TimeFrame.Names,
                                  required=False, action='store',
                                  help='TimeFrame for Resample/Replay')
              
              parser.add_argument('--compression', default=1, type=int,
                                  required=False, action='store',
                                  help='Compression for Resample/Replay')
              
              parser.add_argument('--no-takelate',
                                  required=False, action='store_true',
                                  help=('resample/replay, do not accept late samples '
                                        'in new bar if the data source let them through '
                                        '(latethrough)'))
              
              parser.add_argument('--no-bar2edge',
                                  required=False, action='store_true',
                                  help='no bar2edge for resample/replay')
              
              parser.add_argument('--no-adjbartime',
                                  required=False, action='store_true',
                                  help='no adjbartime for resample/replay')
              
              parser.add_argument('--no-rightedge',
                                  required=False, action='store_true',
                                  help='no rightedge for resample/replay')
              
              parser.add_argument('--broker',
                                  required=False, action='store_true',
                                  help='Use IB as broker')
              
              parser.add_argument('--trade',
                                  required=False, action='store_true',
                                  help='Do Sample Buy/Sell operations')
              
              parser.add_argument('--donotsell',
                                  required=False, action='store_true',
                                  help='Do not sell after a buy')
              
              parser.add_argument('--exectype', default=bt.Order.ExecTypes[0],
                                  choices=bt.Order.ExecTypes,
                                  required=False, action='store',
                                  help='Execution to Use when opening position')
              
              parser.add_argument('--stake', default=10, type=int,
                                  required=False, action='store',
                                  help='Stake to use in buy operations')
              
              parser.add_argument('--valid', default=None, type=int,
                                  required=False, action='store',
                                  help='Seconds to keep the order alive (0 means DAY)')
              
              parser.add_argument('--cancel', default=0, type=int,
                                  required=False, action='store',
                                  help=('Cancel a buy order after n bars in operation,'
                                        ' to be combined with orders like Limit'))
              
              return parser.parse_args()
              

              if name == 'main':
              runstrategy()

              B 1 Reply Last reply Reply Quote 0
              • A
                ab_trader last edited by

                In the script you shown self.dataclose[-2] is not called. Also please use ``` to block the code, will be easier to review. Would be nice to see short version which generates the problem as @scottz1 proposed.

                1 Reply Last reply Reply Quote 1
                • Y
                  YELNAr last edited by

                  To check these statements, I tried to use like print("0 STEPPP"), and in result, it printed only
                  0 and 1 Step, but 2 step it is correct and does not printed ("YEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEES").
                  I checked when I wrote print(self.dataclose[-2]) it is printed today's value

                       if self.datastatus and len(self.orderid) < 1:
                          print('0 STEPPP')
                          if self.dataclose[0] < self.dataclose[-1]:
                              print("1 Step", self.dataclose[0], self.dataclose[-1])
                              if self.dataclose[-1] < self.dataclose[-2]:
                                  print("YEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEES")
                                  # BUY, BUY, BUY!!! (with default parameters)
                                  self.log('BUY CREATE, %.2f' % self.dataclose[0])
                  
                                  # Keep track of the created order to avoid a 2nd order
                                  self.order = self.buy()
                          else:
                              print("NOOO")
                  A 1 Reply Last reply Reply Quote 0
                  • A
                    ab_trader @YELNAr last edited by

                    @YELNAr you use two different scripts in this post. One of them uses dataclose[-2] and one don't. Would you be so kind and post the script which causes the problem. But removed from that script all un-necessary parts.

                    1 Reply Last reply Reply Quote 1
                    • B
                      backtrader administrators @YELNAr last edited by

                      @YELNAr said in BackTrader, algorithm, buy if price decreasing:

                      def __init__(self):
                          # Keep a reference to the "close" line in the data[0] dataseries
                          self.orderid = list()
                          self.order = None
                          self.dataclose = self.datas[0].close
                          self.upper_limit = self.p.upper
                          # self.counttostop = 0
                          self.datastatus = 0
                          self.bar_executed = 0
                      

                      Your __init__ statement contain no indicators and no constraints to ensure buffers are filled with a minimum. This means that when you enter next the first time anything which uses [-1] and [-2] is actually broken, because the minimum period is 1, which means the code goes directly into next as soon as data is available.

                      My recommendation: learn backtesting loading data from a file and not playing with InteractiveBrokers.

                      In the meanwhile read this about the minimum period: https://www.backtrader.com/docu/operating/

                      1 Reply Last reply Reply Quote 0
                      • 1 / 1
                      • First post
                        Last post
                      Copyright © 2016, 2017, 2018 NodeBB Forums | Contributors
                      $(document).ready(function () { app.coldLoad(); }); }