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/

    next() beginning before minimum period

    General Code/Help
    3
    7
    876
    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.
    • xenide
      xenide last edited by xenide

      Hi I have the following code

      class FirstStrat (bt.Strategy):
      
          params = (
              ('system1EntryPeriod', 20),
              ('system1ExitPeriod', 10),
              ('system2EntryPeriod', 55),
              ('system2ExitPeriod', 20),
              ('printlog', True),
          )
      
          def __init__(self):
              # self.dataclose = self.datas[0].close
              # To keep track of pending orders
              self.order = None
              self.buyprice = None
              self.buyComm = None
      
              # Tried with just self.data
              # It uses CLOSE instead of high
              self.S1HEntry = bt.indicators.Highest(self.data.high,
                                               period=self.p.system1EntryPeriod)
              self.S2HEntry = bt.indicators.Highest(self.data.high,
                                               period=self.p.system2EntryPeriod)
              self.S1LExit = bt.indicators.Lowest(self.data.low,
                                               period=self.p.system1ExitPeriod)
              self.S2LExit = bt.indicators.Lowest(self.data.low,
                                               period=self.p.system2ExitPeriod)
              
              self.S1LEntry = bt.indicators.Lowest(self.data.low,
                                              period=self.p.system1EntryPeriod)
              self.S2LEntry = bt.indicators.Lowest(self.data.low,
                                              period=self.p.system2EntryPeriod)
              self.S1HExit = bt.indicators.Highest(self.data.high,
                                               period=self.p.system1ExitPeriod)
              self.S2HExit = bt.indicators.Highest(self.data.high,
                                               period=self.p.system2ExitPeriod)
      

      I'm using one data feed -- YahooFinanceData. The problem I'm facing is that next() should be called when we have 55 data points, but for me it's called right from the first data point. After some debugging I see that self._minperiod = 55 while self._minperiods = [1].

      What am I not getting?

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

        You have a lot more code, which probably is the root of your problem and some more information which would be needed, like timeframes you use, how you load the data ...

        Posting a complete working sample is what helps.

        1 Reply Last reply Reply Quote 0
        • xenide
          xenide last edited by

          Understood. Here's the full code.

          Again, the problem is that next() runs on the first candle with all the indicators as nan instead of running after the expected 55 candles.

          import backtrader as bt
          import pdb
          
          from enum import Enum, auto
          
          class TurtleSystem(Enum):
              SYSTEM_1 = auto()
              SYSTEM_2 = auto()
              NO_POSITION = auto()
          
          
          class FirstStrat (bt.Strategy):
          
              params = (
                  ('system1EntryPeriod', 20),
                  ('system1ExitPeriod', 10),
                  ('system2EntryPeriod', 55),
                  ('system2ExitPeriod', 20),
                  ('printlog', True),
              )
          
              def __init__(self):
                  # self.dataclose = self.datas[0].close
                  # To keep track of pending orders
                  self.order = None
                  self.buyprice = None
                  self.buyComm = None
          
                  # Tried with just self.data
                  # It uses CLOSE instead of high
                  self.S1HEntry = bt.indicators.Highest(self.data.high,
                                                   period=self.p.system1EntryPeriod)
                  self.S2HEntry = bt.indicators.Highest(self.data.high,
                                                   period=self.p.system2EntryPeriod)
                  self.S1LExit = bt.indicators.Lowest(self.data.low,
                                                   period=self.p.system1ExitPeriod)
                  self.S2LExit = bt.indicators.Lowest(self.data.low,
                                                   period=self.p.system2ExitPeriod)
                  
                  self.S1LEntry = bt.indicators.Lowest(self.data.low,
                                                  period=self.p.system1EntryPeriod)
                  self.S2LEntry = bt.indicators.Lowest(self.data.low,
                                                  period=self.p.system2EntryPeriod)
                  self.S1HExit = bt.indicators.Highest(self.data.high,
                                                   period=self.p.system1ExitPeriod)
                  self.S2HExit = bt.indicators.Highest(self.data.high,
                                                   period=self.p.system2ExitPeriod)
          
          
                  self.currentPositionSystem = TurtleSystem.NO_POSITION
          
              def log(self, txt, dt=None, doprint=False):
                  ''' Logging function fot this strategy'''
                  if self.params.printlog or doprint:
                      dt = dt or self.datas[0].datetime.date(0)
                      print('%s, %s' % (dt.isoformat(), txt))
          
              def next(self):
                  self.log('highest %.2f' % self.S1HEntry[0])
          
                  # Check if an order is pending ... if yes, we cannot send a 2nd one
                  if self.order:
                      return
          
                  # We are already in the market
                  if self.position:
          
                      # pdb.set_trace()
                      
                      # If this is a short position
                      if self.position.size < 0:
          
                          # Check if exit criteria is reached
                          if self.currentPositionSystem == TurtleSystem.SYSTEM_1 and \
                              self.data.close[0] > self.S1HExit[-1]:
          
                              self.order = self.buy()
          
                          elif self.currentPositionSystem == TurtleSystem.SYSTEM_2 and \
                                  self.data.close[0] > self.S2HExit[-1]:
          
                              self.order = self.buy()
          
                      # This is a long position
                      elif self.position.size > 0:
                          if self.currentPositionSystem == TurtleSystem.SYSTEM_1 and \
                              self.data.close[0] < self.S1LExit[-1]:
          
                              self.order = self.sell()
          
                          elif self.currentPositionSystem == TurtleSystem.SYSTEM_2 and \
                              self.data.close[0] < self.S2LExit[-1]:
          
                              self.order = self.sell()
                      else:
                          assert False, "Position size zero. Should not happen"
                      
          
                  # We're not in the market yet
                  else:
                      # pdb.set_trace()
                      if self.data.close[0] > self.S1HEntry[-1]:
                          # Need to do other checks before entering position
          
                          self.order = self.buy()
                          self.currentPositionSystem = TurtleSystem.SYSTEM_1
                      # Breaking 55H
                      elif self.data.close[0] > self.S2HEntry[-1]:
          
                          # Always take this entry
                          self.order = self.buy()
                          self.currentPositionSystem = TurtleSystem.SYSTEM_2
          
                      elif self.data.close[0] < self.S1LEntry[-1]:
                          # Need to do other checks before entering this position
          
                          self.order = self.sell()
                          self.currentPositionSystem = TurtleSystem.SYSTEM_1
          
                      # Breaking 55L
                      elif self.data.close[0] < self.S2LEntry[-1]:
                          # Always take this entry
                          self.order = self.sell()
                          self.currentPositionSystem = TurtleSystem.SYSTEM_2
          
                      else:
                          self.log("Do nothing")
          
              def notify_trade(self, trade):
                  if not trade.isclosed:
                      return
                  pdb.set_trace()
                  self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %
                           (trade.pnl, trade.pnlcomm))
          
              def notify_order(self, order):
                  if order.status in [order.Submitted, order.Accepted]:
                      # Buy/Sell order submitted/accepted to/by broker - Nothing to do
                      return
          
                  # 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, Price: %.2f  Cost: %.2f, Comm %.2f' %
                                   (order.executed.price,
                                   order.executed.value,
                                   order.executed.comm))
                      elif order.issell():
                          self.log('SELL EXECUTED, Price: %.2f  Cost: %.2f, Comm %.2f' %
                                   (order.executed.price,
                                   order.executed.value,
                                   order.executed.comm))
          
                      self.bar_executed = len(self)
          
                  elif order.status in [order.Canceled, order.Margin, order.Rejected]:
                      self.log('Order Canceled/Margin/Rejected')
                      self.currentPositionSystem = TurtleSystem.NO_POSITION
          
                  # Write down: no pending order
                  self.order = None
          
          
          
          INSTRUMENT = 'BTC-USD'
          
          if __name__ == '__main__':
          
              cerebro = bt.Cerebro()
          
              data = bt.feeds.YahooFinanceData(dataname=INSTRUMENT,
                                               period='d',
                                               fromdate=datetime.datetime(2013, 1, 1),
                                               todate=datetime.datetime(2018, 9, 20),
                                               )
          
              cerebro.adddata(data)
              cerebro.addstrategy(FirstStrat)
          
              cerebro.broker.setcommission(commission=0.001)
              cerebro.addsizer(bt.sizers.PercentSizer, percents=2)
          
              startingValue = cerebro.broker.getvalue()
              print('Starting Portfolio Value: %.2f' % startingValue)
              cerebro.broker.set_cash(100000)
              cerebro.run()
          
              finalValue = cerebro.broker.getvalue()
              print('Final Portfolio Value: %.2f' % finalValue)
          
          
          1 Reply Last reply Reply Quote 0
          • B
            backtrader administrators last edited by backtrader

            A working sample doesn't mean your full code ... just a working sample, for example with a single indicator and no logic.

            @xenide said in next() beginning before minimum period:

                # Tried with just self.data
                # It uses CLOSE instead of high
                self.S1HEntry = bt.indicators.Highest(self.data.high,
            

            Of course. If you apply self.data it gives you the default which everybody uses, i.e.: the close price. Highest calculates the highest price of what you give to it and not the highest high, unless you pass the high, like in your case.

            @xenide said in next() beginning before minimum period:

            What am I not getting?

            Nothing, in a good sense, because you have uncovered an unexpected behavior. You are probably the first to not use self.data (or any of the data feeds in multiple data feeds scenarios), because you have chosen the individual lines. Which generates this behavior. To be checked.

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

              See Community - Release 1.9.67.122

              And for a test sample

              import argparse
              import backtrader as bt
              
              
              class St(bt.Strategy):
                  params = dict(usedata=False)
              
                  def __init__(self):
                      d = self.data if self.p.usedata else self.data.high
                      bt.indicators.Highest(d, period=20)
              
                  def nextstart(self):
                      print('NEXTSTART len(self):', len(self), 'ok:', len(self) == 20)
              
              
              def runstrat(args=None):
                  args = parse_args(args)
                  cerebro = bt.Cerebro()
              
                  cerebro.adddata(bt.feeds.BacktraderCSVData(
                      dataname='../../datas/2006-day-001.txt'))
                  cerebro.addstrategy(St, usedata=args.data)
                  cerebro.run(stdstats=False)
              
              
              def parse_args(pargs=None):
                  parser = argparse.ArgumentParser(
                      formatter_class=argparse.ArgumentDefaultsHelpFormatter,
                      description=('Sample Skeleton')
                  )
              
                  parser.add_argument('--data', action='store_true', help='Do not use high')
                  return parser.parse_args(pargs)
              
              
              if __name__ == '__main__':
                  runstrat()
              
              1 Reply Last reply Reply Quote 0
              • R
                RY93 last edited by

                Here data0 is on 1Min timeframe and data1 is on 1Day timeframe.
                When I am using this :
                '''
                self.movag0 = backTester.indicators.MovingAverageSimple(self.data0.close, period=5)
                self.movag1 = backTester.indicators.MovingAverageSimple(self.data1.close, period=5)
                '''
                Everything seems fine and it prints after min period (that is after 5 days)
                But when I am trying to use this:
                '''
                self.movag0 = backTester.indicators.MovingAverageSimple(self.data0.close, period=5)
                self.noise = backTester.Min(self.data1.high - self.data1.open, self.data1.open - self.data1.low)
                self.movag1 = backTester.indicators.MovingAverageSimple(self.noise, period=5)
                '''
                It starts printing before the minimum period of 5 (for 1Day timeframe) ,it takes the minimum period as 5 min using 1 Minute timeframe.

                R 1 Reply Last reply Reply Quote 0
                • R
                  RY93 @RY93 last edited by

                  @ry93 said in next() beginning before minimum period:

                  Here data0 is on 1Min timeframe and data1 is on 1Day timeframe.
                  When I am using this :

                  self.movag0 = backTester.indicators.MovingAverageSimple(self.data0.close, period=5)
                          self.movag1 = backTester.indicators.MovingAverageSimple(self.data1.close, period=5)
                  

                  Everything seems fine and it prints after min period (that is after 5 days)
                  But when I am trying to use this:

                  self.movag0 = backTester.indicators.MovingAverageSimple(self.data0.close, period=5)
                  self.noise = backTester.Min(self.data1.high - self.data1.open, self.data1.open - self.data1.low)
                          self.movag1 = backTester.indicators.MovingAverageSimple(self.noise, period=5)
                  

                  It starts printing before the minimum period of 5 (which has to be based on 1Day timeframe) but it takes the minimum period as 5 min using 1 Minute timeframe.
                  Why is that so ?

                  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(); }); }