passing data to strategy via an *args
-
I have a pairs strategy, that I want to re-use with multiple pairs. When I add the strategy as thus:
`cerebro.addstrategy(TestStrategy,d0=NTRS,d1=PNC)`
and then for my main :
`def __init__(self,d0,d1):`
with in that I try to pull the data from that
` self.data_0_close = self.d0.close self.data_1_close = self.d1.close`
however when I run the strategy I get the following error:
'Lines_LineSeries_LineIterator_DataAccessor_Strateg' object has no attribute 'd0'
-
-
@nooby_mcnoob
thanks you, that makes more sense.for anyone in the future: if you are using multiple data sets and want to define the data that goes specifically to that strategy. You need to define the data when you import it.
data_feed_X = bt.feeds.GenericCSVData()
when you add a strategy you need to pass the data you want to that strategy IE
cerebro.addstrategy(TestStrategy,d0=data_feed_X,d1=data_feed_Y)
then with in the strategy you need to add params that pull the data into the strategy, IE:
params = ( ('d0', None ), ('d1', None), )
now you are set you can call:
self.params.d0.close[0]
and it will work just like calling data0 or datas0 or so on.
-
I fail to understand the logic of passing the data feeds as
**kwargs
(because they are not being passed as*args
)The system puts the data feeds already at your disposal as:
- Members of the array
self.datas[x]
- Direct aliases
self.data0
(akaself.data
),self.data1
,self.data2
,self.dataN
- Access by name with
self.dnames.NAME_GIVEN_TO_DATA
orself.dnames[NAME_GIVEN_TO_DATA]
See: Docs - Strategy
You probably want to assign names to the data feeds you want to address and then access them.
In any case you can shorten (as shown in many of the many available samples)
self.params
toself.p
- Members of the array
-
I have a dictionary filled with maybe 100 pairs.
I use that dictionary to pull the data, i also use that dic to dynamically create "cerebro.addstrategy" based on what data feeds get created.
at a minimum i have to pass the dnames, so that I can use
self.dnames.NAME_GIVEN_TO_DATA
the above for me was nothing more than an exercise to understand how info is passed from main, to a single strategy.
-
-
You can add all the data feeds into
cerebro
by regular approach usingcerebro.adddata()
and pass data names as parameters of the strategy. In the strategy get the data by data name and do all necessary actions. -
to make things easier to understand here is the general idea of the code of how I am doing it. It works exactly as i want it to but the question at this point is am i making it more complicated than it needs to be for the platform.
class TestStrategy(bt.Strategy): params = ( ('delta', 1e-7), ('d0', None), ('d1', None), ('printlog', False), ) def __init__(self): #brings params into into self.d0 = self.params.d0 self.d1 = self.params.d1 #renames data feeds self.data_0_close = self.dnames[self.d0].close self.data_1_close = self.dnames[self.d1].close def notify_order(self, order): def next(self): if __name__ == '__main__': cerebro = bt.Cerebro(stdstats=False) start_date = datetime.datetime(2017, 2, 1) end_date = datetime.datetime(2018, 1, 3) #dic of pairs pairs = {"P0": ['AAPL', 'MSFT'], "P1": ['GOOG', 'SPY'], "P2": ['C', 'BAC'], "P3": ['JPM', 'UCBI'], "P4": ['FB', 'WEC']} ##IMPORTS DATA IN THE PAIRS DIC for pair_num, symbols in pairs.items(): for symbol in symbols: globals()['%s' % symbol] = bt.feeds.GenericCSVData( dataname='./%s-2M.csv' % symbol, fromdate=start_date, todate=end_date, timeframe=bt.TimeFrame.Minutes, compression=90, dtformat=('%Y-%m-%d %H:%M:%S'), sessionstart=datetime.time(9, 30), sessionend=datetime.time(16, 00), datetime=0, high=1, low=2, open=3, close=4, volume=5, openinterest=6, ) cerebro.adddata(globals()['%s' % symbol], name='%s' % symbol) ##CREATES NEW STRATEGY FOR EVERY PAIRS IN DIC for pair_num, symbols in pairs.items(): cerebro.addstrategy(TestStrategy, d0='%s' % symbols[0], d1='%s' % symbols[1]) cerebro.broker.setcash(1650000.0) print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue()) cerebro.run() print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
-
alright , so using the above code. If I run pair P0 and the output is $500 and then separately and by itself I run P1and it outputs net profit of $500. However if I run P0 and P1 I get a gross total of 1100, which does not make sense. It does not matter if you set cash to 10m either. What is the proper way to debug this?
-
@blonc said in passing data to strategy via an *args:
alright , so using the above code.
I am really surprised that you have any profits running the code above :), since this code doesn't issue buy/sell orders.
However, as a first guess, I would assume that you open position based on % of equity, and this % has different dollar value when you run two pairs or a single pair.
-
@blonc said in passing data to strategy via an *args:
alright , so using the above code. If I run pair P0 and the output is $500 and then separately and by itself I run P1and it outputs net profit of $500.
for anyone in the future the above problem is related to the bellow issue:
from @backtrader :
"The system won't enter the next phase of the strategy until all data feeds (and also the associated indicators) have covered the warm-up period (aka as minperiod)The reason is clear: in next all elements are guaranteed to have a value available at index [0]. Hence the need to await the minimum period of all elements to be consumed.
If you need to access data before, use prenext, but each element will have to be checked for actual data.
See:
Docs - Operating the Platform
Docs - Strategy
" -
@blonc said in passing data to strategy via an *args:
the bellow issue:
And what's exactly the issue?
That's a well defined and documented behavior of the platform. It has also been discussed before by people who wanted to access data before all warm-up periods were fulfilled and worked using
prenext
and adding multiple checks.