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/

    Laguerre RSI

    Indicators/Strategies/Analyzers
    3
    10
    5052
    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

      Attempting to write this indicator and while I think I am close, I'm not understanding why the appearance of the graphs in matplotlib vs. the other App I am looking at for comparison are not the same. Perhaps I can be educated. :-)

      I also could use some guidance as to how to decide whether to develop these indicators using the __init__() and LineBuffers or in next():.

      Here is current BT code for Laguerre RSI:

      #!/usr/bin/env python
      # -*- coding: utf-8; py-indent-offset:4 -*-
      
      from __future__ import (absolute_import, division, print_function,
                              unicode_literals)
      
      import backtrader as bt
      
      
      class LaguerreRSI(bt.Indicator):
          alias = ('LRSI',)
          lines = ('lrsi',)
          params = (('gamma', 0.5),)
      
          plotinfo = dict(
              plotymargin=0.15,
              plotyticks=[0.0, 0.2, 0.5, 0.8, 1.0]
          )
      
          def __init__(self):
              self.addminperiod(6)
              self.l0 = [0]
              self.l1 = [0]
              self.l2 = [0]
              self.l3 = [0]
      
              self.tp = (self.data.high + self.data.low) / 2
              super(LaguerreRSI, self).__init__()
      
          def next(self):
              self.l0[0] = ((1 - self.p.gamma) * self.tp[0] +
                            self.p.gamma * self.l0[-1])
              self.l1[0] = ((-self.p.gamma * self.l0[0]) + self.l0[-1] +
                            (self.p.gamma * self.l1[-1]))
              self.l2[0] = ((-self.p.gamma * self.l1[0]) + self.l1[-1] +
                            (self.p.gamma * self.l2[-1]))
              self.l3[0] = ((-self.p.gamma * self.l2[0]) + self.l2[-1] +
                             (self.p.gamma * self.l3[-1]))
              cd = 0
              cu = 0
              if self.l0[0] >= self.l1[0]:
                  cu = self.l0[0] - self.l1[0]
              else:
                  cd = self.l1[0] - self.l0[0]
      
              if self.l1[0] >= self.l2[0]:
                  cu = cu + self.l1[0] - self.l2[0]
              else:
                  cd = cd + self.l2[0] - self.l1[0]
      
              if self.l2[0] >= self.l3[0]:
                  cu = cu + self.l2[0] - self.l3[0]
              else:
                  cd = cd + self.l3[0] - self.l2[0]
      
              self.lines.lrsi[0] = cu / (cu + cd)
      

      Here is some C# code for Laguerre that I am working from:

      using System;
      using cAlgo.API;
      using cAlgo.API.Indicators;
       
      namespace cAlgo.Indicators
      {
          [Indicator(IsOverlay = false, AccessRights = AccessRights.None)]
          public class NewIndicator : Indicator
          {
              [Parameter(DefaultValue = 0.2)]
              public double gamma { get; set; }
       
              [Output("Laguerre RSI",Color = Colors.Yellow)]
              public IndicatorDataSeries laguerrersi { get; set; }
               
              [Output("Overbought",Color = Colors.Turquoise)]
              public IndicatorDataSeries overbought { get; set; }
               
              [Output("oversold",Color = Colors.Red)]
              public IndicatorDataSeries oversold { get; set; }
               
              private IndicatorDataSeries price;
              private IndicatorDataSeries L0;
              private IndicatorDataSeries L1;
              private IndicatorDataSeries L2;
              private IndicatorDataSeries L3;
               
              double cu;
              double cd;
               
              protected override void Initialize()
              {
                  price = CreateDataSeries();
                  L0 = CreateDataSeries();
                  L1 = CreateDataSeries();
                  L2 = CreateDataSeries();
                  L3 = CreateDataSeries();
              }
       
              public override void Calculate(int index)
              {
                  overbought[index] = 0.8;
                  oversold[index] = 0.2;
                  price[index] = (MarketSeries.High[index]+MarketSeries.Low[index])/2;
                  if(index<=6)
                  {
                      L0[index] = (1-gamma)*price[index];
                      L1[index] = -gamma*L0[index] + L0[index-1];
                      L2[index] = -gamma*L1[index] + L1[index-1];
                      L3[index] = -gamma*L2[index] + L2[index-1];
                  }
                  if(index>6)
                  {
                      L0[index] = (1-gamma)*price[index] + gamma*L0[index-1];
                      L1[index] = -gamma*L0[index] + L0[index-1] + gamma*L1[index-1];
                      L2[index] = -gamma*L1[index] + L1[index-1] + gamma*L2[index-1];
                      L3[index] = -gamma*L2[index] + L2[index-1] + gamma*L3[index-1];
                  }
                 // laguerrersi[index] = L0[index];
                  cu=0;
                  cd=0;
                  if(L0[index]>=L1[index])
                  {
                      cu = L0[index]-L1[index];
                  }
                  else
                  {
                      cd = L1[index] - L0[index];
                  }
                  if(L1[index]>=L2[index])
                  {
                      cu = cu+ L1[index]-L2[index];
                  }
                  else
                  {
                      cd = cd + L2[index] - L1[index];
                  }
                  if(L2[index]>=L3[index])
                  {
                      cu = cu + L2[index] - L3[index];
                  }
                  else
                  {
                      cd = cd + L3[index] - L2[index];
                  }
                  if(cu+cd!=0)
                  {
                      laguerrersi[index] = cu / (cu+cd);
                  }
              }
          }
      }
      

      Here is the chart I am seeing:
      0_1487291725101_Selection_NNN(071).png

      Here is a look at the indicator in another system:
      0_1487291754514_Selection_NNN(072).png

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

        gamma is 0.2 in the C# code and 0.5 in python, unless you are changing things later in C# (the backtrader chart shows that gamma had a value of 0.5 during execution)

        To have equivalente code to C# you would also need to define prenext which is run before the minimum period (6) is met. There the C# calculations for if (index < 6) would be performed.

        Some thumb counting would also indicate that the minimum period in python should probably be 7. The reason being that 6 in the C# code is referring to a zero-based index, whereas the minimum period is referred to the actual len.

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

          @RandyT said in Laguerre RSI:

              self.l0 = [0]
              self.l1 = [0]
              self.l2 = [0]
              self.l3 = [0]
          

          There seems to be no append to this. References to [-1] will be the same as references to [0]

          No need for them to be lines objects, because only 2 positions are used. The quickest solution for it would be something like:

              self.l0 = [0, 0]
              self.l1 = [0, 0]
              self.l2 = [0, 0]
              self.l3 = [0, 0]
          
          1 Reply Last reply Reply Quote 0
          • RandyT
            RandyT last edited by RandyT

            The two example charts are both running with gamma = 0.5. That dark example chart is actually from Amibroker. Did not share that code as it is not very similar in logic. Can share that if useful.

            I'll give your other example a try. I was there on one iteration but had some other issue.

            The matplotlib chart actually looks like there is some smoothing happening. Not sure if there is a more responsive plotting model option that would make the difference?

            The best approach here would probably be to see if I can get Amibroker to give me the values for the LRSI indicator.

            1 Reply Last reply Reply Quote 0
            • RandyT
              RandyT last edited by

              Thanks for the guidance. While the code looks a bit hacky to me at this stage, the results look pretty legit. I'll submit a PR for this.

              0_1487304589844_Selection_NNN(076).png

              #!/usr/bin/env python
              # -*- coding: utf-8; py-indent-offset:4 -*-
              ###############################################################################
              #
              # Copyright (C) 2015, 2016, 2017 Daniel Rodriguez
              #
              # This program is free software: you can redistribute it and/or modify
              # it under the terms of the GNU General Public License as published by
              # the Free Software Foundation, either version 3 of the License, or
              # (at your option) any later version.
              #
              # This program is distributed in the hope that it will be useful,
              # but WITHOUT ANY WARRANTY; without even the implied warranty of
              # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
              # GNU General Public License for more details.
              #
              # You should have received a copy of the GNU General Public License
              # along with this program.  If not, see <http://www.gnu.org/licenses/>.
              #
              ###############################################################################
              from __future__ import (absolute_import, division, print_function,
                                      unicode_literals)
              
              import backtrader as bt
              
              
              class LaguerreRSI(bt.Indicator):
                  alias = ('LRSI',)
                  lines = ('lrsi',)
                  params = (('gamma', 0.5),)
              
                  plotinfo = dict(
                      plotymargin=0.15,
                      plotyticks=[0.0, 0.2, 0.5, 0.8, 1.0]
                  )
              
                  def __init__(self):
                      self.addminperiod(6)
                      self.l0 = [0, 0]
                      self.l1 = [0, 0]
                      self.l2 = [0, 0]
                      self.l3 = [0, 0]
              
                      super(LaguerreRSI, self).__init__()
              
                  def next(self):
                      tp = (self.data.high + self.data.low) / 2
                      self.l0.insert(0, ((1 - self.p.gamma) * tp +
                                         self.p.gamma * self.l0[0]))
                      self.l1.insert(0, (-self.p.gamma * self.l0[0] + self.l0[1] +
                                         self.p.gamma * self.l1[0]))
                      self.l2.insert(0, (-self.p.gamma * self.l1[0] + self.l1[1] +
                                         self.p.gamma * self.l2[0]))
                      self.l3.insert(0, (-self.p.gamma * self.l2[0] + self.l2[1] +
                                         self.p.gamma * self.l3[0]))
                      del self.l0[2:]
                      del self.l1[2:]
                      del self.l2[2:]
                      del self.l3[2:]
              
                      cd = 0
                      cu = 0
                      if self.l0[0] >= self.l1[0]:
                          cu = self.l0[0] - self.l1[0]
                      else:
                          cd = self.l1[0] - self.l0[0]
              
                      if self.l1[0] >= self.l2[0]:
                          cu = cu + self.l1[0] - self.l2[0]
                      else:
                          cd = cd + self.l2[0] - self.l1[0]
              
                      if self.l2[0] >= self.l3[0]:
                          cu = cu + self.l2[0] - self.l3[0]
                      else:
                          cd = cd + self.l3[0] - self.l2[0]
              
                      self.lines.lrsi[0] = cu / (cu + cd)
              
              1 Reply Last reply Reply Quote 1
              • A
                ab_trader last edited by

                Thanks @RandyT for code!
                I was thinking about of implementation of this RSI too. :)

                • If my answer helped, hit reputation up arrow at lower right corner of the post.
                • Python Debugging With Pdb
                • New to python and bt - check this out
                1 Reply Last reply Reply Quote 0
                • RandyT
                  RandyT last edited by

                  Cool, let me now if you come up with anything interesting. :-)

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

                    @RandyT Now I'll use your code :)

                    • If my answer helped, hit reputation up arrow at lower right corner of the post.
                    • Python Debugging With Pdb
                    • New to python and bt - check this out
                    1 Reply Last reply Reply Quote 0
                    • RandyT
                      RandyT last edited by

                      I hope so. :-) Let me know if you come up with any interesting systems using it.

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

                        The final implementation, already pushed to the development branch, respects the original implementation by Ehlers and rather than expecting the price component to have high and low it takes simply self.data (which unless changed is the close from regular data feeds)

                        Using it for the midpoint of the bar is easy:

                        midpoint = (self.data.high + self.data.low) / 2.0
                        lrsi = bt.ind.LRSI(midpoint)
                        

                        The advantage of not having specifics like high and low in the code is that the LRSI can be calculated for anything which is a data feed or descendant of ... you could create the LRSI of a SimpleMovingAverage

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