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

Pyfolio integration in backtrader 1.9.36



  • It seems there been a change to pyfolio integration in Backtrader 1.9.36 that's not yet updated in the documentation.

    I was able to put together an analyzer for pyfolio using similar code to the pyfolio integration doc:

        ...
        results = cerebro.run()
            
        strat = results[0]
        pyfoliozer = strat.analyzers.getbyname('pyfolio')
        returns, positions, transactions, gross_lev = pyfoliozer.get_pf_items()
        
        return returns, positions, transactions
    if __name__ == '__main__':
        r, p, t = runstrat()
    

    But after updating to 1.9.36, the above code throws the following error:

    ---------------------------------------------------------------------------
    ValueError                                Traceback (most recent call last)
    <ipython-input-24-01fb6dde8296> in <module>()
         72 
         73 if __name__ == '__main__':
    ---> 74     r, p, t = run_strat()
         75     #run_strat()
    
    <ipython-input-24-01fb6dde8296> in run_strat()
         66     cerebro.plot()
         67     strat = results[0]
    ---> 68     pyfoliozer = strat.analyzers.getbyname('pyfolio')
         69     returns, positions, transactions, gross_lev = pyfoliozer.get_pf_items()
         70 
    
    C:\Anaconda3\envs\backtrader\lib\site-packages\backtrader\metabase.py in getbyname(self, name)
        322 
        323     def getbyname(self, name):
    --> 324         idx = self._names.index(name)
        325         return self._items[idx]
    
    ValueError: 'pyfolio' is not in list
    

    I noticed that pyfolio.py has been added to the analyzers directory. So I made some change to the code using bt.analyzers.

        cerebro.addanalyzer(bt.analyzers.pyfolio, _name='pyfolio')
        
        results = cerebro.run()
            
        cerebro.plot()
        strat = results[0]
        returns, positions, transactions, gross_lev = strat.analyzers.pyfolio.get_pf_items()
        
        return returns, positions, transactions
    
    if __name__ == '__main__':
        r, p, t = run_strat()
    

    However, the modifed code throws me the following error. It seems that backtrader is having trouble adding bt.analyzers.pyfolio to the list of analyzers? What's the right way to add pyfolio analyzer?

    ---------------------------------------------------------------------------
    TypeError                                 Traceback (most recent call last)
    <ipython-input-4-96f6582b3ef5> in <module>()
         70 
         71 if __name__ == '__main__':
    ---> 72     r, p, t = run_strat()
         73     #run_strat()
    
    <ipython-input-4-96f6582b3ef5> in run_strat()
         61     cerebro.addanalyzer(bt.analyzers.pyfolio, _name='pyfolio')
         62 
    ---> 63     results = cerebro.run()
         64 
         65     cerebro.plot()
    
    C:\Anaconda3\envs\backtrader\lib\site-packages\backtrader\cerebro.py in run(self, **kwargs)
        792             # let's skip process "spawning"
        793             for iterstrat in iterstrats:
    --> 794                 runstrat = self.runstrategies(iterstrat)
        795                 self.runstrats.append(runstrat)
        796         else:
    
    C:\Anaconda3\envs\backtrader\lib\site-packages\backtrader\cerebro.py in runstrategies(self, iterstrat, predata)
        894 
        895                 for ancls, anargs, ankwargs in self.analyzers:
    --> 896                     strat._addanalyzer(ancls, *anargs, **ankwargs)
        897 
        898                 sizer, sargs, skwargs = self.sizers.get(idx, defaultsizer)
    
    C:\Anaconda3\envs\backtrader\lib\site-packages\backtrader\strategy.py in _addanalyzer(self, ancls, *anargs, **ankwargs)
        220         nsuffix = next(self._alnames[anname])
        221         anname += str(nsuffix or '')  # 0 (first instance) gets no suffix
    --> 222         analyzer = ancls(*anargs, **ankwargs)
        223         self.analyzers.append(analyzer, anname)
        224 
    
    TypeError: 'module' object is not callable
    

  • administrators

    It seems there been a change to pyfolio integration in Backtrader 1.9.36 that's not yet updated in the documentation.

    Which change?

    What's the right way to add pyfolio analyzer?

    Using the name of the analyzer PyFolioand not that of the internal module pyfolio. From the docs Docs - PyFolio Integration

    cerebro.addanalyzer(bt.analyzers.PyFolio, _name='pyfolio')
    


  • can you paste here the full code which can run pyfolio analyzer successfully with latest version of backtrader?



  • @eduedix

    Hi,

    This is what I do to use pyfolio:

            cerebro = bt.Cerebro()
            cerebro.broker.setcash(cash)
            cerebro.addanalyzer(bt.analyzers.PyFolio, _name='pyfolio')
    
            for s in symbols:
                df = pd.read_csv(os.path.join(path_dir, '{}.csv'.format(s)), parse_dates=True, index_col=0)
                data = bt.feeds.PandasData(dataname=df)
                cerebro.adddata(data)
    
            cerebro.addstrategy(strategy, **params)
    
            results = cerebro.run()
            strat = results[0]
            pyfoliozer = strat.analyzers.getbyname('pyfolio')
            returns, positions, transactions, gross_lev = pyfoliozer.get_pf_items()
    

    Hope this helps.



  • @laurent-michelizza thanks, will try it out.



  • @laurent-michelizza said in Pyfolio integration in backtrader 1.9.36:

        cerebro.addstrategy(strategy, **params)
    

    tried out now, I receive error when I try it as suggested. My code looks like:

       cerebro.broker.setcash(100.0)
    
        cerebro.adddata(data)
        data1 = cerebro.resampledata(
            data, timeframe=bt.TimeFrame.Minutes, compression=240)
        data2 = cerebro.resampledata(
            data, timeframe=bt.TimeFrame.Days, compression=1)
    
        cerebro.addstrategy(St)
    
        cerebro.addanalyzer(btanalyzers.SharpeRatio, _name='mysharpe',
                            timeframe=bt.TimeFrame.Days, compression=1, riskfreerate=RISKFREERATE)
        cerebro.addanalyzer(bt.analyzers.PyFolio, _name='pyfolio')
    
        # cerebro.addanalyzer(BasicTradeStats, filter='all')
        cerebro.addanalyzer(btanalyzers.SQN)
        cerebro.addanalyzer(bt.analyzers.TradeAnalyzer, _name="ta")
    
    
    
        strats = cerebro.run()
    
        ss = strats[0]
        pyfoliozer = ss.analyzers.getbyname('pyfolio')
    
    
        returns, positions, transactions, gross_lev = pyfoliozer.get_pf_items()
    

    The error is:

    IndexError                                Traceback (most recent call last)
    ~/Documents/Devel/trade/bt_ib.py in <module>()
        129 
        130 if __name__ == '__main__':
    --> 131     run()
    
    ~/Documents/Devel/trade/bt_ib.py in run(args)
        110     print('Starting portfolio: %f' % cerebro.broker.getvalue())
        111 
    --> 112     strats = cerebro.run()
        113 
        114     ss = strats[0]
    
    ~/.virtualenvs/trade-7uGUPCDQ/lib/python3.6/site-packages/backtrader/cerebro.py in run(self, **kwargs)
       1125             # let's skip process "spawning"
       1126             for iterstrat in iterstrats:
    -> 1127                 runstrat = self.runstrategies(iterstrat)
       1128                 self.runstrats.append(runstrat)
       1129                 if self._dooptimize:
    
    ~/.virtualenvs/trade-7uGUPCDQ/lib/python3.6/site-packages/backtrader/cerebro.py in runstrategies(self, iterstrat, predata)
       1296                     self._runnext_old(runstrats)
       1297                 else:
    -> 1298                     self._runnext(runstrats)
       1299 
       1300             for strat in runstrats:
    
    ~/.virtualenvs/trade-7uGUPCDQ/lib/python3.6/site-packages/backtrader/cerebro.py in _runnext(self, runstrats)
       1628                 self._check_timers(runstrats, dt0, cheat=False)
       1629                 for strat in runstrats:
    -> 1630                     strat._next()
       1631                     if self._event_stop:  # stop if requested
       1632                         return
    
    ~/.virtualenvs/trade-7uGUPCDQ/lib/python3.6/site-packages/backtrader/strategy.py in _next(self)
        326 
        327         minperstatus = self._getminperstatus()
    --> 328         self._next_analyzers(minperstatus)
        329         self._next_observers(minperstatus)
        330 
    
    ~/.virtualenvs/trade-7uGUPCDQ/lib/python3.6/site-packages/backtrader/strategy.py in _next_analyzers(self, minperstatus, once)
        364                 analyzer._nextstart()  # only called for the 1st value
        365             else:
    --> 366                 analyzer._prenext()
        367 
        368     def _settz(self, tz):
    
    ~/.virtualenvs/trade-7uGUPCDQ/lib/python3.6/site-packages/backtrader/analyzer.py in _prenext(self)
        148     def _prenext(self):
        149         for child in self._children:
    --> 150             child._prenext()
        151 
        152         self.prenext()
    
    ~/.virtualenvs/trade-7uGUPCDQ/lib/python3.6/site-packages/backtrader/analyzer.py in _prenext(self)
        150             child._prenext()
        151 
    --> 152         self.prenext()
        153 
        154     def _notify_cashvalue(self, cash, value):
    
    ~/.virtualenvs/trade-7uGUPCDQ/lib/python3.6/site-packages/backtrader/analyzer.py in prenext(self)
        227         The default behavior for an analyzer is to invoke ``next``
        228         '''
    --> 229         self.next()
        230 
        231     def nextstart(self):
    
    ~/.virtualenvs/trade-7uGUPCDQ/lib/python3.6/site-packages/backtrader/analyzers/positions.py in next(self)
         76 
         77     def next(self):
    ---> 78         pvals = [self.strategy.broker.get_value([d]) for d in self.datas]
         79         if self.p.cash:
         80             pvals.append(self.strategy.broker.get_cash())
    
    ~/.virtualenvs/trade-7uGUPCDQ/lib/python3.6/site-packages/backtrader/analyzers/positions.py in <listcomp>(.0)
         76 
         77     def next(self):
    ---> 78         pvals = [self.strategy.broker.get_value([d]) for d in self.datas]
         79         if self.p.cash:
         80             pvals.append(self.strategy.broker.get_cash())
    
    ~/.virtualenvs/trade-7uGUPCDQ/lib/python3.6/site-packages/backtrader/brokers/bbroker.py in get_value(self, datas, mkt, lever)
        420             return self._value if not lever else self._valuelever
        421 
    --> 422         return self._get_value(datas=datas, lever=lever)
        423 
        424     getvalue = get_value
    
    ~/.virtualenvs/trade-7uGUPCDQ/lib/python3.6/site-packages/backtrader/brokers/bbroker.py in _get_value(self, datas, lever)
        444                 dvalue = comminfo.getvalue(position, data.close[0])
        445             else:
    --> 446                 dvalue = comminfo.getvaluesize(position.size, data.close[0])
        447 
        448             dunrealized = comminfo.profitandloss(position.size, position.price,
    
    ~/.virtualenvs/trade-7uGUPCDQ/lib/python3.6/site-packages/backtrader/linebuffer.py in __getitem__(self, ago)
        161 
        162     def __getitem__(self, ago):
    --> 163         return self.array[self.idx + ago]
        164 
        165     def get(self, ago=0, size=1):
    
    IndexError: array index out of range
    

    I don't receive any errors when I remove the lines related to pyfolio. What might be the reason of this error do you think?

    Thank you in advance.


  • administrators

    First and foremost, pyfolio wasn't meant for sub-day data.

    Second: the error is because a data feed has not delivered yet, which may be related to the above.