Overall Statistics |
Total Trades 2 Average Win 15.98% Average Loss 0% Compounding Annual Return -22.886% Drawdown 0.500% Expectancy 0 Net Profit -0.333% Sharpe Ratio -6.605 Probabilistic Sharpe Ratio 14.218% Loss Rate 0% Win Rate 100% Profit-Loss Ratio 0 Alpha 0 Beta 0 Annual Standard Deviation 0.029 Annual Variance 0.001 Information Ratio -6.605 Tracking Error 0.029 Treynor Ratio 0 Total Fees $2.00 Estimated Strategy Capacity $14000000.00 Lowest Capacity Asset SPX 31KC0UJJBN6EM|SPX 31 |
class TestIndexOptionAlgorithm(QCAlgorithm): def Initialize(self): # Backtesting parameters self.SetStartDate(2021, 1, 11) self.SetEndDate(2021, 1, 15) self.SetCash(1000000) # Index Ticker Symbol self.ticker = "SPX" # Time Resolution self.timeResolution = Resolution.Minute # Resolution.Minute .Hour .Daily # Set brokerage model and margin account self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin) # Days to Expiration self.dte = 5 # Number of strikes to retrieve from the option chain universe (nStrikes on each side of ATM) self.nStrikes = 100 # Add the underlying Index index = self.AddIndex(self.ticker, self.timeResolution) index.SetDataNormalizationMode(DataNormalizationMode.Raw) self.underlyingSymbol = index.Symbol # Keep track of the option contract subscriptions self.optionContractsSubscriptions = [] # Add option option = self.AddIndexOption(index.Symbol, self.timeResolution) self.optionSymbol = option.Symbol # Set the option chain filter function option.SetFilter(self.optionChainFilter) # Set option pricing model for retrieving the Greeks. It appears that the Delta computed by the platform is incurrect! #option.PriceModel = OptionPriceModels.CrankNicolsonFD() # Handles both European & American options # The pricing model needs some warm-up time to get the Greeks #self.SetWarmUp(TimeSpan.FromDays(7)) option.PriceModel = OptionPriceModels.BlackScholes() # European Options # Set Security Initializer (This does not seem to solve the issue with the benchmark below) self.SetSecurityInitializer(self.security_initializer) # Setting the benchmark below causes the following error: # Runtime Error: Sorry Hour is not a supported resolution for TradeBar and SecurityType.Index. Please change your AddData to use one of the supported resolutions (Minute). in DataManager.cs:line 455 (Open Stacktrace) #self.SetBenchmark(index.Symbol) # ----------------------------------------------------------------------------- # Scheduled function: every day, 25 minutes after the market open # ----------------------------------------------------------------------------- self.Schedule.On(self.DateRules.EveryDay(self.underlyingSymbol) , self.TimeRules.AfterMarketOpen(self.underlyingSymbol, 25) , Action(self.openPosition) ) def security_initializer(self, security): if security.Type == SecurityType.Equity: security.SetDataNormalizationMode(DataNormalizationMode.Raw) elif security.Type == SecurityType.Option: security.SetMarketPrice(self.GetLastKnownPrice(security)) def optionChainFilter(self, universe): return universe.IncludeWeeklys()\ .Strikes(-self.nStrikes, self.nStrikes)\ .Expiration(0, self.dte) def getOptionChain(self, slice): # Loop through all chains for chain in slice.OptionChains: # Look for the specified optionSymbol if chain.Key != self.optionSymbol: continue # Make sure there are any contracts in this chain if chain.Value.Contracts.Count != 0: return chain.Value def openPosition(self): self.Debug("Entering method openPosition") # Get the option chain chain = self.getOptionChain(self.CurrentSlice) # Exit if we got no chains if chain == None: self.Debug(" -> No chains!") return # Log the number of contracts that were found self.Debug(" -> Found " + str(chain.Contracts.Count) + " contracts in the option chain!") # Do not open any new positions if we have already one open if self.Portfolio.Invested: return # Get the furthest expiry date expiry = sorted(chain, key = lambda x: x.Expiry, reverse = True)[0].Expiry # Sort all Put contracts (with the given expiry date) by the strike price in reverse order puts = sorted([contract for contract in chain if contract.Expiry == expiry and contract.Right == OptionRight.Put ] , key = lambda x: x.Strike , reverse = True ) # Get the ATM put contract = puts[0] # Subscribe to the option contract data feed if not contract.Symbol in self.optionContractsSubscriptions: self.AddOptionContract(contract.Symbol, self.timeResolution) self.optionContractsSubscriptions.append(contract.Symbol) # Sell the Put self.MarketOrder(contract.Symbol, -1, True) def OnOrderEvent(self, orderEvent): self.Debug(orderEvent) def OnData(self, slice): pass