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/

    Question regarding Smoothed Moving Average

    Indicators/Strategies/Analyzers
    2
    6
    960
    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.
    • A
      Alain last edited by Alain

      Hi,

      I tried to implement a relative volatility indicator as follows:

      class RelativeVolatility(bt.Indicator):
          lines = ('rel_vol',)
          params = (('period', 10),)
      
          def __init__(self):
              std_dev = bt.ind.StdDev(self.data.close, period=self.p.period)
              self.u = bt.If(self.data.close > self.data.close(-1), std_dev, 0)
              self.d = bt.If(self.data.close < self.data.close(-1), std_dev, 0)
              self.nU = btind.SMA(self.u, period=14)
              self.nD = btind.SMA(self.d, period=14)
              self.l.rel_vol = 100. * self.nU / (self.nU + self.nD)
      

      The code works perfectly. Actually however i want to replace the simple moving average by a smoothed moving average. But as soon as i change btind.SMA to btind.SmoothedMovingAverage i get lists full or 'nan' values.

      Would be great if anyone here knows why that is ?

      Thanks!

      A 1 Reply Last reply Reply Quote 0
      • A
        Alain @Alain last edited by

        @alain alright, i was able to implement the smoothing moving average inside the next function. it's just a bit less elegant.

        1 Reply Last reply Reply Quote 0
        • B
          backtrader administrators last edited by

          First and foremost ...

          See the top of the forum

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

          This really helps

          @alain said in Question regarding Smoothed Moving Average:

          But as soon as i change btind.SMA to btind.SmoothedMovingAverage i get lists full or 'nan' values.

          You don't show how you change it, you don't show how you use the indicator. Believe me: a simple replacement of SMA for SMMA WORKS.

          In any case, you may want to share your changes to get further help and to let others understand how you solved your problem.

          A 1 Reply Last reply Reply Quote 0
          • A
            Alain @backtrader last edited by

            how i solved the problem (just used next method to calculate the SMMA explicitly in each step):

            class RelativeVolatility(bt.Indicator):
                lines = ('rel_vol', 'signal', 'nU', 'nD',)
                plotlines = dict(nU=dict(_plotskip=True), nD=dict(_plotskip=True))
                params = (('period', 10), ('signal_line_top', 80), ('signal_line_bottom', 20),)
            
                def _plotinit(self):
                    self.plotinfo.plothylines = [self.p.signal_line_top, self.p.signal_line_bottom]
            
                def __init__(self):
                    std_dev = bt.ind.StdDev(self.data.close, period=self.p.period)
                    self.u = bt.If(self.data.close > self.data.close(-1), std_dev, 0)
                    self.d = bt.If(self.data.close < self.data.close(-1), std_dev, 0)
            
                def nextstart(self):
                    self.l.nU[0] = 0
                    self.l.nD[0] = 0
            
                def next(self):
            
                    self.l.nU[0] = (13. * self.l.nU[-1] + self.u[0]) / 14.
                    self.l.nD[0] = (13. * self.l.nD[-1] + self.d[0]) / 14.
            
                    self.l.rel_vol[0] = 100. * self.l.nU[0] / (self.l.nU[0] + self.l.nD[0])
            

            I tried again to directly switch SMA to SMMA.. but it really doesn't work for me:

                def __init__(self):
                    std_dev = bt.ind.StdDev(self.data.close, period=self.p.period)
                    u = bt.If(self.data.close > self.data.close(-1), std_dev, 0)
                    d = bt.If(self.data.close < self.data.close(-1), std_dev, 0)
                    nU = btind.SMMA(u, period=14)
                    nD = btind.SMMA(d, period=14)
                    self.l.rel_vol = 100. * nU / (nU + nD)
            

            gives me lists full of nan's in nU and nD...

            1 Reply Last reply Reply Quote 0
            • B
              backtrader administrators last edited by backtrader

              Well ... after looking at this ... the actual problem is when putting stddev inside bt.If as one of the potential results. When such a behavior was introduced ... ooops, it will have to be traced. But you can still have your indicator developed in an "elegant" manner by creating a null delay version of the result (stddev) to be the one of the results of bt.If.

              There is trivial fix in the base code, but I will still try to understand the why and it can be generically fixed.

              The code (pass SMMA or EMA as parameter if you wish, which were the ones hitting the issue)

              class RelativeVolatility(bt.Indicator):
                  alias = ('RV',)
                  lines = ('rv', 'nU', 'nD',)
                  params = dict(
                      p1=10,
                      p2=14,
                      movav=bt.ind.EMA,
                  )
              
                  def __init__(self):
                      stddev = bt.ind.StdDev(self.data, period=self.p.p1)
                      u = bt.If(self.data > self.data(-1), stddev(0), 0.0)
                      d = bt.If(self.data < self.data(-1), stddev(0), 0.0)
              
                      self.l.nU = nU = self.p.movav(u, period=self.p.p2)
                      self.l.nD = nD = self.p.movav(d, period=self.p.p2)
              
                      self.l.rv = 100.0 * nU / (nU + nD)
              

              A chart ...

              0_1556311394632_fbc77a5a-d28c-4ace-bc10-d6d0afe0fe00-image.png

              1 Reply Last reply Reply Quote 2
              • B
                backtrader administrators last edited by

                See: Community - Release 1.9.72.122

                The trivial fix would have helped, but it wasn't the right one. The real fix was somewhere else, being also mostly trivial.

                The SMMA and EMA indicators rely on the previous value to calculate the new one. As soon as one value is NaN, the result will always be the same and NaN. Non-recursive indicators, mostly every other, will recover after a number of calcualtions which is what made it possible for the error to remain undetected for a long while.

                The code will work now without having to create null delay object as in

                class RelativeVolatility(bt.Indicator):
                    alias = ('RV',)
                    lines = ('rv', 'nU', 'nD',)
                    params = dict(
                        p1=10,
                        p2=14,
                        movav=bt.ind.EMA,
                    )
                
                    def __init__(self):
                        stddev = bt.ind.StdDev(self.data, period=self.p.p1)
                        u = bt.If(self.data > self.data(-1), stddev, 0.0)
                        d = bt.If(self.data < self.data(-1), stddev, 0.0)
                
                        self.l.nU = nU = self.p.movav(u, period=self.p.p2)
                        self.l.nD = nD = self.p.movav(d, period=self.p.p2)
                
                        self.l.rv = 100.0 * nU / (nU + nD)
                
                1 Reply Last reply Reply Quote 1
                • 1 / 1
                • First post
                  Last post
                Copyright © 2016, 2017, 2018, 2019, 2020, 2021 NodeBB Forums | Contributors