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/

    Renko bars calculated with ATR?

    General Code/Help
    1
    2
    67
    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.
    • B
      booboothefool last edited by

      On TradingView, the Renko bars comes with 2 settings for the brick size, ATR or Traditional. This https://www.backtrader.com/blog/posts/2017-06-26-renko-bricks/renko-bricks/ works well for Traditional where you can just set the size, but I am having trouble getting the ATR calculation into the Filter. I'm not sure how to get an Indicator for use in a Filter and have it update those values on the fly, and also wait enough periods for them to be calculated. I attempted to convert it to a Pandas dataframe and go from there, but it's just a mess and doesn't work properly as it creates gaps between all the bars, haha.

      def bt_to_pd(btdata, len):
          get = lambda mydata: mydata.get(ago=0, size=len)
          fields = {
              'open': get(btdata.open),
              'high': get(btdata.high),
              'low': get(btdata.low),
              'close': get(btdata.close),
              'volume': get(btdata.volume)
          }
          time = [btdata.num2date(x) for x in get(btdata.datetime)]
          return pd.DataFrame(data=fields, index=time)
      
      class Renko(bt.Filter):
          '''Modify the data stream to draw Renko bars (or bricks)
          Params:
            - ``hilo`` (default: *False*) Use high and low instead of close to decide
              if a new brick is needed
            - ``size`` (default: *None*) The size to consider for each brick
            - ``autosize`` (default: *20.0*) If *size* is *None*, this will be used
              to autocalculate the size of the bricks (simply dividing the current
              price by the given value)
            - ``dynamic`` (default: *False*) If *True* and using *autosize*, the size
              of the bricks will be recalculated when moving to a new brick. This
              will of course eliminate the perfect alignment of Renko bricks.
            - ``align`` (default: *1.0*) Factor use to align the price boundaries of
              the bricks. If the price is for example *3563.25* and *align* is
              *10.0*, the resulting aligned price will be *3560*. The calculation:
                - 3563.25 / 10.0 = 356.325
                - round it and remove the decimals -> 356
                - 356 * 10.0 -> 3560
          See:
            - http://stockcharts.com/school/doku.php?id=chart_school:chart_analysis:renko
          '''
      
          params = (
              ('hilo', False),
              ('size', None),
              ('autosize', 20.0),
              ('dynamic', False),
              ('align', 1.0),
              ('atr', 0)
          )
      
          def nextstart(self, data):      
              if not self.p.atr:
                  o = data.open[0]
                  self.o = round(o / self.p.align, 0) * self.p.align  # aligned
                  self._size = self.p.size or float(o // self.p.autosize)
                  self._top = int(o) + self._size
                  self._bot = int(o) - self._size
              else:
                  self._size = self.p.size
              
          def next(self, data):
              if not self._size and self.p.atr:
                  self.df = bt_to_pd(data, len(data))
                  self.df['ATR'] = ATR(self.df, n=self.p.atr)
                  ATR_val = self.df['ATR'][-1]
                  if not np.isnan(ATR_val):
                      self._size = self.init_ATR = ATR_val
                      print('init_ATR', self._size)
                      
              if not self._size:
                  return False
              
              if self.p.atr:
                  o = data.open[0]
                  self.o = round(o / self.p.align, 0) * self.p.align  # aligned
                  self._top = int(self.o) + self._size
                  self._bot = int(self.o) - self._size
              
              c = data.close[0]
              h = data.high[0]
              l = data.low[0]
      
              if self.p.hilo:
                  hiprice = h
                  loprice = l
              else:
                  hiprice = loprice = c
      
              if hiprice >= self._top:
                  # deliver a renko brick from top -> top + size
                  self._bot = bot = self._top
      
                  if self.p.size is None and self.p.dynamic:
                      self._size = float(c // self.p.autosize)
                      top = bot + self._size
                      top = round(top / self.p.align, 0) * self.p.align  # aligned
                  else:
                      top = bot + self._size
      
                  self._top = top
      
                  data.open[0] = bot
                  data.low[0] = bot
                  data.high[0] = top
                  data.close[0] = top
                  data.volume[0] = 0.0
                  data.openinterest[0] = 0.0
                  return False  # length of data stream is unaltered
      
              elif loprice <= self._bot:
                  # deliver a renko brick from bot -> bot - size
                  self._top = top = self._bot
      
                  if self.p.size is None and self.p.dynamic:
                      self._size = float(c // self.p.autosize)
                      bot = top - self._size
                      bot = round(bot / self.p.align, 0) * self.p.align  # aligned
                  else:
                      bot = top - self._size
      
                  self._bot = bot
      
                  data.open[0] = top
                  data.low[0] = top
                  data.high[0] = bot
                  data.close[0] = bot
                  data.volume[0] = 0.0
                  data.openinterest[0] = 0.0
                  return False  # length of data stream is unaltered
      
              data.backwards()
              return True  # length of stream was changed, get new bar
      

      I hope there is an easier way and any help is appreciated! Thanks!

      B 1 Reply Last reply Reply Quote 0
      • B
        booboothefool @booboothefool last edited by

        Used this ATR function btw because it didn't seem like bt.ind.ATR() would take the data in next(self, data).

        def ATR(DF, n=14):
            df = DF.copy()
            df['H-L'] = abs(df['high'] - df['low'])
            df['H-PC'] = abs(df['high'] - df['close'].shift(1))
            df['L-PC'] = abs(df['low'] - df['close'].shift(1))
            df['TR'] = df[['H-L', 'H-PC', 'L-PC']].max(axis=1, skipna=False)    
            df['ATR'] = df['TR'].ewm(com=n,min_periods=n).mean()  
            return df['ATR']
        
        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(); }); }