This algorithm simply buys a put and a call on SPX when it is at the 200 day moving average. I am publishing this code because on my youtube channel I explain it and I am providing the source code in the comments there and here. Please share any suggestions you may have and if anyone has a framework for a bracket order on two securities at once with points not percentages please provide it.

 

# region imports
from AlgorithmImports import *
# endregion

class SquareMagentaHamster(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2018, 1, 1)  # Set Start Date
        self.SetEndDate(2023, 1, 1)
        self.SetCash(1000000)  # Set Strategy Cash

        index = self.AddIndex("SPX", Resolution.Minute)
        self.spx = index.Symbol 

        option = self.AddOption(index.Symbol, Resolution.Minute)
        option.SetFilter(self.UniverseFunc)
        self.symbol = option.Symbol
        
        self.indicator = SimpleMovingAverage(200)
        self.RegisterIndicator(self.spx, self.indicator, Resolution.Daily)

        self.entryTicket = None
        self.SLTicket = None
        self.TPTicket = None

        self.entryTime = datetime.min

        self.AddRiskManagement(TrailingStopRiskManagementModel(0.15))

    def UniverseFunc(self, universe: OptionFilterUniverse) -> OptionFilterUniverse:
        return universe.IncludeWeeklys().Strikes(1, 2).Expiration(timedelta(45), timedelta(50))

    def OnData(self, data: Slice):

        if not(data.ContainsKey(self.spx) and data[self.spx] is not None): return

        if not self.indicator.IsReady: return

        option_invested = [x.Key for x in self.Portfolio if x.Value.Invested and x.Value.Type==SecurityType.Option]
 
        if option_invested:
            for option in option_invested:
                if self.Time + timedelta(1) > option.ID.Date:
                    self.Liquidate(option, "Option too close to expiration.")

        lvl = self.indicator.Current.Value

        atSMA = self.Securities[self.spx].AskPrice > lvl - 2 and self.Securities[self.spx].AskPrice < lvl + 2

        if atSMA and not self.Portfolio.Invested:
            self.BuyCall(data)
            self.BuyPut(data)

    def BuyCall(self, data: Slice) -> None:
        # Get the OptionChain
        chain = data.OptionChains.get(self.symbol, None)
        if not chain: return

        # Get the furthest expiry date of the contracts
        expiry = sorted(chain, key = lambda x: x.Expiry, reverse=True)[0].Expiry
       
        # Select the call Option contracts with the furthest expiry
        calls = [i for i in chain if i.Expiry == expiry and i.Right == OptionRight.Call]
        if len(calls) == 0: return

        call_contracts = sorted(calls, key = lambda x: abs(x.Strike - x.UnderlyingLastPrice))
        if len(call_contracts) == 0:
            return

        self.call = call_contracts[0]

        self.entryTicket = self.MarketOrder(self.call.Symbol, 5)


    def BuyPut(self, data: Slice) -> None:
        # Get the OptionChain
        chain = data.OptionChains.get(self.symbol, None)
        if not chain: return

        # Get the furthest expiry date of the contracts
        expiry = sorted(chain, key = lambda x: x.Expiry, reverse=True)[0].Expiry
       
        # Select the call Option contracts with the furthest expiry
        puts = [i for i in chain if i.Expiry == expiry and i.Right == OptionRight.Put]
        if len(puts) == 0: return

        put_contracts = sorted(puts, key = lambda x: abs(x.Strike - x.UnderlyingLastPrice))
        if len(put_contracts) == 0:
            return

        self.put = put_contracts[0]

        self.entryTicket = self.MarketOrder(self.put.Symbol, 5)