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

Stochastic RSI indicator.



  • Hi colleagues.
    I've finished stoch RSI indicator and i would like to share it. It has the same K & D values as the Tradingview stoch RSI.
    https://www.tradingview.com/wiki/Stochastic_RSI_(STOCH_RSI)

    My applauds to the Backtrader developers team - excellent platform. Any comments are welcome.

    from backtrader.indicators import Indicator, MovAv, RelativeStrengthIndex, Highest, Lowest
    class StochasticRSI(Indicator):
          """
          K - The time period to be used in calculating the %K. 3 is the default.
          D - The time period to be used in calculating the %D. 3 is the default.
          RSI Length - The time period to be used in calculating the RSI
          Stochastic Length - The time period to be used in calculating the Stochastic
      
          Formula:
          %K = SMA(100 * (RSI(n) - RSI Lowest Low(n)) / (RSI HighestHigh(n) - RSI LowestLow(n)), smoothK)
          %D = SMA(%K, periodD)
      
          """
          lines = ('fastk', 'fastd',)
      
          params = (
              ('k_period', 3),
              ('d_period', 3),
              ('rsi_period', 14),
              ('stoch_period', 14),
              ('movav', MovAv.Simple),
              ('rsi', RelativeStrengthIndex),
              ('upperband', 80.0),
              ('lowerband', 20.0),
          )
      
          plotlines = dict(percD=dict(_name='%D', ls='--'),
                           percK=dict(_name='%K'))
      
          def _plotlabel(self):
              plabels = [self.p.k_period, self.p.d_period, self.p.rsi_period, self.p.stoch_period]
              plabels += [self.p.movav] * self.p.notdefault('movav')
              return plabels
      
          def _plotinit(self):
              self.plotinfo.plotyhlines = [self.p.upperband, self.p.lowerband]
      
          def __init__(self):
              rsi_hh = Highest(self.p.rsi(period=self.p.rsi_period), period=self.p.stoch_period)
              rsi_ll = Lowest(self.p.rsi(period=self.p.rsi_period), period=self.p.stoch_period)
              knum = self.p.rsi(period=self.p.rsi_period) - rsi_ll
              kden = rsi_hh - rsi_ll
      
              self.k = self.p.movav(100.0 * (knum / kden), period=self.p.k_period)
              self.d = self.p.movav(self.k, period=self.p.d_period)
      
              self.lines.fastk = self.k
              self.lines.fastd = self.d


  • Thank you!

    What is the difference between your implementation and bt built-in implementation?



  • @ab_trader
    I did not find StochRSI in bt. As i see, it has only Stochastic and RSI as a separate indicators. TA-lib StochRSI has K & D values other than Tradingview.
    Tradingview (TV) is a rapidly growing JS framwork. The goal was to receive exact the same values as TV.


  • administrators

    StochRSI is a well known indicator, not something which has been invented by Tradingview.

    You probably want to rewrite this

    @nikolai said in Stochastic RSI indicator.:

          def __init__(self):
              rsi_hh = Highest(self.p.rsi(period=self.p.rsi_period), period=self.p.stoch_period)
              rsi_ll = Lowest(self.p.rsi(period=self.p.rsi_period), period=self.p.stoch_period)
              knum = self.p.rsi(period=self.p.rsi_period) - rsi_ll
              kden = rsi_hh - rsi_ll
      
              self.k = self.p.movav(100.0 * (knum / kden), period=self.p.k_period)
              self.d = self.p.movav(self.k, period=self.p.d_period)
      
              self.lines.fastk = self.k
              self.lines.fastd = self.d
    

    to look like this (and avoid unnecessary instantiation of multiple indicators and unneeded member attributes)

        def __init__(self):
            rsi = bt.ind.RSI(period=self.p.rsi_period)
            rsi_ll = bt.ind.Lowest(rsi, period=self.p.rsi_period)
            rsi_hh = bt.ind.Highest(rsi, period=self.p.rsi_period)
            stochrsi = (rsi - rsi_ll) / (rsi_hh - rsi_ll)
    
            self.l.fastk = k = self.p.movav(100.0 * stochrsi, period=self.p.k_period)
            self.l.fastd = self.p.movav(k, period=self.p.d_period)
    


  • @backtrader, thanks for help with the code. Tradingview didn't invent StochRSI of course. Their docs are a bit messy for this indicator. So, the goal was to get the same implementation.



  • @nikolai Does this give output in pandas dataframe (dateseries format output).
    What is the input used here ohlc data of each day ,hour ?
    I am keen to try this out as i am trying to build the one that exactly gives tv matching output.

    Please reply back what shall be the changes here to be done to get the output as pandas data frame.

    my email mbmarx gmail if you wish to share the code snippet please help.


  • administrators

    @marx-babu said in Stochastic RSI indicator.:

    Does this give output in pandas dataframe (dateseries format output)

    No. For the simple reason that backtrader isn't pandas. You may execute backtrader on a step by step basis (needed for live trading of course), in which case it doesn't make any sense to get a dataframe as the output of anything, given the inflexibility of a dataframe to dynamically grow.

    @marx-babu said in Stochastic RSI indicator.:

    Please reply back what shall be the changes here to be done to get the output as pandas data frame.

    There are no changes to be done. All you can do is run the complete backtest and then transform the data to be imported into a dataframe if you wish.



  • @marx-babu This is all code you need. But it works only as backtrader indicator. Feel free to use it, but you will need to understand how backtrader framework works.



  • Im new to backtrader and still trying to get the hang of it. How would I go about calling the fastk and fastd lines in my strategy? Doing StochasticRSI.lines.fastk throws me an attribute error (AttributeError: 'NoneType' object has no attribute 'lines').



  • @Tomas
    Hi. I wrote an example strategy for you. You can access the indicator lines through the name in __init__ method.

    class CryptoStochRSI(bt.Strategy):
    
        params = (
            ('stoch_k_period', 3),
            ('stoch_d_period', 3),
            ('stoch_rsi_period', 14),
            ('stoch_period', 14),
            ('stoch_upperband', 80.0),
            ('stoch_lowerband', 20.0),
    
            ('take_profit', 0.04),
            ('stop_loss', 0.01),
    
            ('size', 20),
            ('debug', False),
        )
    
        def __init__(self):
    
            self.stoch = StochasticRSI(k_period=self.p.stoch_k_period,
                                       d_period=self.p.stoch_d_period,
                                       rsi_period=self.p.stoch_rsi_period,
                                       stoch_period=self.p.stoch_period,
                                       upperband=self.p.stoch_upperband,
                                       lowerband=self.p.stoch_lowerband)
    
        def next(self):
    
            if not self.position:
                close = self.data.close[0]
                price1 = close
                price2 = price1 - self.p.stop_loss * close
                price3 = price1 + self.p.take_profit * close
    
                if self.stoch.l.fastk[0] < 20:
                    self.buy_bracket(price=price1, stopprice=price2, limitprice=price3, exectype=bt.Order.Limit)
    
                if self.stoch.l.fastk[0] > 80:
                    self.sell_bracket(price=price1, stopprice=price3, limitprice=price2, exectype=bt.Order.Limit)

Log in to reply
 

});