Unable to plot 2nd level nested indicator
-
Hi guys,
First of all, thanks for such a great tool for backtesting investing ideas!
I try to plot a nested indicator. By nesting I mean using one's indicator data as entry data for another's indicator data.
Here is what I do, based on the simple example from readme:
from datetime import datetime import backtrader as bt class SmaCross(bt.SignalStrategy): def __init__(self): sma1, sma2 = bt.ind.SMA(period=10), bt.ind.SMA(period=30) crossover = bt.ind.CrossOver(sma1, sma2) self.signal_add(bt.SIGNAL_LONG, crossover) mom = bt.ind.Momentum() mommom = bt.ind.Momentum(mom) mommommom = bt.ind.Momentum(mommom, plotforce=True) cerebro = bt.Cerebro() cerebro.addstrategy(SmaCross) data0 = bt.feeds.YahooFinanceCSVData(dataname='data/GLD.csv', fromdate=datetime(2011, 1, 1), todate=datetime(2012, 12, 31)) cerebro.adddata(data0) cerebro.run() cerebro.plot()
It crashes with:
$ python smacross.py Traceback (most recent call last): File "smacross.py", line 21, in <module> cerebro.plot() File "/Users/adam/.pyenv/versions/backtrader/lib/python3.5/site-packages/backtrader/cerebro.py", line 991, in plot start=start, end=end, use=use) File "/Users/adam/.pyenv/versions/backtrader/lib/python3.5/site-packages/backtrader/plot/plot.py", line 134, in plot self.sortdataindicators(strategy) File "/Users/adam/.pyenv/versions/backtrader/lib/python3.5/site-packages/backtrader/plot/plot.py", line 856, in sortdataindicators if key not in strategy.datas: File "/Users/adam/.pyenv/versions/backtrader/lib/python3.5/site-packages/backtrader/lineroot.py", line 281, in __eq__ return self._operation(other, operator.__eq__) File "/Users/adam/.pyenv/versions/backtrader/lib/python3.5/site-packages/backtrader/lineroot.py", line 86, in _operation other, operation, r=r, intify=intify) File "/Users/adam/.pyenv/versions/backtrader/lib/python3.5/site-packages/backtrader/lineroot.py", line 201, in _operation_stage1 return self._makeoperation(other, operation, r, self) File "/Users/adam/.pyenv/versions/backtrader/lib/python3.5/site-packages/backtrader/lineroot.py", line 331, in _makeoperation return self.lines[0]._makeoperation(other, operation, r, _ownerskip) File "/Users/adam/.pyenv/versions/backtrader/lib/python3.5/site-packages/backtrader/linebuffer.py", line 378, in _makeoperation _ownerskip=_ownerskip) File "/Users/adam/.pyenv/versions/backtrader/lib/python3.5/site-packages/backtrader/linebuffer.py", line 522, in __call__ return super(MetaLineActions, cls).__call__(*args, **kwargs) File "/Users/adam/.pyenv/versions/backtrader/lib/python3.5/site-packages/backtrader/metabase.py", line 89, in __call__ _obj, args, kwargs = cls.dopostinit(_obj, *args, **kwargs) File "/Users/adam/.pyenv/versions/backtrader/lib/python3.5/site-packages/backtrader/linebuffer.py", line 566, in dopostinit _obj._owner.addindicator(_obj) AttributeError: 'NoneType' object has no attribute 'addindicator'
Without
plotforce=True
it won't crash, but the plot is still not visible.My env is macOS Catalina 10.15.3, Python 3.5.9 with packages:
$ pip freeze backtrader==1.9.74.123 cycler==0.10.0 kiwisolver==1.1.0 matplotlib==3.0.3 numpy==1.18.3 pyparsing==2.4.7 python-dateutil==2.8.1 six==1.14.0
Any help would be appreciated :)
Thanks in advance and keep up the fantastic work!
Adam -
as a quick solution - you can put all three indicators on the same plot using
plotmaster=mom
parameter for 2nd and 3rd indicator. -
Yeah that worked! Thanks a lot :)
Meanwhile I've found another workaround, using dedicated indicator and nesting other indicator inside it:
from datetime import datetime import backtrader as bt class NestedMomentum(bt.Indicator): lines = ('mom', 'mommom', 'mommommom') def __init__(self): self.l.mom = bt.ind.Momentum() self.l.mommom = bt.ind.Momentum(self.l.mom) self.l.mommommom = bt.ind.Momentum(self.l.mommom) class SmaCross(bt.SignalStrategy): def __init__(self): sma1, sma2 = bt.ind.SMA(period=10), bt.ind.SMA(period=30) crossover = bt.ind.CrossOver(sma1, sma2) self.signal_add(bt.SIGNAL_LONG, crossover) # plotmaster workaround mom = bt.ind.Momentum() mommom = bt.ind.Momentum(mom, plotmaster=mom) mommommom = bt.ind.Momentum(mommom, plotmaster=mom) # custom indicator workaround nested = NestedMomentum() cerebro = bt.Cerebro() cerebro.addstrategy(SmaCross) data0 = bt.feeds.YahooFinanceCSVData(dataname='data/GLD.csv', fromdate=datetime(2011, 1, 1), todate=datetime(2012, 12, 31)) cerebro.adddata(data0) cerebro.run() cerebro.plot()
Anyway it looks like a bug, but I'm happy there are workarounds :)
-
@aartajew it seems like an issue in the
bt
script, but to be 100% sure we need to hear from author or get deeper intobt
scripts with debugger.