Get name of data inside the indicator
-
I am trying to develop dividends indicator and in order to read file with dividends I need to pass data name to the indicator (currently the indicator value is set to 1.0 along the timeline:
class Dividends(bt.Indicator): lines = ('value', ) params = (('data', None), ) def __init__(self): print(self.p.data._name) self.lines.value = bt.LineNum(1.0)
In the strategy
__init()__
I call it as follows:divs = Dividends(data=self.data0).lines.value
This is the output (data name is printed in the first line):
XLY Traceback (most recent call last): File "etf_viewer.py", line 85, in <module> volup = 'green', voldown = 'red', voltrans = 50.0, voloverlay = False) File "D:\Python27\lib\site-packages\backtrader\cerebro.py", line 659, in plot start=start, end=end) File "D:\Python27\lib\site-packages\backtrader\plot\plot.py", line 226, in plot downinds=self.dplotsdown[ind]) File "D:\Python27\lib\site-packages\backtrader\plot\plot.py", line 388, in plotind indlabel = ind.plotlabel() File "D:\Python27\lib\site-packages\backtrader\lineseries.py", line 455, in plotlabel sublabels[i] = sublabel.plotinfo.plotname or \ AttributeError: 'AutoInfoClass_pi_LineSeries_pi_DataSeries_pi_OHLC_' object has no attribute 'plotname'
So data is passed and name is extracted as expected. But
cerebro.plot()
failed to plot the diagram. If I remove all items related todata
, then it works well and draws appropriate diagram.Is it appropriate way to get data name in the indicator? What does it need to run?
-
It seems superfluous to pass
data
as a named parameter, because the indicator already receives adata
, either automatically or manually and has aself.datas
array and aliases likeself.data
,self.data0
.Either use that approach Assign a
plotname
todata
underplotinfo
-
I do not understand how does that work.
Say, I have added 2 security OHLCV data and 4 other data of passed into cerebros by
cerebro.adddata()
, how do I assign/construct signals from those 4 data to trade on the 2 securities?Right now I am just manually coding the strategy w/o using SignalStrategy or indicators and I am still having a hard time keeping track of everything especially orders since I can't seem to find the ticker name from the order object.
-
An
Order
instance (let's call itorder
) carries an attributedata
which is the asset on which the order has been issued. The ticker name should be available as:order.data._name
(where_name
is the name you have assigned when usingadddata
)Names are actually a late addition to backtrader, because one of the underlying design concepts is that the development of a trading idea should, ideally, not be bound to a specific asset.
A
signal
/indicator
has (like aStrategy
) receives an array of the available data feeds in the environment in which they are instantiated (anIndicator
can be instantiated inside aStrategy
or inside anotherIndicator
)If your
Strategy
has 4 data feeds, the indicator will default to receiving 4 data feeds, which will be available in the iterableself.datas
and asself.data0
, ...,self.data3
. Most indicators actually only use 1 data feed. One can actually declare that a given indicator must receive more than 1 data feed.Notice that it defaults to receiving the data feeds from the environment.. Because if the user specifies which data feeds go by passing them to the instantiation, those will be the ones passed.
Another reason not to rely on names is that an indicator can receive another indicator as data feed. For example:
sma_on_sma = bt.ind.SMA(bt.ind.SMA(self.data1, period=10), period=20)
The outer
SMA
receives the innerSMA
as data feed. And this data feed carries no name, even if it's calculating the simple moving average ofself.data1
. We still don't know whatself.data1
is. It could be anRSI
for example. See:class MyInd1(bt.Indicator): lines = ('sma_on_sma',) def __init__(self): self.lines.sma_on_sma = bt.ind.SMA(bt.ind.SMA(self.data1, period=10), period=20) class MyInd2bt.Indicator): lines = ('myline',) def __init__(self): self.lines.myline = MyInd1(self.data, bt.ind.RSI(self.data))
MyInd2
passes 2 data feeds, one is the main data feed received (which can be anythin) and the 2nd is the RSI. As suchMyInd1
receives anRSI
instance asself.data1
, but it doesn't know it. It simply does anSMA
on it and then a 2ndSMA
If your signal is going to be name-bound, it will be limited to real data feeds which carry a
_name
attribute and will fail to be generic for any kind of actual data feed, like in the examples above.class MyInd3(bt.Indicator): lines = ('name_bound',) def __init__(self): if self.data0._name == 'my-preferred-name': self.lines.name_bound = bt.ind.SMA(self.data3) else: self.lines.name_bound = bt.ind.SMA(self.data2)
At least
data0
must be a real data feed with a name in that example.