Hey guys! 

I have a simple equity strategy that looks a lot like this: 

  1. # region imports
  2. from AlgorithmImports import *
  3. import pandas as pd
  4. import numpy as np
  5. from datetime import time, datetime, timedelta
  6. # endregion
  7. class CombinedAlgorithm(QCAlgorithm):
  8. def Initialize(self):
  9. # INITIALIZE
  10. self.SetStartDate(2022, 1, 1) # Set Start Date
  11. self.SetEndDate(2022, 5, 5)
  12. self.SetCash(10000) # Set Strategy Cash
  13. self.symbol = self.AddEquity('AAPL', Resolution.Minute)
  14. self.symbol.SetDataNormalizationMode(DataNormalizationMode.SplitAdjusted)
  15. # SCHEDULED EVENTS
  16. self.Schedule.On(self.DateRules.EveryDay(self.symbol.Symbol), self.TimeRules.AfterMarketOpen(self.symbol.Symbol, 120), self.TradingOn)
  17. self.Schedule.On(self.DateRules.EveryDay(self.symbol.Symbol), self.TimeRules.BeforeMarketClose(self.symbol.Symbol, 10), self.TradingOff)
  18. self.Schedule.On(self.DateRules.EveryDay(self.symbol.Symbol), self.TimeRules.BeforeMarketClose(self.symbol.Symbol, 2), self.LiquidateCheck)
  19. self.Schedule.On(self.DateRules.EveryDay(self.symbol.Symbol), self.TimeRules.BeforeMarketClose(self.symbol.Symbol), self.DayEnd)
  20. # TOGGLES
  21. self.thirty_min_reversal_sell = False
  22. self.initial_thirty_min_stop_sell = False
  23. self.initial_stop_sell = False
  24. self.target_sell = False
  25. self.target_hit = False
  26. self.short = False
  27. self.trading = False
  28. self.break_even = False
  29. self.liquidate_toggle = False
  30. self.invest_thirty_min = False
  31. self.thirty_min_trigger = False
  32. # VARIABLES
  33. self.symbol_price = 0
  34. self.initial_stop_price = 0
  35. self.initial_target_price = 0
  36. self.entry_price = 0
  37. self.trigger_thirty_min_open = 0
  38. self.trigger_thirty_min_close = 0
  39. self.trigger_thirty_min_high = 0
  40. self.trigger_thirty_min_low = 0
  41. self.SetWarmUp(timedelta(days = 25))
  42. self.ema = self.EMA(self.symbol.Symbol, 15, Resolution.Daily)
  43. # CONSOLIDATED DATA
  44. # 30-Minute Bars
  45. thirty_min_consolidator = TradeBarConsolidator(timedelta(minutes=30))
  46. self.SubscriptionManager.AddConsolidator(self.symbol.Symbol, thirty_min_consolidator)
  47. thirty_min_consolidator.DataConsolidated += self.OnThirtyMinBar
  48. self.thirtyMinBarWindow = RollingWindow[TradeBar](2)
  49. def OnData(self, data):
  50. if self.IsWarmingUp:
  51. return
  52. # VARIABLES
  53. self.symbol_price = self.Securities[self.symbol.Symbol].Price
  54. held_stocks = self.Portfolio[self.symbol.Symbol].Quantity
  55. shares_to_buy = int(self.Portfolio.Cash / self.Securities[self.symbol.Symbol].Price)
  56. # ENTRY (SHORT) (HOUR TRIGGERING HOUR - FIRST TRADE OTD)
  57. if self.trading and self.thirty_min_trigger and not self.short:
  58. if (self.symbol_price < self.trigger_thirty_min_low) and self.invest_thirty_min and not self.Portfolio.Invested:
  59. self.ticket = self.MarketOrder(self.symbol.Symbol, -(shares_to_buy))
  60. self.invest_thirty_min = False
  61. self.thirty_min_trigger = False
  62. self.initial_thirty_min_stop_sell = True
  63. self.initial_stop_sell = True
  64. self.initial_thirty_min_stop_price = self.trigger_thirty_min_high
  65. self.thirty_min_reversal_sell = True
  66. self.short = True
  67. self.target_sell = True
  68. self.entry_price = self.symbol_price
  69. self.initial_target_price = self.entry_price * 0.99
  70. self.Log(f'SHORT ENTRY (HOURLY TRIGGERING HOURLY) {self.symbol_price}')
  71. # EXIT (INITIAL TARGET)
  72. if self.Portfolio.Invested and self.short and self.target_sell and (self.symbol_price < self.initial_target_price):
  73. self.MarketOrder(self.ticket.Symbol, (self.Securities[self.ticket.Symbol].Holdings.AbsoluteQuantity))
  74. self.target_sell = False
  75. self.target_hit = True
  76. self.Log(f'EXIT (INITIAL TARGET) {self.symbol_price}')
  77. # EXIT (INITIAL STOP)
  78. if not self.target_hit and self.Portfolio.Invested and self.short and self.initial_thirty_min_stop_sell and (self.symbol_price > self.initial_thirty_min_stop_price):
  79. self.MarketOrder(self.ticket.Symbol, (self.Securities[self.ticket.Symbol].Holdings.AbsoluteQuantity))
  80. self.initial_thirty_min_stop_sell = False
  81. self.thirty_min_reversal_sell = False
  82. self.short = False
  83. self.Log(f'EXIT (INITIAL STOP before target hit) {self.symbol_price}')
  84. if not self.target_hit and self.Portfolio.Invested and self.short and self.initial_stop_sell and (self.symbol_price > self.initial_stop_price):
  85. self.MarketOrder(self.ticket.Symbol, (self.Securities[self.ticket.Symbol].Holdings.AbsoluteQuantity))
  86. self.initial_stop_sell = False
  87. self.thirty_min_reversal_sell = False
  88. self.short = False
  89. self.Log(f'EXIT (INITIAL STOP before target hit) {self.symbol_price}')
  90. if (self.target_hit or self.break_even) and self.Portfolio.Invested and self.short and self.initial_thirty_min_stop_sell and (self.symbol_price > self.entry_price):
  91. self.MarketOrder(self.ticket.Symbol, (self.Securities[self.ticket.Symbol].Holdings.AbsoluteQuantity))
  92. self.initial_thirty_min_stop_sell = False
  93. self.thirty_min_reversal_sell = False
  94. self.short = False
  95. self.Log(f'EXIT (INITIAL STOP after target hit) {self.symbol_price}')
  96. # EXIT (60-MIN TRAILING STOP)
  97. if self.short and self.Portfolio.Invested and self.thirty_min_reversal_sell and (self.symbol_price > (self.trigger_hour_high)):
  98. self.MarketOrder(self.ticket.Symbol, (self.Securities[self.ticket.Symbol].Holdings.AbsoluteQuantity))
  99. self.thirty_min_reversal_sell = False
  100. self.initial_stop_sell = False
  101. self.short = False
  102. self.Log(f'EXIT (30-MIN REVERSAL) {self.symbol_price} and {self.trigger_thirty_min_high}')
  103. # EXIT (LIQUIDATE AT THE END OF THE DAY)
  104. if self.liquidate_toggle:
  105. self.MarketOrder(self.ticket.Symbol, (self.Securities[self.ticket.Symbol].Holdings.AbsoluteQuantity))
  106. self.liquidate_toggle = False
  107. self.short = False
  108. self.Log(f'EXIT (LIQUIDATE AT THE END OF THE DAY) {self.symbol_price}')
  109. # CONSOLILDATED FUNCTIONS
  110. def OnThirtyMinBar(self, sender, bar):
  111. self.thirtyMinBarWindow.Add(bar)
  112. if not self.thirtyMinBarWindow.IsReady:
  113. return
  114. if self.IsWarmingUp:
  115. return
  116. # VARIABLES
  117. self.thirtyMinBarWindow.Add(bar)
  118. if not self.thirtyMinBarWindow.IsReady:
  119. return
  120. trigger_thirty_min = self.thirtyMinBarWindow[0]
  121. previous_thirty_min = self.thirtyMinBarWindow[1]
  122. self.trigger_thirty_min_open = trigger_thirty_min.Open
  123. self.trigger_thirty_min_close = trigger_thirty_min.Close
  124. self.trigger_thirty_min_high = trigger_thirty_min.High
  125. self.trigger_thirty_min_low = trigger_thirty_min.Low
  126. previous_thirty_min_high = previous_thirty_min.High
  127. previous_thirty_min_low = previous_thirty_min.Low
  128. if self.Time.hour == 10 and self.Time.minute == 0:
  129. self.open_thirty_low = self.trigger_thirty_min_low
  130. if (self.trigger_thirty_min_high < previous_thirty_min_high) and (self.trigger_thirty_min_low > previous_thirty_min_low):
  131. self.trigger_thirty_min_timer = self.Time.minute
  132. self.invest_thirty_min = True
  133. self.thirty_min_trigger = True
  134. # SCHEDULED EVENTS
  135. def TradingOn(self): # 2 hours after market open
  136. self.trading = True
  137. def TradingOff(self): # 1 hour before market close
  138. self.trading = False
  139. def LiquidateCheck(self): # 2 mins before market close
  140. if self.Portfolio.Invested:
  141. self.liquidate_toggle = True
  142. if not self.Portfolio.Invested:
  143. return
  144. def DayEnd(self):
  145. self.trading = False
  146. self.short = False
+ Expand

I am trying to leave all the entry and exit logic the same, but trade Equity Options instead. 

I have changed two things.

  1. contract_symbols = self.OptionChainProvider.GetOptionContractList(self.symbol.Symbol, self.Time)
  2. expiry = min([symbol.ID.Date for symbol in contract_symbols])
  3. filtered_symbols = [symbol for symbol in contract_symbols if symbol.ID.Date == expiry and symbol.ID.OptionRight == OptionRight.Call]
  4. self.contract_symbol = sorted(filtered_symbols, key=lambda symbol: symbol.ID.StrikePrice)[0]

And then I changed the Market Orders to order the ‘contract_symbol’ instead of symbol.Symbol:

  1. # self.ticket = self.MarketOrder(self.symbol.Symbol, -(shares_to_buy))
  2. self.ticket = self.MarketOrder(self.contract_symbol, -(shares_to_buy))

Now here is the problem: 

I mess around with the code and it will either produce one of two errors. 

  1. Runtime Error: This asset symbol (AAPL XUSJM7EPSLUU|AAPL R735QTJ8XC9X) was not found in your security list. Please add this security or check it exists before using it with 'Securities.ContainsKey("AAPL XUSJM7EPSLUU|AAPL R735QTJ8XC9X")' in SecurityManager
  2. ############ OR ############
  3. OptionRight is only defined for SecurityType.Option, SecurityType.FutureOption, and SecurityType.IndexOption in SecurityIdentifier

Does anyone have any idea what is happening! Thank you to all those who took the time and effort to read this. I am looking forward to hear from my fellow Quants. 

Best, 

Jesse

Author

Jesse Fleming

November 2022