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

Oanda Live Trading: trade never got closed in backtrader even if the tp/cl price is reached



  • I am trying to implement my strategy with backtrader to do live trading with Oanda and I am testing on practice account now. I found that both my main order and take profit/cut loss order of my bracket order(manual bracket order) get traded on Oanda after python sends orders to oanda, but the take profit and cut loss part will never get done in my python(backtrader) even if the level is reached. As a result, the position is never closed in my python program, and my algorithm to generate trading signals will never be executed again, since my strategy will hold only 1 trading position at once. Anyone know what is the problem here? or how to solve this?

    And, apart from that, the algorithm often executes several trades in a row (maybe cos tick data come in too fast? I guess). I am not sure why is that happening. fixed

    Can anyone help? a test version of my code is showing down below.

    class TestStrategy(bt.Strategy):
        def __init__(self):
            # To keep track of pending orders
            self.orders = []
            # others
            self.datastatus = 0
    
        def logdata(self):
            txt = []
            txt.append('{}'.format(len(self)))
    
            txt.append('{}'.format(
                self.data.datetime.datetime(0).isoformat())
            )
            txt.append('{:.4f}'.format(self.data.open[0]))
            txt.append('{:.4f}'.format(self.data.high[0]))
            txt.append('{:.4f}'.format(self.data.low[0]))
            txt.append('{:.4f}'.format(self.data.close[0]))
            txt.append('{:.4f}'.format(self.data.volume[0]))
            print(','.join(txt))
    
        def notify_data(self, data, status, *args, **kwargs):
            print('*' * 5, 'DATA NOTIF:', data._getstatusname(status), *args)
            if status == data.LIVE:
                self.datastatus = 1
    
    
        def notify_order(self, order):
            date = self.data.datetime.datetime().date()
    
            if order.status == order.Accepted:
                print('-' * 32, ' NOTIFY ORDER ', '-' * 32)
                print('{} Order Accepted'.format(order.info['name']))
                print('{}, Status {}: Ref: {}, Size: {}, Price: {}'.format(
                    date,
                    order.status,
                    order.ref,
                    order.size,
                    'NA' if not order.price else round(order.price, 5)
                ))
    
    
    
            elif order.status == order.Completed:
                print('-' * 32, ' NOTIFY ORDER ', '-' * 32)
                print('{} Order Completed'.format(order.info['name']))
                print('{}, Status {}: Ref: {}, Size: {}, Price: {}'.format(
                    date,
                    order.status,
                    order.ref,
                    order.size,
                    'NA' if not order.price else round(order.price, 5)
                ))
                print('Created: {} Price: {} Size: {}'.format(bt.num2date(order.created.dt), order.created.price,
                                                              order.created.size))
                print('-' * 80)
    
    
    
            elif order.status == order.Canceled:
                print('-' * 32, ' NOTIFY ORDER ', '-' * 32)
                print('{} Order Canceled'.format(order.info['name']))
                print('{}, Status {}: Ref: {}, Size: {}, Price: {}'.format(
                    date,
                    order.status,
                    order.ref,
                    order.size,
                    'NA' if not order.price else round(order.price, 5)
                ))
    
    
    
            elif order.status == order.Rejected:
                print('-' * 32, ' NOTIFY ORDER ', '-' * 32)
                print('WARNING! {} Order Rejected'.format(order.info['name']))
                print('{}, Status {}: Ref: {}, Size: {}, Price: {}'.format(
                    date,
                    order.status,
                    order.ref,
                    order.size,
                    'NA' if not order.price else round(order.price, 5)
                ))
                print('-' * 80)
    
    
    
            #print(self.orders)
            if not order.alive():  # not alive - nullify
                dorders = self.orders
                idx = dorders.index(order)
                dorders[idx] = None
                if all(x == None for x in dorders):
                    dorders[:] = []  # empty list - New orders allowed
    
        def notify_trade(self, trade):
            date = self.data.datetime.datetime()
            if trade.isclosed:
                print('-' * 32, ' NOTIFY TRADE ', '-' * 32)
                print('{}, Close Price: {}, Profit, Gross {}, Net {}'.format(
                    date,
                    trade.price,
                    round(trade.pnl, 2),
                    round(trade.pnlcomm, 2)))
                print('-' * 80)
    
    
        def next(self):
            if(len(self.data.close)<30 or data.LIVE==False):
                return
            # Simply log the closing price of the series from the reference
            self.logdata()
    
            if self.orders != [] and self.position.size != 0 :
                return
    
            print(self.orders)
    
            # Check if we are in the market
            if not self.position and self.datastatus:
                o1 = self.buy(exectype=bt.Order.Limit,
                              price=self.data.close[0],
                              transmit=False)
    
                o2 = self.sell(exectype=bt.Order.Stop,
                               price=self.data.close[0] - 0.01,
                               parent=o1,
                               transmit=False)
    
                o3 = self.sell(exectype=bt.Order.Limit,
                               price=self.data.close[0] + 0.03,
                               parent=o1,
                               transmit=True)
                self.orders = [o1, o2, o3]
    
    
        def start(self):
            if self.data0.contractdetails is not None:
                print('-- Contract Details:')
                print(self.data0.contractdetails)
            print('Started')
            acc_cash = cerebro.broker.getcash()
            acc_val = cerebro.broker.getvalue()
            print('Account Cash = {}'.format(acc_cash))
            print('Account Value = {}'.format(acc_val))
    
    
    if __name__ == '__main__':
        cerebro = bt.Cerebro()
        oandastore = bt.stores.OandaStore(token=apikey, account=acc, practice=True)
        cerebro.broker = oandastore.getbroker()
    
        data = oandastore.getdata(dataname="USD_JPY", timeframe=bt.TimeFrame.Ticks,
                                  compression=1, backfill_start=True, backfill=True,
                                  bidask = True, reconnect = True, reconntimeout = 10)
    
        cerebro.replaydata(data, timeframe=bt.TimeFrame.Seconds, compression=5)
    
        cerebro.addsizer(bt.sizers.SizerFix, stake=500)
        cerebro.addstrategy(TestStrategy)
        cerebro.run()

  • administrators

    @jimmyliu said in Oanda Live Trading: trade never got closed in backtrader even if the tp/cl price is reached:

    but the take profit and cut loss part will never get done in my python(backtrader) even if the level is reached

    This is fully unclear. If you are trading with Oanda and you send orders, why are you expecting them to be matched by your python code in backtrader.

    There isn't even a log of the prices which are being reached, your order being executed ...



  • @backtrader Thanks for replying, and I am sorry this might be a noob question and also I didn't make that clear enough.

    I was just trying to say that if the take profit/cut loss leg is not executed in my python, I will always hold a position in my python, and my algo will never send any new orders to Oanda ever after.

    And what do you mean by "there isn't a log of prices which are being reached?" could you please clarify a little bit?

    thanks a lot and happy new year.
    Jimmy