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:
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