I've got a day trading algorithm that both shorts and longs futures. Only one trade is meant to happen at a time and when self.Portfolio.Invested is true or there are open orders, no new entries should submit. Entries are always stop market and exits are limit orders. It seems that if-testing for open orders is not working in Live Deployment with IBKR because QC is not recognizing any orders as open. In the order log, it appears that the all orders when expanded show every event happening at the same second (see picture). This implies that while orders and order updates are functioning properly, orders are not recognized as open. This was not an issue when back testing. I am using IBKR data if it matters.

There may be something else going on as well, because many orders are returning as “invalid” status, even those that have been filled or get filled after becoming “invalid.” This could be a result of the above, though.

These issues are resulting in a long entry filling, a short entry filling (which in fact acts as a long exit), and vice versa, then the respective exit orders being submitted. This ended up eventually resulting in orders being placed with double the intended quantity (see other picture) for a Sell Market order, leaving me short 1 contract. There aren't any market orders in the code at all… This “soft-locked” the algorithm since if-testing for self.Portfolio.Invested prevented a new “entry” order from submitting, and no “exit” orders could be triggered under OnOrderEvent, the position was held. This is dangerous with futures, and luckily the trade went in my favor and I was periodically checking the live deployment. 

Is this a known bug / intended feature? What is the work around? Code below. Thank you in advance

216315_1671813502.jpgShowing all submissions, updates, and fills being recorded as happening at the time of fill216315_1671813756.jpgShowing multiple orders as “invalid” and with strange limits. Also at bottom shows a Sell Market order for twice the intended quantity
	def Initialize(self):

		# Backtesting / Papertrading parameters if necessary
		#self.SetCash(15000)
		#self.SetStartDate(2022, 11, 15)
		#self.SetEndDate(2022, 11, 15)
		
		# Create futures contract symbol for ES using expiration date {UPDATE as necessary}
		# Request contract data with tick resolution
		self.esContract = Symbol.CreateFuture(Futures.Indices.MicroSP500EMini, Market.CME, datetime(2023,3,17))
		self.es = self.AddFutureContract(self.esContract, Resolution.Tick)
		# Futures.Indices.MicroSP500EMini // Futures.Indices.SP500EMini

		# Set fees to zero for backtesting purposes
		#self.Securities[self.es.Symbol].SetFeeModel(ConstantFeeModel(0.25))

		# Variables to record W/L ratio & highest/lowest intraday P/L
		self.tallyWin = 0
		self.tallyLoss = 0
		self.tallyEven = 0
		self.tallyS = 0
		self.tallyL = 0
		self.shortWin = 0
		self.longWin = 0
		# Variables for intraday high/low P/L
		self.lowBal = self.Portfolio.Cash
		self.highBal = self.Portfolio.Cash
		self.begBal = self.Portfolio.Cash
		self.endBal = self.Portfolio.Cash
		self.lowTime = 0
		self.highTime = 0
		self.startTime = 0
		self.maxDrawD = 0
		self.dDTime = 0

		self.drawD = 0
		self.haltNum = 1
		self.dDHalt = False

		# Variables for both short and long entry and exit tickets, trade cooldowns, prices for trailing stops and cancellations, and contracts per trade
		self.sEnTicket = None
		self.lEnTicket = None
		self.sExTick = None
		self.lExTick = None
		self.liquidateTicket = None

		self.exitFillTime = datetime.min
		self.cancelTime = datetime.min

		self.trgPrice = 0
		self.highestPrice = 0
		self.lowestPrice = 25000
        
		# Quantity {UPDATE manually}
		self.qty = 1

		# Variables for price levels {Must be > 3 pts away from any other}
		# ! Intended to be updated daily, ensure correct futures contract prices

		# Daily Support and Resistance price levels
		self.resi6 = 0
		self.resi5 = 3901
		self.resi4 = 3892
		self.resi3 = 3880
		self.resi2 = 3869
		self.resi1 = 3856

		self.supp1 = 3838
		self.supp2 = 3826
		self.supp3 = 3807
		self.supp4 = 3784
		self.supp5 = 3773
		self.supp6 = 0

		# Dynamic price levels {e.g. previous day low, overnight high, etc.}
		self.dyna1 = 3788
		self.dyna2 = 3875
		self.dyna3 = 3830
		self.dyna4 = 0
		self.dyna5 = 0

		# Macroenvironment price levels {These weren't used in back tests}
		self.macr1 = 0
		self.macr2 = 0
		self.macr3 = 0

		# Multiples of one-hundred 
		self.hund1 = 4000
		self.hund2 = 3700
		self.hund3 = 3800

		# Miscellaneous price levels
		self.misc1 = 0
		self.misc2 = 0
		self.misc3 = 0

		# Variable for entry trail stop
		self.trailEntry = 3

		# Variable for order cancel based on PA
		self.entryCancel = 4

		# Variables for cooldowns {in seconds}
		self.exitCool = 30
		self.cancelCool = 15

		# no entries occur outside of RTH
		
		self.stopPreM = self.Time.replace(hour=9,minute=32, second=59)
		self.stopAftM = self.Time.replace(hour=15,minute=55, second=59)

	def OnData(self, slice):

		# Plot W/L and high/low intraday P/L at EOD & update ending balance
		if self.Time == self.Time.replace(hour=15, minute=59, second=59):
			self.endBal = self.Portfolio.Cash
			if self.endBal == self.Portfolio.Cash:
				self.Plot("W/L", "Wins", self.tallyWin)
				self.Plot("W/L", "Losses", self.tallyLoss)
				#self.Plot("W/L", "Draws", self.tallyEven)
				self.Plot("P/L", "Highest", self.highBal - self.begBal)
				self.Plot("P/L", "Lowest", self.lowBal - self.begBal)
				self.Plot("P/L", "Ending", self.endBal - self.begBal)
				self.Plot("Intraday Times", "High Time", int(round(self.highTime / 60)))
				self.Plot("Intraday Times", "Low Time", int(round(self.lowTime / 60)))
				self.Plot("Intraday Times", "Max DD Time", int(round(self.dDTime / 60)))
				self.Plot("Misc. Stats", "Max Drawdown", self.maxDrawD)
				#self.Plot("Misc. Stats", "W/L", self.tallyWin * 100 / self.tallyTtl)
				self.Plot("Misc. Stats", "Long w/l", self.longWin * 100 / self.tallyL)
				self.Plot("Misc. Stats", "Short w/l", self.shortWin * 100 / self.tallyS)
		# Reset balances daily
		if self.Time == self.Time.replace(hour=9, minute=30, second=0):
			self.highBal = self.Portfolio.Cash
			self.lowBal = self.Portfolio.Cash
			self.begBal = self.Portfolio.Cash
			self.startTime = int(round(self.Time.timestamp()))
			self.lowTime = 0
			self.highTime = 0
			self.maxDrawD = 0
			self.dDTime = 0
			self.drawD = 0
			self.haltNum = 1
			self.dDHalt = False
		    # no entries occur outside of RTH
			self.stopPreM = self.Time.replace(hour=9,minute=32, second=59)
			self.stopAftM = self.Time.replace(hour=15,minute=55, second=59)

		# Variable for ES contract price
		price = self.Securities[self.es.Symbol].Price
		
		# Cooldowns
		if (self.Time - self.exitFillTime).seconds <= self.exitCool or (self.Time - self.cancelTime).seconds <= self.cancelCool:
			return

		# Submit entry order if there are no positions or open orders and time conditions are met
		if not self.Portfolio.Invested and not self.Transactions.GetOpenOrders(self.es.Symbol) and self.stopPreM < self.Time < self.stopAftM and self.dDHalt != True:
			
			# Short entries
			if self.resi6 + 1.5 >= price > self.resi6 or self.resi5 + 1.5 >= price > self.resi5 or self.resi4 + 1.5 >= price > self.resi4 or self.resi3 + 1.5 >= price > self.resi3 or self.resi2 + 1.5 >= price > self.resi2 or self.resi1 + 1.5 >= price > self.resi1 or self.supp6 + 1.5 >= price > self.supp6 or self.supp5 + 1.5 >= price > self.supp5 or self.supp4 + 1.5 >= price > self.supp4 or self.supp3 + 1.5 >= price > self.supp3 or self.supp2 + 1.5 >= price > self.supp2 or self.supp1 + 1.5 >= price > self.supp1 or self.dyna1 + 1.5 >= price > self.dyna1 or self.dyna2 + 1.5 >= price > self.dyna2 or self.dyna3 + 1.5 >= price > self.dyna3 or self.dyna4 + 1.5 >= price > self.dyna4 or self.dyna5 + 1.5 >= price > self.dyna5 or self.macr1 + 1.5 >= price > self.macr1 or self.macr2 + 1.5 >= price > self.macr2 or self.macr3 + 1.5 >= price > self.macr3 or self.hund1 + 1.5 >= price > self.hund1 or self.hund2 + 1.5 >= price > self.hund2 or self.hund3 + 1.5 >= price > self.hund3 or self.misc1 + 1.5 >= price > self.misc1 or self.misc2 + 1.5 >= price > self.misc2 or self.misc3 + 1.5 >= price > self.misc3:
				if not self.Transactions.GetOpenOrders(self.es.Symbol):
					self.sEnTicket = self.StopMarketOrder(self.es.Symbol, -self.qty, price-5)
					self.trgPrice = price

			# Long entries
			if self.resi6 - 1.5 <= price < self.resi6 or self.resi5 - 1.5 <= price < self.resi5 or self.resi4 - 1.5 <= price < self.resi4 or self.resi3 - 1.5 <= price < self.resi3 or self.resi2 - 1.5 <= price < self.resi2 or self.resi1 - 1.5 <= price < self.resi1 or self.supp6 - 1.5 <= price < self.supp6 or self.supp5 - 1.5 <= price < self.supp5 or self.supp4 - 1.5 <= price < self.supp4 or self.supp3 - 1.5 <= price < self.supp3 or self.supp2 - 1.5 <= price < self.supp2 or self.supp1 - 1.5 <= price < self.supp1 or self.dyna1 - 1.5 <= price < self.dyna1 or self.dyna2 - 1.5 <= price < self.dyna2 or self.dyna3 - 1.5 <= price < self.dyna3 or self.dyna4 - 1.5 <= price < self.dyna4 or self.dyna5 - 1.5 <= price < self.dyna5 or self.macr1 - 1.5 <= price < self.macr1 or self.macr2 - 1.5 <= price < self.macr2 or self.macr3 - 1.5 <= price < self.macr3 or self.hund1 - 1.5 <= price < self.hund1 or self.hund2 - 1.5 <= price < self.hund2 or self.hund3 - 1.5 <= price < self.hund3 or self.misc1 - 1.5 <= price < self.misc1 or self.misc2 - 1.5 <= price < self.misc2 or self.misc3 - 1.5 <= price < self.misc3:
				if not self.Transactions.GetOpenOrders(self.es.Symbol):
					self.lEnTicket = self.StopMarketOrder(self.es.Symbol, self.qty, price+5)
					self.trgPrice = price
	
		# Trailing stop and possible cancellation if a short entry order is open 
		if self.sEnTicket is not None and self.sEnTicket.Status != OrderStatus.Filled:
        	# Trailing stop
			if price < self.lowestPrice:
				self.lowestPrice = price
			if self.lowestPrice + self.trailEntry <= price:
				updateFields = UpdateOrderFields()
				updateFields.StopPrice = price+5
				self.sEnTicket.Update(updateFields)
            # Cancel order and save time if price is not rejecting the level
			if price <= self.trgPrice - self.entryCancel:
				self.sEnTicket.Cancel()
				self.cancelTime = self.Time
			# Cancel order if near end of RTH
			if self.Time > self.stopAftM:
				self.sEnTicket.Cancel()
			# Reset long entry ticket, lowest price, and trigger price variables if order is canceled
			if self.sEnTicket.Status == OrderStatus.Canceled:
				self.sEnTicket = None
				self.lowestPrice = 25000
				self.trgPrice = 0

		# Trailing stop and possible cancellation if a long entry order is open 
		if self.lEnTicket is not None and self.lEnTicket.Status != OrderStatus.Filled:
			# Trailing stop
			if price > self.highestPrice:
				self.highestPrice = price
			if self.highestPrice - self.trailEntry >= price:
				updateFields = UpdateOrderFields()
				updateFields.StopPrice = price-5
				self.lEnTicket.Update(updateFields)
			# Cancel order and save time if price is not rejecting the level
			if price >= self.trgPrice + self.entryCancel:
				self.lEnTicket.Cancel()
				self.cancelTime = self.Time
			# Cancel order if near end of RTH
			if self.Time > self.stopAftM:
				self.lEnTicket.Cancel()
			# Reset long entry ticket, lowest price, and trigger price variables if order is canceled
			if self.lEnTicket.Status == OrderStatus.Canceled:
				self.lEnTicket = None
				self.highestPrice = 25000
				self.trgPrice = 0

		# Trailing stop and possible cancellation and liquidation if a short closing order is open
		if self.sExTick is not None and self.Portfolio.Invested:
			# Trailing stop which updates as the position moves favorably
			if self.sEnTicket.AverageFillPrice + 2.5 <= price:
				updateFields = UpdateOrderFields()
				updateFields.LimitPrice = price + 2
				self.sExTick.Update(updateFields)
			
		# Trailing stop and possible cancellation and liquidation if a long closing order is open
		if self.lExTick is not None and self.Portfolio.Invested:
			# Trailing stop which updates as the position moves favorably
			if self.lEnTicket.AverageFillPrice - 2.5 >= price:
				updateFields = UpdateOrderFields()
				updateFields.LimitPrice = price - 2
				self.lExTick.Update(updateFields)

	def OnOrderEvent(self, orderEvent):
		if orderEvent.Status != OrderStatus.Filled:
			return

		# Submit short exit order when long entry is filled
		if self.sEnTicket is not None and self.Portfolio.Invested:
			self.sExTick = self.LimitOrder(self.es.Symbol, self.qty, self.sEnTicket.AverageFillPrice - 0.5)
			# Reset price variables
			self.trgPrice = 0
			self.highestPrice = 0
			self.lowestPrice = 25000

		# Submit long exit order when short entry is filled
		if self.lEnTicket is not None and self.Portfolio.Invested:
			self.lExTick = self.LimitOrder(self.es.Symbol, -self.qty, self.lEnTicket.AverageFillPrice + 0.5)
			# Reset price variables
			self.trgPrice = 0
			self.highestPrice = 0
			self.lowestPrice = 25000

		# Save time and reset price and ticket variables when a short exit order fills & record W/L & high/low intraday P/L
		if self.sExTick is not None and self.sExTick.OrderId == orderEvent.OrderId:

			self.tallyS += 1
			if self.sEnTicket.AverageFillPrice > self.sExTick.AverageFillPrice:
				self.tallyWin += 1
				self.shortWin += 1
			if self.sEnTicket.AverageFillPrice < self.sExTick.AverageFillPrice:
				self.tallyLoss += 1
			if self.sEnTicket.AverageFillPrice == self.sExTick.AverageFillPrice:
				self.tallyEven += 1

			if self.Portfolio.Cash > self.highBal:
				self.drawD = 0
				self.highBal = self.Portfolio.Cash
				self.highTime = int(round(self.Time.timestamp())) - self.startTime
			if self.Portfolio.Cash < self.lowBal:
				self.lowBal = self.Portfolio.Cash
				self.lowTime = int(round(self.Time.timestamp())) - self.startTime
			
			if self.Portfolio.Cash < self.highBal:
				if self.highBal - self.Portfolio.Cash > self.maxDrawD:
					self.maxDrawD = self.highBal - self.Portfolio.Cash
					self.dDTime = int(round(self.Time.timestamp())) - self.startTime
				if self.highBal - self.Portfolio.Cash > self.drawD:
					self.drawD = self.highBal - self.Portfolio.Cash

			self.exitFillTime = self.Time
			self.sEnTicket = None
			self.sExTick = None
			self.highestPrice = 0
			self.lowestPrice = 25000

			# UPDATE THESE VALUES FOR MICRO VS TRAD MINI [/*10]

			#if self.begBal+1450*self.qty <= self.highBal < self.begBal+1700*self.qty and self.haltNum != 3:
				#self.haltNum = 2
			if self.begBal+170*self.qty <= self.highBal:
				self.haltNum = 3

			if self.drawD >= 75*self.qty + 2.8*self.qty*3 and self.haltNum == 1:
				self.dDHalt = True
			#if self.drawD >= 500*self.qty + 2.8*self.qty*2 and self.haltNum == 2:
				#self.dDHalt = True
			if self.drawD >= 25*self.qty + 2.8*self.qty and self.haltNum == 3:
				self.dDHalt = True

		# Save time and reset price and ticket variables when a long exit order fills and record W/L & high/low intraday P/L
		if self.lExTick is not None and self.lExTick.OrderId == orderEvent.OrderId:

			self.tallyL += 1
			if self.lEnTicket.AverageFillPrice < self.lExTick.AverageFillPrice:
				self.tallyWin += 1
				self.longWin += 1
			if self.lEnTicket.AverageFillPrice > self.lExTick.AverageFillPrice:
				self.tallyLoss += 1
			if self.lEnTicket.AverageFillPrice == self.lExTick.AverageFillPrice:
				self.tallyEven += 1

			if self.Portfolio.Cash > self.highBal:
				self.drawD = 0
				self.highBal = self.Portfolio.Cash
				self.highTime = int(round(self.Time.timestamp())) - self.startTime
			if self.Portfolio.Cash < self.lowBal:
				self.lowBal = self.Portfolio.Cash
				self.lowTime = int(round(self.Time.timestamp())) - self.startTime
			
			if self.Portfolio.Cash < self.highBal:
				if self.highBal - self.Portfolio.Cash > self.maxDrawD:
					self.maxDrawD = self.highBal - self.Portfolio.Cash
					self.dDTime = int(round(self.Time.timestamp())) - self.startTime
				if self.highBal - self.Portfolio.Cash > self.drawD:
					self.drawD = self.highBal - self.Portfolio.Cash

			self.exitFillTime = self.Time
			self.lEnTicket = None
			self.lExTick = None
			self.highestPrice = 0
			self.lowestPrice = 25000

			# UPDATE THESE VALUES FOR MICRO VS TRAD MINI [/*10]

			#if self.begBal+1450*self.qty <= self.highBal < self.begBal+1700*self.qty and self.haltNum != 3:
				#self.haltNum = 2
			if self.begBal+170*self.qty <= self.highBal:
				self.haltNum = 3

			if self.drawD >= 75*self.qty + 2.8*self.qty*3 and self.haltNum == 1:
				self.dDHalt = True
			#if self.drawD >= 500*self.qty + 2.8*self.qty*2 and self.haltNum == 2:
				#self.dDHalt = True
			if self.drawD >= 25*self.qty + 2.8*self.qty and self.haltNum == 3:
				self.dDHalt = True

Author