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/

    storing the candle data which touched a bollinger band

    General Code/Help
    3
    10
    281
    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.
    • Jens Halsberghe
      Jens Halsberghe last edited by

      Hi,

      I'm trying to do the following:

      a) if a candle touches or breaks the level of the lower bollinger band, store its data
      b) if any candle after (unless the top of the bollinger band gets hit), breaks the candle from a)'s low, then replace this candle

      It seems the way that I am storing the candle's data is incorrect

      # Create a Stratey
      class TestStrategy(bt.Strategy):
      
      
          def log(self, txt, dt=None):
              ''' Logging function fot this strategy'''
              dt = dt or self.datas[0].datetime.datetime(0)
              print('%s, %s' % (dt.strftime("%Y-%m-%d %H:%M"), txt))
      
          def __init__(self):
              # Keep a reference to the "close" line in the data[0] dataseries
              self.dataclose = self.datas[0].close
      
              # Add Bollinger bands
              self.BB = bt.indicators.BollingerBands(self.datas[0])
            
          def next(self):
              
              # The candle touches the lower bollinger band
              if self.data.low[0] <= self.BB.lines.bot[0]:
                  self.BBlowtouch = self.data   
      
              # if there is a touch of the lower bollinger and the low is lower than the previous candle which touched the lower bollinger, it resets
                  if self.data.low[0] < self.BBlowtouch.low[0] and self.data.low[0] <= self.BB.lines.bot[0]:
                      self.BBlowtouch = self.data
                      self.log('BB Low broken touched')                    
                      
      if __name__ == '__main__':
          cerebro = bt.Cerebro()
          
          # Add a strategy
          cerebro.addstrategy(TestStrategy)
          
          cerebro.addsizer(bt.sizers.FixedSize, stake=1000)
              
          # Create a Data Feed
          minute_data = bt.feeds.PandasData(dataname=df2020)
      
          # Add the Data Feed to Cerebro
          cerebro.adddata(minute_data)
      
          print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
          cerebro.run()
           print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
      

      I thought I might have to add self.BBlowtouch to the init function but then I'm not sure what to instantiate it with.
      It just seem that when I do self.BBlowtouch = self.data I'm not actually storing self.data's values at the time of that bar but it will update the values for each bar.

      1 Reply Last reply Reply Quote 0
      • run-out
        run-out last edited by

        There's a bit of confusion between lines and static values. When setting equal to self.data you need to set it at the current bar.

        self.BBlowtouch = self.data[0]
        

        And later when using self.BBlowtouch to compare, don't use .low[0] since this is a single variable.

        if self.data.low[0] < self.BBlowtouch  ...etc
        

        RunBacktest.com

        1 Reply Last reply Reply Quote 1
        • Jens Halsberghe
          Jens Halsberghe last edited by

          thanks so much again run-out. this is what I thought what was happening. I will try this out later today!

          1 Reply Last reply Reply Quote 0
          • Jens Halsberghe
            Jens Halsberghe last edited by

            One other thing I need to know is how to declare self.BBlowtouch with empty data. I can only have this information once I have had the first bar which has touched the lower bollinger band. It's causing me later issues when I'm running conditionals as

                def __init__(self):
                    # Keep a reference to the "close" line in the data[0] dataseries
                    self.dataclose = self.datas[0].close
            
                    # Add Bollinger bands
                    self.BB = bt.indicators.BollingerBands(self.datas[0])
                    
                    self.BBlowtouchbool = False
                  
                def next(self): 
                    
                    # Mark if the candle touched or broke the bottom bollinger band
                    # Record that candle's information
                    if self.data.low[0] <= self.BB.lines.bot[0]:
                        self.BBlowtouch = self.data[0] 
                        self.BBlowtouchbool = True
                        self.log('BB low touched')
            
                    if self.data.low[0] < self.BBlowtouch.low[0]: # this will give me an error as self.BBlowtouch wasn't created yet
                        self.BBlowtouch = self.data[0]
                        self.log('BB low broken')
                        self.log(BBlowtouch.low[0])
            
            # Error:
            AttributeError: 'Lines_LineSeries_LineIterator_DataAccessor_Strateg' object has no attribute 'BBlowtouch'
            
            1 Reply Last reply Reply Quote 0
            • run-out
              run-out last edited by

              You can set up a dummy line. Read here.

              RunBacktest.com

              1 Reply Last reply Reply Quote 1
              • Jens Halsberghe
                Jens Halsberghe last edited by

                I'm still stuck with this.

                I have added a line and then added 0 for the OHLCV data.

                # Create a Stratey
                class TestStrategy(bt.Strategy):
                
                    lines = ('LowestBB',)
                    params = (('Open', 0),('High',0),('Low',0),('Close',0),('Volume',0))
                
                    def log(self, txt, dt=None):
                        ''' Logging function for this strategy'''
                        dt = dt or self.datas[0].datetime.datetime(0)
                        print('%s, %s' % (dt.strftime("%Y-%m-%d %H:%M"), txt))
                
                    def __init__(self):
                        # Keep a reference to the "close" line in the data[0] dataseries
                        self.dataclose = self.datas[0].close
                        
                        # Addy dummy to initialize the bblowtouchdata
                        
                #         self.lines.BBlowtouch = self.params.OHLCV
                
                        # Add Bollinger bands
                        self.BB = bt.indicators.BollingerBands(self.datas[0])
                        
                        self.LowestBB.Open = 0 
                        self.LowestBB.High = 0
                        self.LowestBB.Low = 0
                        self.LowestBB.Close = 0 
                        self.LowestBB.Volume = 0
                      
                    def next(self): 
                        
                        
                #         # Mark if the candle touched or broke the bottom bollinger band
                #         # Record that candle's information
                        if self.data.low[0] <= self.BB.lines.bot[0] and self.LowestBB.Low < self.data.low[0]:
                            self.BBlowtouch = self.data[0] 
                            self.LowestBB = self.data.Low[0]
                            
                                
                if __name__ == '__main__':
                    cerebro = bt.Cerebro()
                    
                    # Add a strategy
                    cerebro.addstrategy(TestStrategy)
                    
                    cerebro.addsizer(bt.sizers.FixedSize, stake=1000)
                        
                    # Create a Data Feed
                    minute_data = bt.feeds.PandasData(dataname=df2020)
                
                    # Add the Data Feed to Cerebro
                    cerebro.adddata(minute_data)
                
                    print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
                    cerebro.run()
                    print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
                
                
                TypeError: 'int' object is not subscriptable
                

                I'm getting an error. It makes sense to me as I have just assigned zeros to the different attributes. I'm sure I have to assign a data structure to BBlowtouch similar to "datas" which I think is a list. I'm just not sure how to proceed

                1 Reply Last reply Reply Quote 0
                • run-out
                  run-out last edited by

                  I'm still not sure I follow what you are doing but it seems to me that you are trying to store one bar of data, and then change that stored bar over time. If this is the case, then it's pretty simple.

                  Just set up the variables individually in init.

                  def __init__(self):
                      self.open = 0
                      self.high = 0
                      self.low = 0
                      self.close = 0
                      self.volume = 0
                  

                  If you like, you can set their values at the first bar.

                  def next(self):
                      if len(self) == 0:
                          self.open = self.datas[0].open[0]
                          self.high = self.datas[0].high[0]
                          self.low = self.datas[0].low[0]
                          self.close = self.datas[0].close[0]
                          self.volume = self.datas[0].volume[0]
                      else:
                          pass
                  

                  Then your condition:

                      # The candle touches the lower bollinger band
                      if self.datas[0].low[0] <= self.BB.lines.bot[0]:
                          self.open = self.datas[0].open[0]
                          self.high = self.datas[0].high[0]
                          self.low = self.datas[0].low[0]
                          self.close = self.datas[0].close[0]
                          self.volume = self.datas[0].volume[0]
                  

                  You might want to set this up in a funtion:

                  
                  def track_ohlcv(self, data):
                      """  Resets the candle tracking bar.   """
                      self.open = self.datas[0].open[0]    
                      self.high = self.datas[0].high[0]
                      self.low = self.datas[0].low[0]    
                      self.close = self.datas[0].close[0]
                      self.volume = self.datas[0].volume[0]
                  
                      return None
                  

                  RunBacktest.com

                  Jens Halsberghe 1 Reply Last reply Reply Quote 1
                  • Jens Halsberghe
                    Jens Halsberghe @run-out last edited by

                    @run-out

                    thanks again, you've been very helpful. yes, that was what I was trying to do, to store the bar data. I've been able to apply all of this to my code and it works.

                    Just wondering if there is not a more optimal way to assign the current bar's data to the - let's call it the track_ohlcv bar- instead of doing self.open =, self.high= etc

                    would there be no way to do something like
                    self.ohlcv.data = self.data (not adding the zero as I want the static data)

                    1 Reply Last reply Reply Quote 0
                    • Jens Halsberghe
                      Jens Halsberghe last edited by

                      there doesn't seem to be a way to edit my post.

                      Just want to state that at the moment it seems an issue to me when I want to create an empty ohlcv bar at the start (where all values are 0)
                      and after, I want to do self.ohlcv.data = self.data, that it doesn't work that way. I might have missed something. It's more about writing cleaner code than utility as I can make it work the way I have it now.

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

                        You may take a look at the _Bar class as an example (it is an internal class in Backtrader) and create something similar for your needs.

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