Backtrader Community

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

    Fundamental concept I am missing with indicator development: (Adaptive LRSI Filter)

    Indicators/Strategies/Analyzers
    2
    3
    1519
    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.
    • RandyT
      RandyT last edited by

      I've spent a good part of the day trying to get this working and seem to continue to miss some fundamental concepts about indicator development. When something needs to be in __init__() vs next() or something.

      I have the following bit of code that does not quite accomplish the goal. Help would be very much appreciated.

      class AdaptiveLaguerreFilter(btind.PeriodN):
          '''
          // Adaptive Laguerre Filter, from John Ehlers
          // Link : http://www.mesasoftware.com/Papers/Time%20Warp%20Without%20Space%20Travel.exe
          // Another work from Ehlers : http://www.mesasoftware.com/technicalpapers.htm
          //
          // Description :
          // Laguerre Filtering, (alpha is automaticaly adapted depending the error of filtering)
          function ALFilter(price, length, medianlong) {
              result=price;
              L0 = price;
              L1 = price;
              L2 = price;
              L3 = price;
              coef=0.5;
              Diff=0;
              HH=0.1;
              LL=0;
              alpha=0.5;
      
              for(i = 1+length; i < BarCount; i++) {
                  Diff[i] = abs(price[i] - result[i-1]);
                  HH[i] = Diff[i];
                  LL[i] = Diff[i];
      
                  for(j = 0; j < (length-1); j++) {
                      if (Diff[i-j] > HH[i]) HH[i] = Diff[i-j];
                      if (Diff[i-j] < LL[i]) LL[i] = Diff[i-j];
                  }
      
                  if ( (i > length) AND (HH[i] - LL[i] != 0) ) {
                      coeftemp=(Diff - LL) / (HH - LL);
                      mlen = medianlong;
                      for(k = mlen - 1; k >= 0; k--) temparray[k] = coeftemp[i + k - (mlen - 1)];
                      temp=0;
                      for(k = mlen - 1; k > 0; k--) {
                          for (j = mlen - 1; j > 0; j--) {
                              if (temparray[j-1] > temparray[j]) {
                                  temp = temparray[j-1];
                                  temparray[j-1] = temparray[j];
                                  temparray[j] = temp;
                              }
                          }
                      }
                      coef[i] = temparray[(mlen/2)-0.5];
                      //----- End median calculation
                  } // end main IF
      
                  alpha=coef[i];
                  L0[i] = alpha*price[i] + (1 - alpha)*L0[i-1];
                  L1[i] = -(1 - alpha)*L0[i] + L0[i-1] + (1 - alpha)*L1[i-1];
                  L2[i] = -(1 - alpha)*L1[i] + L1[i-1] + (1 - alpha)*L2[i-1];
                  L3[i] = -(1 - alpha)*L2[i] + L2[i-1] + (1 - alpha)*L3[i-1];
                  result[i] = (L0[i] + 2*L1[i] + 2*L2[i] + L3[i]) / 6;
              }// end main  FOR
              return result;
          }
          '''
          alias = ('ALF', 'ALRSI', 'AdaptiveLRSI')
          lines = ('alf',)
          params = (('period', 20),
                    ('medianperiod', 5),)
          plotinfo = dict(subplot=False)
      
          def __init__(self):
              self.l0, self.l1, self.l2, self.l3 = 0.0, 0.0, 0.0, 0.0
              self.diff = abs(self.data - self.l.alf(-1))
              super(AdaptiveLaguerreFilter, self).__init__()
      
          def next(self):
              l0_1 = self.l0  # cache previous intermediate values
              l1_1 = self.l1
              l2_1 = self.l2
              alpha = 0.5
              llv, hhv = 0.0, 0.0
      
              llv = btind.Lowest(self.diff, period=self.p.period)
              hhv = btind.Highest(self.diff, period=self.p.period)
              alpha = btind.Mean((self.diff[0] - llv) / (hhv - llv),
                                 period=self.p.medianperiod)
      
              self.l0 = l0 = (alpha * self.data[0]) + ((1.0 - alpha) * l0_1)
              self.l1 = l1 = (-(1 - alpha) * l0) + l0_1 + (1 - alpha) * l1_1
              self.l2 = l2 = (-(1 - alpha) * l1) + l1_1 + (1 - alpha) * l2_1
              self.l3 = l3 = (-(1 - alpha) * l2) + l2_1 + (1 - alpha) * self.l3
              self.l.alf[0] = (l0 + (2 * l1) + (2 * l2) + l3) / 6
      
      1 Reply Last reply Reply Quote 0
      • RandyT
        RandyT last edited by

        Here is a hack to get this working, but I must be missing something. Looking at some of the other adaptive indicators, it seems it should be easier.

            alias = ('ALF', 'ALRSI', 'AdaptiveLRSI')
            lines = ('alf',)
            params = (('period', 20),
                      ('medianperiod', 5),)
            plotinfo = dict(subplot=False)
        
            def __init__(self):
                self.l0, self.l1, self.l2, self.l3 = 0.0, 0.0, 0.0, 0.0
                self.diff = abs(self.data - self.l.alf(-1))
                self.llv = btind.Lowest(self.diff, period=self.p.period)
                self.hhv = btind.Highest(self.diff, period=self.p.period)
                self.alpha = btind.Mean((self.diff - self.llv) / (self.hhv - self.llv),
                                        period=self.p.medianperiod)
                super(AdaptiveLaguerreFilter, self).__init__()
        
            def next(self):
                l0_1 = self.l0  # cache previous intermediate values
                l1_1 = self.l1
                l2_1 = self.l2
        
                alpha = self.alpha.av[0] if not math.isnan(self.alpha.av[0]) else 0.5
        
                self.l0 = l0 = (alpha * self.data) + ((1.0 - alpha) * l0_1)
                self.l1 = l1 = (-(1 - alpha) * l0) + l0_1 + (1 - alpha) * l1_1
                self.l2 = l2 = (-(1 - alpha) * l1) + l1_1 + (1 - alpha) * l2_1
                self.l3 = l3 = (-(1 - alpha) * l2) + l2_1 + (1 - alpha) * self.l3
                self.l.alf[0] = (l0 + (2 * l1) + (2 * l2) + l3) / 6
        
        
        1 Reply Last reply Reply Quote 0
        • B
          backtrader administrators last edited by backtrader

          • In __init__

            Operations like self.x = (self.data.high + self.data.low) / 2.0 generate a lazily evaluated lines object.

            Even this generates that: self.y = self.data.close > self.data.open

          • In next

            Here the [] operator is used to access the values provided by lines objects like the generated self.x or self.y or standard lines like self.data.high

            if self.data.close[0] > self.data.open[0]:
                do_something()
            

            Thanks to operator overloading the following is equivalent also in next

            if self.data.close > self.data.open:
                do_something()
            

            But unlike in __init__, this comparison generates a bool.

          One can generate a complete indicator just by using operations and logic in __init__. See for example an old friend of everybody like MACD (removing documentation and plotting preparation boilerplate)

          class MACD(bt.Indicator):
              lines = ('macd', 'signal',)
              params = (
                  ('period_me1', 12),
                  ('period_me2', 26), ('period_signal', 9),
                  ('movav', MovAv.Exponential),
              )
          
              def __init__(self):
                  super(MACD, self).__init__()
                  me1 = self.p.movav(self.data, period=self.p.period_me1)
                  me2 = self.p.movav(self.data, period=self.p.period_me2)
                  self.lines.macd = me1 - me2
                  self.lines.signal = self.p.movav(self.lines.macd, period=self.p.period_signal)
          

          No need to use scalar operations/logic in next. Everything is defined in terms of lines objects.

          Some indicators may need next. Some help from things defined in __init__ can be used. For example the ZeroLagIndicator

          class ZeroLagIndicator(MovingAverageBase):
              alias = ('ZLIndicator', 'ZLInd', 'EC', 'ErrorCorrecting',)
              lines = ('ec',)
              params = (
                  ('gainlimit', 50),
                  ('_movav', MovAv.EMA),
              )
          
              def __init__(self):
                  self.ema = MovAv.EMA(period=self.p.period)
                  self.limits = [-self.p.gainlimit, self.p.gainlimit + 1]
          
                  # To make mixins work - super at the end for cooperative inheritance
                  super(ZeroLagIndicator, self).__init__()
          
              def next(self):
                  leasterror = MAXINT  # 1000000 in original code
                  bestec = ema = self.ema[0]  # seed value 1st time for ec
                  price = self.data[0]
                  ec1 = self.lines.ec[-1]
                  alpha, alpha1 = self.ema.alpha, self.ema.alpha1
          
                  for value1 in range(*self.limits):
                      gain = value1 / 10
                      ec = alpha * (ema + gain * (price - ec1)) + alpha1 * ec1
                      error = abs(price - ec)
                      if error < leasterror:
                          leasterror = error
                          bestec = ec
          
                  self.lines.ec[0] = bestec
          

          Here the base ema for the calculations is defined in __init__ but the core of the operations which is a loop over several values is best done in next.

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