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?



  • 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!



  • 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']
    

Log in to reply
 

});