Wrong value of Indicator in another CustomIndicator
-
class SomeStrategy(bt.Strategy): def __init__(self): self.atr = bt.indicators.ATR(self.datas[0], plotname="ATR", subplot=True) self.sr = SR(logger=self.indi_logger, master=self, fromdate=self.p.fromdate_trading, todate=self.p.todate_trading)
Within my custom indicator
SR
I need to access theATR line value
withinSR->next()
. So I pass the wholeself
to it during init:class SR(bt.Indicator): def __init__(self, logger, master, fromdate, todate): self.logger = logger self.master = master self.atr = self.master.atr
In this example I would assume to access the
ATR line value
of candle 2001-09-10 usingself.atr[0]
(which is about0.51
). Instead I get the finalATR line value
of today (which is2.67588x
):Do I need to calculate the shift manually to get the correct ATR value or is there another way to achieve this?
Thanks & BR!
-
Generating it new in the custom indicator worked for me:
class SomeStrategy(bt.Strategy): def __init__(self): self.atr = bt.indicators.ATR(self.datas[0], subplot=False)
-
Of course, creating an indicator within an indicator allows the created indicator to report itself to the environment it is being created in. i.e.: the other indicator.
In any case the use case presented in the 1st post can work, but only if you let the platform know (and it doesn't take much)
@cgi1 said in Wrong value of Indicator in another CustomIndicator:
self.atr = self.master.atr
The problem there is:
self.master.atr
can be anything. It could be a callable. The indicatorSR
has no way of knowing what's in the attributeatr
.@cgi1 said in Wrong value of Indicator in another CustomIndicator:
In this example I would assume to access the ATR line value of candle 2001-09-10 using self.atr[0] (which is about 0.51). Instead I get the final ATR line value of today (which is 2.67588x)
That's a side effect of the above. Knowing nothing about
atr
, the indicatorSR
accesses[0]
and because you are running withrunonce=True
, you get the last calculated value. IfSR
had known something aboutatr
it would have managed it to give you the right value of[0]
each time.Even if you now think that the problem goes away by doing
runonce=False
... yes it would but for the wrong reasons.What you have to take into account is that mostly everything behaves like a data feed (See the section Almost everything is a Data Feed under Docs - Platform Concepts)
And that's why the proper approach that will work under all conditions is:
class SomeStrategy(bt.Strategy): def __init__(self): self.atr = bt.indicators.ATR(self.datas[0], plotname="ATR", subplot=True) self.sr = SR(self.atr, logger=self.indi_logger, master=self, fromdate=self.p.fromdate_trading, todate=self.p.todate_trading)
followed by
class SR(bt.Indicator): def __init__(self, logger, master, fromdate, todate): self.logger = logger self.master = master # NO LONGER NEEDED - atr is `self.data` aka `self.data0` aka `self.datas[0]` # self.atr = self.master.atr
Because
atr
is passed as a data feed toSR
it will properly managed under all circumstances. -
Thanks for the good explanation! That´s a view of data feeds I did not had in before.
So
self.datas[0]
withinSR(bt.Indicator)
are now set correctly to the values ofATR
.The limitation now is, that there is no
YahooDataFeed
available anymore, because the data feed gets overwritten byself.sr = SR(self.atr, [...])
Is it possible to pass multiple data feeds to the indicator?
In this case the market data (YahooDataFeed
) and another indicator (ATR
)Something like:
self.sr = SR([self.datas[0], self.atr, self.further_indi], [...])
-
Of course. You can pass any number of data-feed-like objects to indicators. They will be available as
self.dataX
or the correspondingself.datas[X]
In the previous example and because no data feed was explicitly passed, the framework gives the indicator the same data feeds which are available in the strategy (or parent indicator)
-
@backtrader said in Wrong value of Indicator in another CustomIndicator:
Of course. You can pass any number of data-feed-like objects to indicators. They will be available as
self.dataX
or the correspondingself.datas[X]
Nice. For reference:
self.sr = SR(self.datas[0], self.atr)
Gives
inside custom indicator
SR
. So it can be used likeclass SR(bt.Indicator): def __init__(self, logger, master, fromdate, todate): # self.datas[0] is yahoo market data (as default) self.atr = self.datas[1]
DONE