'Lines_LineSeries_LineIterator_DataAccessor_Strateg' object has no attribute 'self'

1.3k views Asked by At

everyone!

I´m trying to replicate one of the strategies with backtrader for practice purposes, but I get this message when I try to run it: 'Lines_LineSeries_LineIterator_DataAccessor_Strateg' object has no attribute 'self'.

I want to buy when RSI is above 30 and SMA(14) crosses over SMA (50) upwards and sell when RSI is less than 70 and SMA(14) crosses over SMA (50) downwards.

Could you please help me to find where´s the error and how do I fix it? Thank you very much!

Please see below my code:

´´´

class RSI_SMA_Strategy(bt.Strategy):
    params = dict(rsi_periods=21, rsi_upper=70, 
                  rsi_lower=30, rsi_mid=50,
                 sma_periods=14, sma_periods2=50)

    def __init__(self):
        # keep track of close price in the series
        self.data_close = self.datas[0].close
        self.data_open = self.datas[0].open

        # keep track of pending orders/buy price/buy commission
        self.order = None
        self.price = None
        self.comm = None

        # initializing rsi and sma
        self.rsi = bt.indicators.RSI(self.datas[0], period=self.p.rsi_periods)
        
        self.sma14=bt.ind.SMA(self.datas[0], period=self.params.sma_periods)
        self.sma50=bt.ind.SMA(self.datas[0], period=self.params.sma_periods2)
        
        self.rsi_signal_long_buy = bt.ind.CrossUp(self.rsi, self.p.rsi_lower)
        self.rsi_signal_long_exit = bt.ind.CrossUp(self.rsi, self.p.rsi_mid)
        self.rsi_signal_short = bt.ind.CrossDown(self.rsi, self.p.rsi_upper)

    def log(self, txt):
        '''Logging function'''
        dt = self.datas[0].datetime.date(0).isoformat()
        print(f'{dt}, {txt}')

    def notify_order(self, order):
        if order.status in [order.Submitted, order.Accepted]:
            # order already submitted/accepted - no action required
            return

        # report executed order
        if order.status in [order.Completed]:
            if order.isbuy():
                self.log(
                    f'BUY EXECUTED --- Price: {order.executed.price:.2f}, Cost: {order.executed.value:.2f}, Commission: {order.executed.comm:.2f}'
                )
                self.price = order.executed.price
                self.comm = order.executed.comm
            else:
                self.log(
                    f'SELL EXECUTED --- Price: {order.executed.price:.2f}, Cost: {order.executed.value:.2f}, Commission: {order.executed.comm:.2f}'
                )

        # report failed order
        elif order.status in [order.Canceled, order.Margin, 
                              order.Rejected]:
            self.log('Order Failed')

        # set no pending order
        self.order = None

    def notify_trade(self, trade):
        if not trade.isclosed:
            return

        self.log(f'OPERATION RESULT --- Gross: {trade.pnl:.2f}, Net: {trade.pnlcomm:.2f}')

    def next_open(self):
        if not self.position:
            if self.rsi > 30 and self.self.sma14 > self.self.sma50:
                # calculate the max number of shares ('all-in')
                size = int(self.broker.getcash() / self.datas[0].open)
                # buy condition
                self.log(f'BUY CREATED --- Size: {size}, Cash: {self.broker.getcash():.2f}, Open: {self.data_open[0]}, Close: {self.data_close[0]}')
                self.buy(size=size)
        else:
            if self.rsi < 70 and self.self.sma14 < self.self.sma50:
                # sell order
                self.log(f'SELL CREATED --- Size: {self.position.size}')
                self.sell(size=self.position.size)
                
data = bt.feeds.PandasData(dataname=yf.download('MSFT', '2018-01-01', '2018-12-31'))


cerebro = bt.Cerebro(stdstats = False, cheat_on_open=True)

cerebro.addstrategy(RSI_SMA_Strategy)
cerebro.adddata(data)
cerebro.broker.setcash(10000.0)
cerebro.broker.setcommission(commission=0.002)
cerebro.addobserver(bt.observers.BuySell)
cerebro.addobserver(bt.observers.Value)
cerebro.addanalyzer(bt.analyzers.Returns, _name='returns')
cerebro.addanalyzer(bt.analyzers.TimeReturn, _name='time_return')

print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
backtest_result = cerebro.run()
print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())

´´´

1

There are 1 answers

1
jthulhu On

Your issue comes from the self.self.sma14 and self.self.sma50 lines, at the end of the class definition. They should be self.sma14 and self.sma50 instead.