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

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?

    Figure_0.png


Log in to reply
 

});