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

Market buy orders are Submitted, but not Accepted or Executed



  • I am currently backtesting a strategy where backtrader acts normally up until about a third of the way through the entire data set. From that point on, backtrader seems to only be capable of creating a buy order and submitting it, but not accepting or executing the order. I have three attachments associated with this post. The first is the strategy, then the second is the image where we can see that backtrader is incapable of accepting/executing an order, and finally the log output. Does anyone know as to why my orders are not being accepted/executed? Thanks!

    Please note, not all objects are defined in the provided script.

    Code:

    class EmaCross(bt.Strategy):
        params = {('order_percentage', .95)}
        plotlines = dict(
            ema_s=dict(_name = 'ema_s', ls='--', color='yellow'),  # use same color as prev line (dcm)
            ema_l=dict(_name = 'ema_l', ls='--', color='blue')) # use same color as prev line (dch)
    
        def log(self, txt, dt=None):
            ''' Logging function fot this strategy'''
            dt = dt or self.datas[0].datetime.datetime(0)
            print('%s, %s' % (dt.isoformat(), txt))
    
        def __init__(self):
            self.dataopen = self.datas[0].open
            self.dataclose = self.datas[0].close
            self.datahigh = self.datas[0].high
            self.datalow = self.datas[0].low
            
            # Bring in moving averages 
            self.myind = color_ind()
    
            # Define average true range 
            self.atr = bt.indicators.ATR(self.datas[0], period =14)
            
            # Define self order
            self.order = None
            self.trail_stop = None
            self.cross_down = None
        
        def notify_order(self, order):
            #Cancel stop if cross initiated
            if (self.cross_down and self.trail_stop):
                self.cancel(self.trail_stop)
    
    
            # Check the order status. 
            # If it is submitted/accepted, leave the fucntion 
            if order.status in [order.Submitted, order.Accepted]:
                if order.isbuy():
                    self.log(f"Buy Submitted at {order}")
                return
    
            if order.status in [order.Completed]:
                if order.isbuy():
                    # Keep track of executred price and stop loss 
                    self.log(f"Buy Executed at {order.executed.price}")
                if order.issell():
                    # Keep track of sell price 
                    self.log(f"Sell Executed at {order.executed.price} and order {order}")
                    self.cancel(self.cross_down)
                    self.cancel(self.trail_stop)
                    print(f'position: \n {self.position} and order: \n {order}')
    
            if order.status == order.Canceled:
                #self.log(f'Order canceled at {self.dataclose[0]} and order is \n{order}')
                return
    
            # Sentinel to None: new orders allowed
            self.order = None
            self.trail_stop = None
            self.cross_down = None
    
        def next(self):
            if self.order:
                return
    
            # if there is no current postion 
            if self.position.size == 0:
                self.cancel(self.cross_down)
                if ( self.myind.ema_s[0] > self.myind.ema_l[0] and  
                self.myind.ema_s[-1] < self.myind.ema_l[-1] ):                     
                    self.size = 1
                    self.log('BUY CREATE, %.2f' % self.dataclose[0])
                    self.order = self.buy(size = self.size)
                 
    
            elif self.position.size > 0:          
                if (self.trail_stop is None and self.cross_down is None and sell_type in ['atr_sell','atr_cross_sell']):
                    # cancel any prior cross_down
                    self.cancel(self.cross_down)
                    # sell on trailing stop 
                    self.trail_stop = self.close(exectype=bt.Order.StopTrail, 
                                                trailamount = atr_stop * self.atr[0], 
                                                size = self.position.size, ref = '999')                
                
                elif (self.myind.ema_s[0] < self.myind.ema_l[0] 
                    and (self.myind.ema_s[-1] > self.myind.ema_l[-1] 
                    or self.myind.ema_s[-2] > self.myind.ema_l[-2])
                    and (self.cross_down is None) and sell_type  in ['cross_sell','atr_cross_sell']): 
                                   
                    # cancel trailing stop
                    self.cancel(self.trail_stop)
                    # sell on the cros down
                    self.cross_down = self.close()
    
    
    if f in ['30min','15min','hour','4hour']:
        if f == '30min':
            compression = 30
        elif f == '15min':
            compression = 15
        elif f == 'hour':
            compression = 60
        else:
            compression = 240
    
        data0 = pd.read_csv(f'data/{c}/{f}/{d}.csv' ) #index_col=[0], parse_dates=[0]
        data0['time'] = data0.reset_index().time.apply(lambda x: datetime.strptime(x,'%m/%d/%Y %H:%M'))
        
        data0.set_index('time',inplace = True)
    
    
        data = bt.feeds.PandasData(dataname = data0, timeframe = bt.TimeFrame.Minutes, compression = compression) 
    else: 
        data0 = pd.read_csv(f'data/{c}/{f}/{d}.csv',index_col=[0], parse_dates=[0] ) 
        start = pd.to_datetime(data0.index.max()) - pd.offsets.DateOffset(months=3) - timedelta(days = 10)
        data0 = data0[data0.index>=start]
        data = bt.feeds.PandasData(dataname = data0, timeframe = bt.TimeFrame.Days)
    
    
    b = Bokeh(style='bar', plot_mode='multi', scheme=Tradimo(), bar_up = 'green')
    cerebro = bt.Cerebro()
    if contract == 'RTY':
        cerebro.broker.setcommission(commission = .85, mult = 50, stocklike=False, margin = 10000)
    elif contract == 'ES':
        cerebro.broker.setcommission(commission = .85, mult = 12.5, stocklike=False, margin = 15000)
    elif contract == 'NQ':
        cerebro.broker.setcommission(commission = .85, mult = 20, stocklike=False, margin = 22000)
    elif contract == 'NG':
        cerebro.broker.setcommission(commission = .85, mult = 10, stocklike=False, margin = 10000)
    elif contract == 'CL':
        cerebro.broker.setcommission(commission = .85, mult = 10, stocklike=False, margin = 10000)
    
    cerebro.addstrategy(EmaCross)
    cerebro.broker.setcash(50000.0)
    cerebro.adddata(data)
    cerebro.addwriter(bt.WriterFile, csv = True, out='data.csv')
    #cerebro.broker.set_coc(True)
    cerebro.run()
    cerebro.plot(b, iplot = False)
    

    Image:

    image (10).png

    Output

    2008-12-15T05:00:00, Buy Executed at 1273.75
    2008-12-22T15:15:00, Sell Executed at 1224.11104544575 and order Ref: 20320
    OrdType: 1
    OrdType: Sell
    Status: 4
    Status: Completed
    Size: -1
    Price: None
    Price Limit: None
    TrailAmount: 69.13895455424985
    TrailPercent: None
    ExecType: 5
    ExecType: StopTrail
    CommInfo: <backtrader.comminfo.CommInfoBase object at 0x0000024D2EFEA748>
    End of Session: 733391.9999999999
    Info: AutoOrderedDict([('ref', '999')])
    Broker: None
    Alive: False
    2008-12-30T11:30:00, BUY CREATE, 1252.50
    2008-12-30T15:15:00, Buy Submitted at Ref: 20321
    OrdType: 0
    OrdType: Buy
    Status: 1
    Status: Submitted
    Size: 1
    Price: None
    Price Limit: None
    TrailAmount: None
    TrailPercent: None
    ExecType: 0
    ExecType: Market
    CommInfo: None
    End of Session: 733406.9999999999
    Info: AutoOrderedDict()
    Broker: None
    Alive: True
    2008-12-30T15:15:00, BUY CREATE, 1259.75
    2008-12-30T19:30:00, Buy Submitted at Ref: 20322
    OrdType: 0
    OrdType: Buy
    Status: 1
    Status: Submitted
    Size: 1
    Price: None
    Price Limit: None
    TrailAmount: None
    TrailPercent: None
    ExecType: 0
    ExecType: Market
    CommInfo: None
    End of Session: 733406.9999999999
    Info: AutoOrderedDict()
    Broker: None
    Alive: True  
    


  • Stupid question, but are you sure it is not canceled by your code?
    I guess the way would be to print out your cancel conditions and see the available cash?



  • Hello Jonny,

    I don't think that is the case as the only point a buy market order can be cancelled is within the sentinel. The code within sentinel shouldn't execute in the current script because backtrader should be exiting the notify_order function with the code below. Please let me know if my reasoning is flawed here.

    if order.status in [order.Submitted, order.Accepted]:
        if order.isbuy():
            self.log(f"Buy Submitted at {order}")
        return
    

Log in to reply
 

});