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

AttributeError: 'ItemCollection' object has no attribute 'sharpe_ratio'



  • Following the example from Backtrader for Backtesting (Python) – A Complete Guide, I've had an error which I can't resolve in the following line:

    sharpe = strategy.analyzers.sharpe_ratio.get_analysis()
    

    That's line 119 from the following code:

    from __future__ import (absolute_import, division, print_function,
                            unicode_literals)
    
    import datetime
    import os.path
    import sys
    import math
    
    import backtrader as bt
    
    STARTING_CASH = 1700
    
    class maxRiskSizer(bt.Sizer):
        params = (('risk', 0.95),)
    
        def __init__(self):
            if self.p.risk > 1 or self.p.risk < 0:
                raise ValueError('The risk parameter is a percentage which must be'
                    'entered as a float. e.g. 0.5')
    
        def _getsizing(self, comminfo, cash, data, isbuy):
            position = self.broker.getposition(data)
    
            if not position:
                size = comminfo.getsize(data.close[0], cash * self.p.risk)
            else:
                size = position.size
    
            return size
    
    class DegiroCommission(bt.CommInfoBase):
        params = (('per_share', 0.004), ('flat', 0.5),)
    
        def _getcommission(self, size, price, pseudoexec):
            return self.p.flat + size * self.p.per_share
    
    class SMAcrossover(bt.Strategy):
        params = (('fast', 20), ('slow', 50),)
    
        def log(self, txt, dt=None):
            dt = dt or self.datas[0].datetime.date(0)
            #print(f'{dt.isoformat()} {txt}') # Comment this line when running optimization
    
        def __init__(self):
            self.dataclose = self.datas[0].close
            self.order = None
    
            fast_sma, slow_sma = bt.ind.SMA(period=self.p.fast), bt.ind.SMA(period=self.p.slow)
            self.crossover = bt.indicators.CrossOver(fast_sma, slow_sma)
            #self.signal_add(bt.SIGNAL_LONGSHORT, bt.ind.CrossOver(sma1, sma2))
    
        def notify_trade(self, trade):
            if not trade.isclosed:
                return
    
            self.log(f'GROSS {trade.pnl:.2f}, NET {trade.pnlcomm:.2f}')
    
        def notify_order(self, order):
            if order.status in [order.Submitted, order.Accepted]:
                # An active Buy/Sell order has been submitted/accepted - Nothing to do
                return
    
            # Check if an order has been completed
            # Attention: broker could reject order if not enough cash
            if order.status in [order.Completed]:
                if order.isbuy():
                    self.log(f'BUY EXECUTED, {order.executed.price:.2f}')
                elif order.issell():
                    self.log(f'SELL EXECUTED, {order.executed.price:.2f}')
                self.bar_executed = len(self)
    
            elif order.status in [order.Canceled, order.Margin, order.Rejected]:
                self.log('Order Canceled/Margin/Rejected')
    
            # Reset orders
            self.order = None
    
        def next(self):
            # Check for open orders
            if self.order:
                return
    
            if self.crossover > 0:
                self.log(f'BUY CREATE {self.dataclose[0]:.2f}')
                self.order = self.buy()
            elif self.crossover < 0:
                self.log(f'SELL CREATE {self.dataclose[0]:.2f}')
                self.order = self.sell()
    
    if __name__ == '__main__':
        cerebro = bt.Cerebro(optreturn=False)
        cerebro.optstrategy(SMAcrossover, fast=range(5,7), slow=range(50,52))
        #cerebro.optstrategy(SMAcrossover, fast=range(5,55,5), slow=range(60,310,10))
        cerebro.broker.set_cash(STARTING_CASH)
        cerebro.broker.set_coc(True)
    
        modpath = os.path.dirname(os.path.abspath(sys.argv[0]))
        datapath = os.path.join(modpath, 'datas/CPE.csv')
        data = bt.feeds.YahooFinanceCSVData(
            dataname=datapath,
            # Do not pass values before this date
            fromdate=datetime.datetime(1990, 10, 1),
            # Do not pass values after this date
            todate=datetime.datetime(2020, 10, 15),
            reverse=False
        )
        cerebro.adddata(data)
    
        cerebro.addsizer(maxRiskSizer)
        comminfo = DegiroCommission()
        cerebro.broker.addcommissioninfo(comminfo)
    
        optimized_runs = cerebro.run()
    
        final_results_list = []
        for run in optimized_runs:
            for strategy in run:
                PnL = round(strategy.broker.get_value() - STARTING_CASH,2)
                sharpe = strategy.analyzers.sharpe_ratio.get_analysis()
                final_results_list.append([strategy.params.fast, 
                    strategy.params.slow, PnL, sharpe['sharperatio']])
    
        sort_by_sharpe = sorted(final_results_list, key=lambda x: x[3], 
                                 reverse=True)
        for line in sort_by_sharpe[:5]:
            print(line)
    


  • your code is missing adding the actual analyzer (it appears in the original article):

    cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='sharpe_ratio')
    

Log in to reply
 

});