Overall Statistics
Total Trades
0
Average Win
0%
Average Loss
0%
Compounding Annual Return
0%
Drawdown
0%
Expectancy
0
Net Profit
0%
Sharpe Ratio
0
Probabilistic Sharpe Ratio
0%
Loss Rate
0%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
0
Beta
0
Annual Standard Deviation
0
Annual Variance
0
Information Ratio
0
Tracking Error
0
Treynor Ratio
0
Total Fees
$0.00
Estimated Strategy Capacity
$0
Lowest Capacity Asset
# region imports
from AlgorithmImports import *
# endregion

class HyperActiveOrangeCat(QCAlgorithm):

	def Initialize(self):

		# Backtesting / Papertrading parameters if necessary
		self.SetCash(100000)
		self.SetStartDate(2022, 11, 11)
		self.SetEndDate(2022, 11, 11)
		
		# Request ES data with tick resolution, filter for expirations in between 5 and 100 days
		self.es = self.AddFuture(Futures.Indices.SP500EMini, Resolution.Tick)
		self.es.SetFilter(5, 100)

		# Variables for both short and long entry and exit tickets, trade cooldowns, prices for trailing stops and cancellations, and contracts per trade
		# !!! EXHIBIT EXTREME CAUTION USING LEVERAGE ; MANUALLY MANAGE CONTRACT QUANTITY
		self.longEntryTicket = None
		self.shortEntryTicket = None
		self.longExitTicket = None
		self.shortExitTicket = None
		self.liquidateTicket = None

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

		self.triggerPrice = 0
		self.highestPrice = 0
		self.lowestPrice = 25000

		self.qty = 1

		# Variables for price levels
		# ! Intended to be updated daily, ensure correct futures contract prices
		# Daily Support and Resistance price levels
		self.resi6 = 0
		self.resi5 = 0
		self.resi4 = 0
		self.resi3 = 0
		self.resi2 = 0
		self.resi1 = 0

		self.supp1 = 0
		self.supp2 = 0
		self.supp3 = 0
		self.supp4 = 0
		self.supp5 = 0
		self.supp6 = 0

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

		# Macroenvironment price levels
		self.macr1 = 0
		self.macr2 = 0
		self.macr3 = 0

		# Multiples of one-hundred 
		self.hund1 = 0
		self.hund2 = 0
		self.hund3 = 0

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

		# Variables to halt entries, cancel open entry orders, and liquidate positions around major news events {intended to be updated daily}
		# Variables to ensure no entries occur outside of RTH
		self.event1Start = self.Time.replace(hour=1, minute=30, second=0)
		self.event1End = self.Time.replace(hour=1, minute=30, second=0)
		
		self.event2Start = self.Time.replace(hour=1, minute=30, second=0)
		self.event2End = self.Time.replace(hour=1, minute=30, second=0)

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

		#  Sort contracts for highest Open Interest and create a variable for the highest OI
		for chain in slice.FutureChains:
			self.popularContracts = [contract for contract in chain.Value if contract.OpenInterest > 1000]
			if len(self.popularContracts) == 0:
				continue
			sortedByOIContracts = sorted(self.popularContracts, key=lambda k : k.OpenInterest, reverse=True)
			self.liquidContract = sortedByOIContracts[0]
		
		# Variable for liquid contract price
		price = self.Securities[self.liquidContract.Symbol].Price
		
		# Enable 30sec cooldown between exit fills and entry submissions, 15sec cooldown between cancellations and entry submissions
		if (self.Time - self.exitFillTime).seconds <= 30 or (self.Time - self.cancelTime).seconds <= 15:
			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.liquidContract.Symbol) and not self.Time < self.stopPreM and not self.Time > self.stopAftM and not self.event1Start < self.Time < self.event1End and not self.event2Start < self.Time < self.event2End:
			
			# Long entry, submit if price comes within 1.5 points above a level
			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:
				self.longEntryTicket = self.StopMarketOrder(self.liquidContract.Symbol, self.qty, price + 1.25)
				# Save price at submission time
				self.triggerPrice = price

			# Short entry, submit if price comes within 1.5 points below a level
			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:
				self.shortEntryTicket = self.StopMarketOrder(self.liquidContract.Symbol, -self.qty, price - 1.25)
				# Save price at submission for cancellation
				self.triggerPrice = price
	
		# Trailing stop and possible cancellation if a long entry order is open 
		if self.longEntryTicket is not None and self.longEntryTicket.Status != OrderStatus.Filled:
			# Trailing stop
			if price < self.lowestPrice:
				self.lowestPrice = price
				updateFields = UpdateOrderFields()
				updateFields.StopPrice = price + 1.25
				self.longEntryTicket.Update(updateFields)
			# Cancel order and save time if price is not rejecting the level
			if price <= self.triggerPrice - 4:
				self.longEntryTicket.Cancel()
				self.cancelTime = self.Time
			# Cancel order and save time if time nears end of RTH or news/data event
			if self.Time > self.stopAftM or self.event1Start < self.Time < self.event1End or self.event2Start < self.Time < self.event2End:
				self.longEntryTicket.Cancel()
				self.cancelTime = self.Time
			# Reset long entry ticket, lowest price, and trigger price variables if order is canceled
			if self.longEntryTicket.Status == OrderStatus.Canceled:
				self.longEntryTicket = None
				self.lowestPrice = 25000
				self.triggerPrice = 0

		# Trailing stop and possible cancellation if a short entry order is open 
		if self.shortEntryTicket is not None and self.shortEntryTicket.Status != OrderStatus.Filled:
			# Trailing stop
			if price > self.highestPrice:
				self.highestPrice = price
				updateFields = UpdateOrderFields()
				updateFields.StopPrice = price - 1.25
				self.shortEntryTicket.Update(updateFields)
			# Cancel order and save time if price is not rejecting the level
			if price >= self.triggerPrice + 4:
				self.shortEntryTicket.Cancel()
				self.cancelTime = self.Time
			# Cancel order and save time if time nears end of RTH or news/data event
			if self.Time > self.stopAftM or self.event1Start < self.Time < self.event1End or self.event2Start < self.Time < self.event2End:
				self.shortEntryTicket.Cancel()
				self.cancelTime = self.Time
			# Reset long entry ticket, lowest price, and trigger price variables if order is canceled
			if self.shortEntryTicket.Status == OrderStatus.Canceled:
				self.shortEntryTicket = None
				self.highestPrice = 25000
				self.triggerPrice = 0

		# Trailing stop and possible cancellation and liquidation if a long closing order is open
		if self.longExitTicket is not None and self.Portfolio.Invested:
			# Trailing stop which updates as the position moves favorably
			if price > self.highestPrice and price < self.longEntryTicket.AverageFillPrice + 1.25:
				self.highestPrice = price
				updateFields = UpdateOrderFields()
				updateFields.StopPrice = price - 1.75
				self.longExitTicket.Update(updateFields)
			if price > self.highestPrice and self.longEntryTicket.AverageFillPrice + 1.25 <= price < self.longEntryTicket.AverageFillPrice + 3.5:
				self.highestPrice = price
				updateFields = UpdateOrderFields()
				updateFields.StopPrice = price - 2.25
				self.longExitTicket.Update(updateFields)
			if price > self.highestPrice and self.longEntryTicket.AverageFillPrice + 3.5 <= price < self.longEntryTicket.AverageFillPrice + 6:
				self.highestPrice = price
				updateFields = UpdateOrderFields()
				updateFields.StopPrice = price - 3
				self.longExitTicket.Update(updateFields)
			if price > self.highestPrice and self.longEntryTicket.AverageFillPrice + 6 <= price < self.longEntryTicket.AverageFillPrice + 8:
				self.highestPrice = price
				updateFields = UpdateOrderFields()
				updateFields.StopPrice = price - 4
				self.longExitTicket.Update(updateFields)
			if price > self.highestPrice and self.longEntryTicket.AverageFillPrice + 8 <= price < self.longEntryTicket.AverageFillPrice + 11.5:
				self.highestPrice = price
				updateFields = UpdateOrderFields()
				updateFields.StopPrice = price - 5.75
				self.longExitTicket.Update(updateFields)
			if price > self.highestPrice and self.longEntryTicket.AverageFillPrice + 11.5 <= price < self.longEntryTicket.AverageFillPrice + 17.5:
				self.highestPrice = price
				updateFields = UpdateOrderFields()
				updateFields.StopPrice = price - 7.75
				self.longExitTicket.Update(updateFields)
			if price > self.highestPrice and self.longEntryTicket.AverageFillPrice + 17.5 <= price < self.longEntryTicket.AverageFillPrice + 23:
				self.highestPrice = price
				updateFields = UpdateOrderFields()
				updateFields.StopPrice = price - 9
				self.longExitTicket.Update(updateFields)
			if price > self.highestPrice and self.longEntryTicket.AverageFillPrice + 23 <= price < self.longEntryTicket.AverageFillPrice + 30:
				self.highestPrice = price
				updateFields = UpdateOrderFields()
				updateFields.StopPrice = price - 11.5
				self.longExitTicket.Update(updateFields)
			if price > self.highestPrice and self.longEntryTicket.AverageFillPrice + 30 <= price < self.longEntryTicket.AverageFillPrice + 40:
				self.highestPrice = price
				updateFields = UpdateOrderFields()
				updateFields.StopPrice = price - 14
				self.longExitTicket.Update(updateFields)
			if price > self.highestPrice and self.longEntryTicket.AverageFillPrice + 40 <= price < self.longEntryTicket.AverageFillPrice + 50:
				self.highestPrice = price
				updateFields = UpdateOrderFields()
				updateFields.StopPrice = price - 20
				self.longExitTicket.Update(updateFields)
			if price > self.highestPrice and self.longEntryTicket.AverageFillPrice + 50 <= price < self.longEntryTicket.AverageFillPrice + 70:
				self.highestPrice = price
				updateFields = UpdateOrderFields()
				updateFields.StopPrice = price - 18
				self.longExitTicket.Update(updateFields)
			if price > self.highestPrice and self.longEntryTicket.AverageFillPrice + 70 <= price < self.longEntryTicket.AverageFillPrice + 80:
				self.highestPrice = price
				updateFields = UpdateOrderFields()
				updateFields.StopPrice = price - 13
				self.longExitTicket.Update(updateFields)
			if price > self.highestPrice and self.longEntryTicket.AverageFillPrice + 80 <= price < self.longEntryTicket.AverageFillPrice + 90:
				self.highestPrice = price
				updateFields = UpdateOrderFields()
				updateFields.StopPrice = price - 8
				self.longExitTicket.Update(updateFields)
			if price > self.highestPrice and self.longEntryTicket.AverageFillPrice + 90 <= price:
				self.highestPrice = price
				updateFields = UpdateOrderFields()
				updateFields.StopPrice = price - 5
				self.longExitTicket.Update(updateFields)
			
			# Liquidate position on news/data event and reset relevant variables
			if self.event1Start < self.Time < self.event1End or self.event2Start < self.Time < self.event2End:
				self.longExitTicket.Cancel()
			if self.longExitTicket.Status == OrderStatus.Canceled:
				self.liquidateTicket = self.MarketOrder(self.liquidContract.Symbol, -self.qty)
				self.longEntryTicket = None
				self.longExitTicket = None
				self.highestPrice = 0

		# Trailing stop and possible cancellation and liquidation if a short closing order is open
		if self.shortExitTicket is not None and self.Portfolio.Invested:
			# Trailing stop which updates as the position moves favorably
			if price < self.lowestPrice and price > self.shortEntryTicket.AverageFillPrice - 1.25:
				self.lowestPrice = price
				updateFields = UpdateOrderFields()
				updateFields.StopPrice = price + 1.75
				self.shortExitTicket.Update(updateFields)
			if price < self.lowestPrice and self.shortEntryTicket.AverageFillPrice - 1.25 >= price > self.shortEntryTicket.AverageFillPrice - 3.5:
				self.lowestPrice = price
				updateFields = UpdateOrderFields()
				updateFields.StopPrice = price + 2.25
				self.shortExitTicket.Update(updateFields)
			if price < self.lowestPrice and self.shortEntryTicket.AverageFillPrice - 3.5 >= price > self.shortEntryTicket.AverageFillPrice - 6:
				self.lowestPrice = price
				updateFields = UpdateOrderFields()
				updateFields.StopPrice = price + 3
				self.shortExitTicket.Update(updateFields)
			if price < self.lowestPrice and self.shortEntryTicket.AverageFillPrice - 6 >= price > self.shortEntryTicket.AverageFillPrice - 8:
				self.lowestPrice = price
				updateFields = UpdateOrderFields()
				updateFields.StopPrice = price + 4
				self.shortExitTicket.Update(updateFields)
			if price < self.lowestPrice and self.shortEntryTicket.AverageFillPrice - 8 >= price > self.shortEntryTicket.AverageFillPrice - 11.5:
				self.lowestPrice = price
				updateFields = UpdateOrderFields()
				updateFields.StopPrice = price + 5.75
				self.shortExitTicket.Update(updateFields)
			if price < self.lowestPrice and self.shortEntryTicket.AverageFillPrice - 11.5 >= price > self.shortEntryTicket.AverageFillPrice - 17.5:
				self.lowestPrice = price
				updateFields = UpdateOrderFields()
				updateFields.StopPrice = price + 7.75
				self.shortExitTicket.Update(updateFields)
			if price < self.lowestPrice and self.shortEntryTicket.AverageFillPrice - 17.5 >= price > self.shortEntryTicket.AverageFillPrice - 23:
				self.lowestPrice = price
				updateFields = UpdateOrderFields()
				updateFields.StopPrice = price + 9
				self.shortExitTicket.Update(updateFields)
			if price < self.lowestPrice and self.shortEntryTicket.AverageFillPrice - 23 >= price > self.shortEntryTicket.AverageFillPrice - 30:
				self.lowestPrice = price
				updateFields = UpdateOrderFields()
				updateFields.StopPrice = price + 11.5
				self.shortExitTicket.Update(updateFields)
			if price < self.lowestPrice and self.shortEntryTicket.AverageFillPrice - 30 >= price > self.shortEntryTicket.AverageFillPrice - 40:
				self.lowestPrice = price
				updateFields = UpdateOrderFields()
				updateFields.StopPrice = price + 14
				self.shortExitTicket.Update(updateFields)
			if price < self.lowestPrice and self.shortEntryTicket.AverageFillPrice - 40 >= price > self.shortEntryTicket.AverageFillPrice - 50:
				self.lowestPrice = price
				updateFields = UpdateOrderFields()
				updateFields.StopPrice = price + 20
				self.shortExitTicket.Update(updateFields)
			if price < self.lowestPrice and self.shortEntryTicket.AverageFillPrice - 50 >= price > self.shortEntryTicket.AverageFillPrice - 70:
				self.lowestPrice = price
				updateFields = UpdateOrderFields()
				updateFields.StopPrice = price + 18
				self.shortExitTicket.Update(updateFields)
			if price < self.lowestPrice and self.shortEntryTicket.AverageFillPrice - 70 >= price > self.shortEntryTicket.AverageFillPrice - 80:
				self.lowestPrice = price
				updateFields = UpdateOrderFields()
				updateFields.StopPrice = price + 13
				self.shortExitTicket.Update(updateFields)
			if price < self.lowestPrice and self.shortEntryTicket.AverageFillPrice - 80 >= price > self.shortEntryTicket.AverageFillPrice - 90:
				self.lowestPrice = price
				updateFields = UpdateOrderFields()
				updateFields.StopPrice = price + 8
				self.shortExitTicket.Update(updateFields)
			if price < self.lowestPrice and self.shortEntryTicket.AverageFillPrice - 90 >= price:
				self.lowestPrice = price
				updateFields = UpdateOrderFields()
				updateFields.StopPrice = price + 5
				self.shortExitTicket.Update(updateFields)
			
			# Liquidate position on news/data event and reset relevant variables
			if self.event1Start < self.Time < self.event1End or self.event2Start < self.Time < self.event2End:
				self.shortExitTicket.Cancel()
			if self.shortExitTicket.Status == OrderStatus.Canceled:
				self.liquidateTicket = self.MarketOrder(self.liquidContract.Symbol, self.qty)
				self.shortEntryTicket = None
				self.shortExitTicket = None
				self.lowestPrice = 25000

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

		# Submit long exit order when long entry is filled
		if self.longEntryTicket is not None and self.Portfolio.Invested:
			self.longExitTicket = self.StopMarketOrder(self.liquidContract.Symbol, -self.qty, self.longEntryTicket.AverageFillPrice - 1.75)
			# Reset price variables
			self.triggerPrice = 0
			self.highestPrice = 0
			self.lowestPrice = 25000

		# Submit short exit order when short entry is filled
		if self.shortEntryTicket is not None and self.Portfolio.Invested:
			self.shortExitTicket = self.StopMarketOrder(self.liquidContract.Symbol, self.qty, self.shortEntryTicket.AverageFillPrice + 1.75)
			# Reset price variables
			self.triggerPrice = 0
			self.highestPrice = 0
			self.lowestPrice = 25000

		# Save time and reset price and ticket variables when a long exit order fills:
		if self.longExitTicket is not None and self.longExitTicket.OrderId == orderEvent.OrderId:
			self.exitFillTime = self.Time
			self.longEntryTicket = None
			self.longExitTicket = None
			self.highestPrice = 0
			self.lowestPrice = 25000

		# Save time and reset price and ticket variables when a short exit order fills:
		if self.shortExitTicket is not None and self.shortExitTicket.OrderId == orderEvent.OrderId:
			self.exitFillTime = self.Time
			self.shortEntryTicket = None
			self.shortExitTicket = None
			self.highestPrice = 0
			self.lowestPrice = 25000