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/

    Strange behavior with cheat_on_open – or that might have nothing to do with it

    General Code/Help
    2
    2
    189
    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.
    • Jeff Vahue
      Jeff Vahue last edited by Jeff Vahue

      Implementing a simple strategy that looks at the ROC(10) of SPY monthly data. If ROC xAbove 0 go long at the open of the next month (via daily data), otherwise if ROC xBelow 0 go short at the open of the next month (via daily data).
      Monthly data from Yahoo is tagged against the first of the month, not the last day. To achieve what I want I provide two data feeds, daily SPY (to do the trades against) and Monthly SPY to trigger the trades. I have set cheat_on_open to true and configured the broker as well. In <strategy>.next_open I determine if the month is different from the last month (i.e., the first trading day of a new month). At this point I look at the current and previous value of ROC(10, monthly) to determine if any trade needs to be done.
      The weird thing is the values that are being served up for ROC. Sometimes they match my calculated values, and sometimes they repeat or skip forward. I can’t understand what is happening. The blue heading indicates data that came out of Backtrader versus the Yahoo data and my calculated ROC value in grey/orange.

      Any ideas?

      0_1561842707453_rocData.JPG

      Here is the main setup

              print('---------- Start: %s - End: %s ----------' % (fromdate.date(), todate.date()))
      
              # Create a cerebro entity, runonce handle mixed timeBase indicators
              # cerebro0 is strategy, cerebro_bnh is Buy and hold to compare against
              cerebro0 = CerebroAnalyzer.CerebroAnalyzer(runonce=False, cheat_on_open=True)
              cerebro_bnh = CerebroAnalyzer.CerebroAnalyzer(runonce=False, cheat_on_open=True)
              cerebros = (cerebro0, cerebro_bnh)
      
              # Add a strategy
              if 1:
                  cerebro0.addstrategy(sRocSpx.RocCross, rocPeriod=10, emaRocPeriod=1, eLim=0.0)
              else:
                  cerebro0.optstrategy(sRocSpx.RocCross, rocPeriod=range(4, 20, 2))
      
              # Create a Data Feed
              data = bt.feeds.YahooFinanceCSVData(
                  dataname=os.path.join(datapath, 'SPY-1D.csv'),
                  fromdate=fromdate,        # Do not pass values before this date
                  todate=todate,            # Do not pass values after this date
                  reverse=False,            #
              )
      
              data1 = bt.feeds.YahooFinanceCSVData(
                  dataname=os.path.join(datapath, 'SPY-1M.csv'),
                  fromdate=fromdate,        # Do not pass values before this date
                  todate=todate,            # Do not pass values after this date
                  reverse=False,            #
                  timeframe=bt.TimeFrame.Months,
              )
      
              stake = 100
              comm = 5.0/stake
              for c in cerebros:
                  # Add the Data Feed to Cerebro
                  c.adddata(data)
                  c.adddata(data1)
                  # Set our desired cash start
                  c.broker.setcash(100000.0)
                  c.broker.set_coo(True)
      

      Here is the strategy

          params = {
              ('emaRocPeriod', 19),
              ('eLim', 0.003),
              ('rocPeriod', 10),
          }
      
          def __init__(self, *args, **kwArgs):
              super().__init__(*args, **kwArgs)
      
              self.dailyClose = self.datas[0].close
              self.monthClose = self.datas[1].close
      
              self.roc = bt.ind.ROC(self.monthClose, period=self.p.rocPeriod)
              #self.roc1 = self.roc(-1)
      
              # To keep track of pending orders and buy price/commission
              self.order = None
              self.buyprice = None
              self.buycomm = None
              self.tradeOpen = False
      
              self.rocCurrent = None
              bt.Indicator.csv = True
      
              self.lastMonth = None  # what was the last month that we looked at the close
              self.monthEnd = None   # what day 1-31 is the last trading day of the month
      
          #------------------------------------------------------------------------
          def next_open(self):
              """ We decide on the 1st day of the month if we need to trade based on how the monthly ROC
              finsihed
              """
              nowIs = self.datas[0].datetime.date(0)
              if self.lastMonth != nowIs.month:
                  self.lastMonth = nowIs.month
      
                  rocCurrent = self.roc.roc[0]
                  self.rocCurrent = rocCurrent
      
                  rocLast = self.roc.roc[-1] #self.roc1[0]
                  #value1 = self.ema_roc1.ema[0]
      
                  xa = rocCurrent > 0 and rocLast <= 0
                  xb = rocCurrent < 0 and rocLast >= 0
      
                  # Check if an order is pending ... if yes, we cannot send a 2nd one
                  if self.order:
                      return
      
                  self.log('>>> %7.3f,%7.4f,%7.4f,%5s,%5s' % (self.monthClose[0],
                                                              rocCurrent, rocLast, xa, xb))
      
                  # Check if we are not in the market (no open)
                  if self.tradeSize <= 0 and xa:
                      # Not yet ... we MIGHT BUY if ...
                      #if xa: # and (emaRoc0 <= -self.p.eLim or self.p.eLim == 0.0):
      
                      # BUY, BUY, BUY!!! (with all possible default parameters)
                      self.log('BUY CREATE, %.2f' % self.dailyClose[0])
      
                      # Simply log the closing price of the series from the reference
                      self.log('Close, %.2f, %.2f, %.2f, xa:%5s xb:%5s' % (
                          self.monthClose[-1], rocCurrent, rocLast, xa, xb))
      
                      # Keep track of the created order to avoid a 2nd order
                      size = 100 if self.tradeSize == 0 else 200
                      self.order = self.buy(size=size)
      
                  elif self.tradeSize >= 0 and xb:
                      #if xb: # and (emaRoc0 >= self.p.eLim or self.p.eLim == 0.0):
                      #if self.dataclose[0] < self.sma[0]:
                          # SELL, SELL, SELL!!! (with all possible default parameters)
                      self.log('SELL CREATE, %.2f' % self.dailyClose[0])
      
                      # Simply log the closing price of the series from the reference
                      self.log('Close, %.2f, %.2f, %.2f, xa:%s xb:%s' % (
                          self.monthClose[0], rocCurrent, rocLast, xa, xb))
      
                      # Keep track of the created order to avoid a 2nd order
                      size = 100 if self.tradeSize == 0 else 200
                      # go short
                      self.order = self.sell(size=size)
      
      1 Reply Last reply Reply Quote 0
      • B
        backtrader administrators last edited by

        When using cheat-on-open:

        • The indicators have not been recalculated and hold the values that were last seen during the previous cycle in the equivalent xxx regular methods

        From: Docs - Cheat-On-Open

        1 Reply Last reply Reply Quote 0
        • 1 / 1
        • First post
          Last post
        Copyright © 2016, 2017, 2018, 2019, 2020, 2021 NodeBB Forums | Contributors