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
Sortino 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
-14.727
Tracking Error
0.104
Treynor Ratio
0
Total Fees
$0.00
Estimated Strategy Capacity
$0
Lowest Capacity Asset
Portfolio Turnover
0%
from AlgorithmImports import *
from datetime import datetime, timedelta

class MyAlgorithm(QCAlgorithm):
    def Initialize(self):
        self.SetStartDate(2024, 1, 5)  # Set your desired start date
        self.SetEndDate(2024, 1, 10)    # Set your desired end date
        self.SetCash(100000)            # Set your initial capital

        # Add SPX and SPY indices
        spx = self.AddIndex("SPX", Resolution.Minute).Symbol
        spy = self.AddEquity("SPY", Resolution.Minute).Symbol
        self.optionSymbols = []
        self.optionSymbols.append(Symbol.CreateCanonicalOption(spx, "SPXW", Market.USA, "?SPXW"))
        self.optionSymbols.append(self.AddOption(spy).Symbol)

        # Schedule the SelectOptionStrikes method to run every 5 minutes
        self.Schedule.On(self.DateRules.EveryDay('SPY'), self.TimeRules.Every(timedelta(minutes=60)), self.SelectOptionStrikes)

    def OnSecuritiesChanged(self, changes):
        self.Plot('SPX', 'Added', len(changes.AddedSecurities))
        self.Plot('SPX', 'Removed', len(changes.RemovedSecurities))
        self.Plot("Total Securities", len(self.ActiveSecurities.Keys))

    def SelectOptionStrikes(self):

        if not self.IsMarketOpen(self.optionSymbols[0]):
            for optionSymbol in self.optionSymbols:
                for activeSymbol in self.ActiveSecurities.Keys:
                    if activeSymbol.SecurityType in [SecurityType.Option, SecurityType.IndexOption] and activeSymbol.Underlying == optionSymbol.Underlying and not self.Portfolio[activeSymbol].Invested:
                        self.RemoveOptionContract(activeSymbol)

        if self.CurrentSlice.ContainsKey(self.optionSymbols[0].Underlying):
            # Define the range around the spot price
            strikeRange = 20

            # Loop through SPX and SPY symbols
            for optionSymbol in self.optionSymbols:
                # Get the spot price of the specified index
                spotPrice = self.Securities[optionSymbol.Underlying].Price
                self.Log(f'{optionSymbol.Underlying} spotPrice {spotPrice}')
                
                # Get the option chain for the specified index
                optionChain = self.OptionChainProvider.GetOptionContractList(optionSymbol, self.Time)
                optionChain = [x for x in optionChain if x.ID.Date.date() == self.Time.date()] if optionSymbol.Underlying == 'SPX' else [x for x in optionChain if x.ID.Date.date() == (self.Time.date() + timedelta(days=1))]
                self.Log(f'{optionSymbol.Underlying} length of optionChain {len(optionChain)}')

                # Select 20 strikes around the spot price with expiration date equal to the current date
                selectedStrikes = sorted([x for x in optionChain],key=lambda x: abs(x.ID.StrikePrice - spotPrice))[:40]
                selectedStrikes = sorted(selectedStrikes, key=lambda x: x.ID.StrikePrice)
                if len(selectedStrikes) > 0:
                    self.Log(f'{optionSymbol.Underlying} length of selectedStrikes {len(selectedStrikes)} expiry: {selectedStrikes[0].ID.Date.date()} low {selectedStrikes[0].ID.StrikePrice} high {selectedStrikes[-1].ID.StrikePrice}')

                    # Remove strikes that are no longer within the selected range and not invested
                    for activeSymbol in self.ActiveSecurities.Keys:
                        if activeSymbol.Underlying == optionSymbol.Underlying and activeSymbol not in selectedStrikes and not self.Portfolio[activeSymbol].Invested:
                            self.RemoveOptionContract(activeSymbol)

                    # Add new strikes to the universe
                    for strike in selectedStrikes:
                        if strike not in self.ActiveSecurities.Keys:
                            self.AddOptionContract(strike, Resolution.Minute)

            # Log the total number of securities
            self.Debug(f"Total Securities: {len(self.ActiveSecurities.Keys)}")