For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/

bar number is greater than length



  • how we can check bar number is greater than length in init
    actually i want to perform this piece of code but i am facing issue "object has no attribute 'bar_executed"

    if (self.bar_executed) > len(self):
             self.haop1  = (self.open(-1) + self.close(-1)) / 2.0
        else:
             self.haop1 = (self.hacl1(-1) + self.haop1(-1)) / 2.0
    


  • You haven't defined self.bar_executed. If it's a parameter then self.p.bar_executed. If defined in init then make sure there's a self in front.



  • @run-out
    i am executing if bar len is less then 2 so execute if part otherwise execute else part but script all run if part never goes in else part what's wrong i am doing

    self.haop1  = (self.open(-1) + self.close(-1)) / 2.0
    if(len(self)<=2):
            self.haop1 = self.haop1
        else:
            self.haop1 = (self.hacl1(-1) + self.haop1(-1)) / 2.0
    


  • @mudassar031 said in bar number is greater than length:

    len(self)

    I assume that len(self) in init() is zero. Length is increasing on each next() call.



  • @ab_trader
    yes in next function i can get len value is there any way to do in init()



  • @ab_trader
    as placed question many time no reply
    i want to calculate compound value

    https://stackoverflow.com/questions/59003693/understanding-converting-thinkscripts-compoundvalue-function

    i need to convert this in backtrader and want to calculate ha_open like this



  • @mudassar031
    here is my full code can you please let me know which part i need to execute in init and which in next function
    i spent lot of time on it please help

    import backtrader as bt
    class TOS(bt.Strategy):
    
      lines = ('super_trend',)
      params = (('ST_Period', 15),('ST_Coeff', 3),)
      plotlines = dict(super_trend=dict(_name='ST',color='blue',alpha=1))
      def log(self, txt, dt=None):
        ''' Logging function for this strategy'''
        dt = dt or self.datas[0].datetime.datetime(0)
        print('%s, %s' % (dt.isoformat(), txt))
    
      def __init__(self):
        self.open = self.data.open
        self.close = self.data.close
        self.high = self.data.high
        self.low = self.data.low
        self.finalUp1 = [0]
        self.finalDn1 = [0]
        self.st = [0]
        #calculate HAcl1
        self.hacl1 = (self.open+self.high+self.low+self.close)/4
        # calculate compoundvalue
        self.haop1  = (self.open(-1) + self.close(-1)) / 2.0
        if(len(self)<=2):
            self.haop1 = self.haop1
        else:
            self.haop1 = (self.hacl1(-1) + self.haop1(-1)) / 2.0
        #max value
        self.hahi1 = bt.Max(self.open, bt.Max(self.hacl1,self.haop1))
        #min value
        self.halo1 = bt.Min(self.low, bt.Min(self.hacl1,self.haop1))
        #avg of self.hahi1 and self.halo1
        self.hahl2_1 = (self.hahi1 + self.halo1) / 2
    
        self.trueRange = bt.Max(self.hahi1, self.hacl1, self.halo1)
    
        # True range is equal to the greatest of these values
        self.newTrueRange = bt.Max(
            abs(self.hahi1 - self.halo1),
            abs(self.hahi1 - self.hacl1),
            abs(self.halo1 - self.hacl1)
        )
    
        # End manual TrueRange
        self.atr = ((self.newTrueRange)/self.params.ST_Period)
        self.iATR1 = (self.atr-1)*((self.params.ST_Period-1)/self.params.ST_Period)
    
        self.tmpUp1 = self.hahl2_1 - (self.params.ST_Coeff * self.iATR1);  # hahl2 is better than hl2
    
        self.tmpDn1 = self.hahl2_1 + (self.params.ST_Coeff * self.iATR1);  # hahl2 is better than hl2
    
        #self.hma = bt.indicators.SmoothedMovingAverage(self.high, period=self.params.ST_Period)
    
      def next(self):
        self.log(f"Number of bars {len(self)}")
        pre_upband = self.finalUp1[0]
        pre_lowband = self.finalDn1[0]
        if self.close[-1] > self.finalUp1[-1]:
            self.finalUp1[0] = max(self.tmpUp1[0], self.finalUp1[-1])
        else:
            self.finalUp1[0] = self.tmpUp1[0]
    
        if self.close[-1] < self.finalDn1[-1]:
            self.finalDn1[0] = min(self.tmpDn1[0], self.finalDn1[-1])
        else:
            self.finalDn1[0] = self.tmpDn1[0]
    
    
        #self.lines.super_trend[0] = self.finalUp1[0]
        # Simply log the closing price of the series from the reference
        self.log('Open: %.2f '
                 'Close: %.2f '
                 'High: %.2f '
                 'Low: %.2f '
                 'Hacl1: %.2f '
                 'haop1: %.2f '
                 'hahi1: %.2f '
                 'halo1: %.2f '
                 'hahl2_1: %.2f '
                 'tr: %.2f '
                 'newtr: %.2f '
                 'iATR1: %.2f '
                 'tmpUp1: %.2f '
                 'tmpDn1: %.2f '
                 'finalUp1: %.2f '
                 'finalDn1: %.2f '
                 % (self.open[0],
                    self.close[0],
                    self.high[0],
                    self.low[0],
                    self.hacl1[0],
                    self.haop1[0],
                    self.hahi1[0],
                    self.halo1[0],
                    self.hahl2_1[0],
                    self.trueRange[0],
                    self.newTrueRange[0],
                    self.iATR1[0],
                    self.tmpUp1[0],
                    self.tmpDn1[0],
                    self.finalUp1[0],
                    self.finalDn1[0]
                   )
                 )
    


  • This is an indicator which returns CompoundValue based on the description from your post:

    class CompoundValue(bt.Indicator):
        '''
        Calculates a compound value according to following rule:
        if a bar number is greater than `length` then the `data1` value is returned,
        otherwise the `data2` value is returned (Thinkorswim).
        '''
    
        lines = ('value',)
    
        params = (('length', 1), ('data1', None), ('data2', None),)
        
        def __init__(self):
            pass
    
        def next(self):
            if len(self) <= self.p.length:
                self.lines.value[0] = self.p.data2[0]
            else:
                self.lines.value[0] = self.p.data1[0]
    


  • This is general approach. Parameters data1 and data2 can be removed and the indicator can be simplified, if it is known that data1 and data2 are the data feeds.



  • Unfortunately, I understood the idea wrong, that script is incorrect.



  • There is Heikin Ashi indicator in the bt which returns HA open, close, high and low values. Why don't you use it?



  • @ab_trader
    i have to interpret this HeikinAshi + SuperTrend Strategy in Backtrader
    https://github.com/sureshja/ThinkOrSwim/blob/master/HeikinAshiSuperTrendStrategy.ts



  • @ab_trader
    Parameters data1 and data2 can be removed and the indicator can be simplified can you please can any example





  • The part that is concerning you is the ComoundValue part of the equation. In the link you provide to stackoverflow "Understanding & Converting ThinkScripts CompoundValue Function" the post illustrates how CompoundValue works. It's purpose is to provide initial parameters for a recursive formula. They use a fibonocci formula as an example. Heikin ashi also requires such initial parameters.

    From the code you are trying to copy, here is the CompoundValue code:

    def haop1 = CompoundValue(1, (haop1[1] + hacl1[1]) / 2, (open(period = aggrPd1)[1] + close(period = aggrPd1)[1]) / 2);
    

    You can see here that if the bar is 1 then the formula uses the open and close values at 1, but if not then it uses the previous values, since the seed values are now set.

    It has been mentioned to you several times in this question and another that backtrader has a heikin ashi indicator. I'm wondering if you have investigated it to see if the values match your tradingview indicator? If you look a the formual for the backtrader heikin ashi you will find the main body the following:

    def __init__(self):
            o = self.data.open
            h = self.data.high
            l = self.data.low
            c = self.data.close
    
            self.l.ha_close = ha_close = (o + h + l + c) / 4.0
            self.l.ha_open = ha_open = (self.l.ha_open(-1) + ha_close(-1)) / 2.0
            self.l.ha_high = bt.Max(h, ha_open, ha_close)
            self.l.ha_low = bt.Min(l, ha_open, ha_close)
    
            super(HeikinAshi, self).__init__()
    

    This is the seeded part of the formula. But if you look way down to the bottom, you'll also find this:

      def prenext(self):
            # seed recursive value
            self.lines.ha_open[0] = (self.data.open[0] + self.data.close[0]) / 2.0
    

    Which is backtrader's alread built in 'CompoundValue' part of the formula. The two formulas are the same and should work.



  • @mudassar031 said in bar number is greater than length:

    i have to interpret this HeikinAshi + SuperTrend Strategy in Backtrader
    https://github.com/sureshja/ThinkOrSwim/blob/master/HeikinAshiSuperTrendStrategy.ts

    I understand that. The code by the link has two parts: HA candles calculations and SuperTrend calculations. HA candles is already in the bt and can be used as an indicator or as a data feed. In other words this part of the TS code is in bt already:

    # Heikin Ashi Stuff
    # Working off of HA open, high, low, close 
    def hacl1 = ( open(period = aggrPd1) + high(period = aggrPd1) + low(period = aggrPd1) + close(period = aggrPd1) ) / 4;
    def haop1 = CompoundValue(1, (haop1[1] + hacl1[1]) / 2, (open(period = aggrPd1)[1] + close(period = aggrPd1)[1]) / 2);
    def hahi1 = Max( open(period = aggrPd1), Max( hacl1, haop1 ) );
    def halo1 = Min( low(period = aggrPd1), Min( hacl1, haop1 ) );
    

    Then you apply SuperTrend calculations to HA candles and it is done.

    CompoundValue formula is not required, since bt HA candles are calculated without it.



  • @run-out
    i have tried backtrader heikin ashi main body instead of our custom code

    self.l.ha_open = ha_open = (self.l.ha_open(-1) + ha_close(-1)) / 2.0
    

    this line of code always return "nan"
    Screen Shot 2020-07-17 at 2.46.52 AM.png



  • @mudassar031
    resolve it by using prenext function to seed recursive value


Log in to reply
 

});