Question regarding Smoothed Moving Average
-
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!
-
@alain alright, i was able to implement the smoothing moving average inside the next function. it's just a bit less elegant.
-
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
forSMMA
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.
-
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...
-
Well ... after looking at this ... the actual problem is when putting
stddev
insidebt.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 ofbt.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
orEMA
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 ...
-
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
andEMA
indicators rely on the previous value to calculate the new one. As soon as one value isNaN
, the result will always be the same andNaN
. 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)