Simple strategy using IB live data
-
Hi
I have done backtesting strategies using R quantstrat and now looking to use Python for execution.
I am new to backtrader. After looking at some examples I was able to use getdata from IB and separately I was able to backtest a simple strategy using a different CSV data. Now I would like to combine those 2 things together for my first milestone using backtrader.However I am getting error:
AttributeError: 'IBBroker' object has no attribute 'setcash'Not sure what is wrong and I would really appreciate your help!
The code is here:
from __future__ import (absolute_import, division, print_function, unicode_literals) import datetime # For datetime objects import backtrader as bt class TestStrategy(bt.Strategy): params = ( ('maperiod', 15), ) def log(self, txt, dt=None): ''' Logging function fot this strategy''' # dt = dt or self.datas[0].datetime.date(0) # print('%s, %s' % (dt.isoformat(), txt)) txt = [] txt.append("{}".format(self.data._name)) txt.append("{}".format(len(self))) txt.append('{}'.format( self.data.datetime.datetime(0).isoformat()) ) txt.append("{:.2f}".format(self.data.open[0])) txt.append("{:.2f}".format(self.data.high[0])) txt.append("{:.2f}".format(self.data.low[0])) txt.append("{:.2f}".format(self.data.close[0])) txt.append("{:.2f}".format(self.data.volume[0])) print(", ".join(txt)) data_live = False def notify_data(self, data, status, *args, **kwargs): print('*' * 5, 'DATA NOTIF:', data._getstatusname(status), *args) if status == data.LIVE: self.data_live = True def __init__(self): # Keep a reference to the "close" line in the data[0] dataseries self.dataclose = self.datas[0].close # To keep track of pending orders and buy price/commission self.order = None self.buyprice = None self.buycomm = None # Add a MovingAverageSimple indicator self.sma = bt.indicators.SimpleMovingAverage( self.datas[0], period=self.params.maperiod) def notify_order(self, order): if order.status in [order.Submitted, order.Accepted]: # Buy/Sell order submitted/accepted to/by broker - 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( 'BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' % (order.executed.price, order.executed.value, order.executed.comm)) self.buyprice = order.executed.price self.buycomm = order.executed.comm else: # Sell self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' % (order.executed.price, order.executed.value, order.executed.comm)) self.bar_executed = len(self) elif order.status in [order.Canceled, order.Margin, order.Rejected]: self.log('Order Canceled/Margin/Rejected') # Write down: no pending order self.order = None def notify_trade(self, trade): if not trade.isclosed: return self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' % (trade.pnl, trade.pnlcomm)) def next(self): # Simply log the closing price of the series from the reference self.log('Close, %.2f' % self.dataclose[0]) # Check if an order is pending ... if yes, we cannot send a 2nd one if self.order: return # Check if we are in the market if not self.position: # Not yet ... we MIGHT BUY if ... if self.sma[0] < 2700: # BUY, BUY, BUY!!! (with all possible default parameters) self.log('BUY CREATE, %.2f' % self.dataclose[0]) # Keep track of the created order to avoid a 2nd order self.order = self.buy() else: if self.sma[0] > 2900: # SELL, SELL, SELL!!! (with all possible default parameters) self.log('SELL CREATE, %.2f' % self.dataclose[0]) # Keep track of the created order to avoid a 2nd order self.order = self.sell() if __name__ == '__main__': # Create a cerebro entity cerebro = bt.Cerebro() store = bt.stores.IBStore(host="127.0.0.1", port=7496, clientId=1) cerebro.broker = store.getbroker() stockkwargs = dict( timeframe=bt.TimeFrame.Minutes, rtbar=False, # use RealTime 5 seconds bars historical=True, # only historical download qcheck=0.5, # timeout in seconds (float) to check for events fromdate=datetime.datetime(2020, 4, 20), # get data from.. # todate=datetime.datetime(2020, 4, 21), # get data from.. latethrough=False, # let late samples through tradename=None # use a different asset as order target ) data = store.getdata(dataname='ES-202006-GLOBEX', **stockkwargs) cerebro.resampledata(data, timeframe=bt.TimeFrame.Minutes, compression=60) # Add a strategy cerebro.addstrategy(TestStrategy) # Add the Data Feed to Cerebro cerebro.adddata(data) # Set our desired cash start cerebro.broker.setcash(1000.0) # Add a FixedSize sizer according to the stake cerebro.addsizer(bt.sizers.FixedSize, stake=10) # Set the commission cerebro.broker.setcommission(commission=0.0) # Print out the starting conditions print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue()) # Run over everything cerebro.run() # Print out the final result print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue()) # Plot the result cerebro.plot()
-
@mlbt2020 said in Simple strategy using IB live data:
cerebro.broker.setcash(1000.0)
Seems you can't just set cash for the real broker account from the
bt
script. Probably you need to move some cash to the real broker account from bank account before trading. -
@mlbt2020 I am new to backtrader as well and is trying to learn from all these IB related posts. I am trying to plot your shared code and it seems like it is able to pull data from IB, but it is not able to execute any trades for backtesting. Have you experienced this same issue?