Multiple assets with custom pandas dataframe
-
Hello,
I am trying to run strategy on multiple assets that have custom pandas dataframe.
class PandasData(bt.feeds.PandasData): lines = ('pe') params = ( ('pe', 'pe'), )
There is a list of dataframes that has information for different assets
for data in list: df=PandasData(dataname=data) cerebro.adddata(df, name='abc') cerebro.run()
I am able to use this for single asset in next() using
for i, d in enumerate(self.datas): dt, dn = self.datas[0].datetime.date(0)), d._name pos = self.getposition(d).size
How can I create multiple 'pe' lines for multiple assets and use it in the next()?
-
@btr said in Multiple assets with custom pandas dataframe:
How can I create multiple 'pe' lines for multiple assets and use it in the next()?
I would say yes. You can create a custom loader that has extra lines. You will need to assign the p/e from your dataframe to a custom p/e line in backtrader. That logic you have to sort out. So maybe pe_largcap and pe_international. However you are splitting them out. To set up your custom loader, you create the following class:
class CustomPandasLoader(bt.feeds.PandasData): lines = ( "pe_largcap", "pe_international", ) params = ( ("pe_largcap", -1), ("pe_international", -1), ) datafields = bt.feeds.PandasData.datafields + ( [ "pe_largcap", "pe_international", ] )
The -1 means backtrader will seek out the column if it exist.
You can load the custom loader as follows:
data = CustomPandasLoader( dataname=df, ) cerebro.adddata(data)
Now of course when using it in next you simply call the dataline of your asset say data number 3 and:
self.datas[3].pe_international[0]
If you try to call it on another dataline where pe_interntional wans't used, you get an error. So you need to manage that in next.
-
@run-out
I am able to do this. I have custom loader that has extra columns and I am feeding it to cerebro and using it next. The issue I am facing is with applying the same logic to multiple datafeeds.Multiple data feeds means there would be pe_largcap and pe_international for all data feeds. So, if the cerebro is feed with 2 assets data, it should have 4 lines. and somehow I need to check those 4 lines in next depending on the data feed.
-
@run-out
I am trying to follow this https://backtest-rookies.com/2017/08/22/backtrader-multiple-data-feeds-indicators/ but instead of using backtrader indicators, I want to use the lines create from custom dataframe in next. I was able to implement this with single data feed. Creating the lines from custom pandas data and using that line in next.I am having issues extending the same with multiple data feeds
-
I like using pandas this way as well. If you want all the p/e's from the different assets to be compiled under one p/s inside backtrader, then just change the column name in your data frame to p/e and add it in.
I feel like my answer is too simple and I'm missing your problem. Let me know.
-
@run-out
Yes, there's misunderstanding here. p/e is just an example. Take a simple moving average strategy. I have a dataframe that already has sma crossover calculated. I am sending that dataframe to custom pandas data function and creating a line. Like this:class PandasData(bt.feeds.PandasData): lines = ('crossover') params = ( ('crossover', 'crossover'), )
and feeding it to cerebro
df=PandasData(dataname=current_df) cerebro.adddata(df, name=current_df['symbol'][0])
Now, I use this in next as following:
if self.datas[0].crossover > 0: buy() if self.datas[0].crossover < 0: sell()
This works perfectly fine. Now I am extending my strategy so that it can run over multiple assets as the same time. I am sending single dataframes to single data feed like:
resp is a list of dataframe where each has crossover already calculatedfor df in resp: data=PandasData(dataname=df) cerebro.adddata(df, name='data0') #name here would be dynamic so I can get the name in next and find which asset/dataframe's order is placed cerebro.run()
and then in next:
for i, d in enumerate(self.datas): dt, dn = self.datas[0].datetime.date(), d._name pos = self.getposition(d).size if not pos:
In order to do this in next, I would need multiple lines of crossover from custom pandas data function, one for each asset/datafeed/dataframe
-
It seems like you are doing everything right to get the datas into cerebro with one exception:
@btr said in Multiple assets with custom pandas dataframe:
for df in resp: data=PandasData(dataname=df) cerebro.adddata(df, name='data0') cerebro.run()
cerebro.run should not be part of this loop. This will run backtrader individually for the first data line. If this is just a typo let me know.
If you are not getting the dataframes properly loaded and
cerebro.run
actually is outside the loop, please provide a bit more detail as to what difficulty you are having. It seems like you are on the right track. -
@run-out
Thanks for your help. I found out that I was not using the enumerate for loop in init function so that it can run for each data feed