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.

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?

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.

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

You probably want to rewrite this

``````      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.

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

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
price1 = close
price2 = price1 - self.p.stop_loss * close
price3 = price1 + self.p.take_profit * close

if self.stoch.l.fastk < 20:
self.buy_bracket(price=price1, stopprice=price2, limitprice=price3, exectype=bt.Order.Limit)

if self.stoch.l.fastk > 80:
self.sell_bracket(price=price1, stopprice=price3, limitprice=price2, exectype=bt.Order.Limit)``````

});