For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/

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 calculated

    for 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


Log in to reply
 

});