Overall Statistics |
Total Trades 8 Average Win 2.88% Average Loss 0% Compounding Annual Return 10.557% Drawdown 2.000% Expectancy 0 Net Profit 11.985% Sharpe Ratio 2.027 Probabilistic Sharpe Ratio 91.890% Loss Rate 0% Win Rate 100% Profit-Loss Ratio 0 Alpha 0.069 Beta -0.084 Annual Standard Deviation 0.036 Annual Variance 0.001 Information Ratio 0.542 Tracking Error 0.214 Treynor Ratio -0.862 Total Fees $20.00 Estimated Strategy Capacity $24000000.00 Lowest Capacity Asset SPY 323UYHQN3M1YE|SPY R735QTJ8XC9X |
#region imports from AlgorithmImports import * #endregion class VirtualRedDogfish(QCAlgorithm): def Initialize(self): self.SetStartDate(2021, 12, 1) # self.SetEndDate(2022, 10, 1) self.SetCash(1000000) self.vix = self.AddIndex('VIX', Resolution.Minute) self.stock = self.AddEquity("SPY", Resolution.Minute) self.stock.SetDataNormalizationMode(DataNormalizationMode.Raw) self.stock_symbol = self.stock.Symbol self.SetSecurityInitializer(lambda x: x.SetMarketPrice(self.GetLastKnownPrice(x))) self.contract = None #Initialize the option contract self.trade = False #Setup flag to trade self.option_wt = 0.05 #Target portfolio weight #Set parameters for optimization self.option_premium = float(self.GetParameter("option_premium")) # self.option_premium = 0.95 # % Strike price premium/discount to underlying self.option_dte = float(self.GetParameter("option_dte")) # self.option_dte = 90 #Target days-to-expiration for option contract #Schedule trade #1 self.Schedule.On(self.DateRules.On(2021, 12, 21), \ self.TimeRules.AfterMarketOpen(self.stock_symbol, 30), \ self.SetupBuyTrade) self.Schedule.On(self.DateRules.On(2022, 1, 24), \ self.TimeRules.AfterMarketOpen(self.stock_symbol, 30), \ self.SetupSellTrade) #Schedule trade #2 self.Schedule.On(self.DateRules.On(2022, 2, 9), \ self.TimeRules.AfterMarketOpen(self.stock_symbol, 30), \ self.SetupBuyTrade) self.Schedule.On(self.DateRules.On(2022, 2, 24), \ self.TimeRules.AfterMarketOpen(self.stock_symbol, 30), \ self.SetupSellTrade) #Schedule trade #3 self.Schedule.On(self.DateRules.On(2022, 4, 12), \ self.TimeRules.AfterMarketOpen(self.stock_symbol, 30), \ self.SetupBuyTrade) self.Schedule.On(self.DateRules.On(2022, 4, 29), \ self.TimeRules.AfterMarketOpen(self.stock_symbol, 30), \ self.SetupSellTrade) #Schedule trade #4 self.Schedule.On(self.DateRules.On(2022, 8, 8), \ self.TimeRules.AfterMarketOpen(self.stock_symbol, 30), \ self.SetupBuyTrade) self.Schedule.On(self.DateRules.On(2022, 9, 23), \ self.TimeRules.AfterMarketOpen(self.stock_symbol, 30), \ self.SetupSellTrade) # #Schedule trade #5 # self.Schedule.On(self.DateRules.On(2023, 1, 13), \ # self.TimeRules.AfterMarketOpen(self.stock_symbol, 30), \ # self.SetupBuyTrade) def OnData(self, slice): #Liquidate any options that are within 1.5 days of expiration option_invested = [x.Key for x in self.Portfolio if x.Value.Invested and x.Value.Type==SecurityType.Option] if option_invested: expirydate = self.contract.ID.Date if (expirydate - self.Time) < timedelta(1.5): # self.Debug("Sell option, less than 2 days before expiry") self.Liquidate(self.contract) self.contract = None if self.trade: # self.Log("Buy trade fired at : {0}".format(self.Time)) self.InitiateTrade() def SetupBuyTrade(self): #Check to see if already invested in option option_invested = [x.Key for x in self.Portfolio if x.Value.Invested and x.Value.Type==SecurityType.Option] if not option_invested: self.contract = self.GetPut() self.trade = True def SetupSellTrade(self): #Check to see if already invested in option option_invested = [x.Key for x in self.Portfolio if x.Value.Invested and x.Value.Type==SecurityType.Option] if option_invested: # self.Log("Exit trade fired at : {0}".format(self.Time)) self.Liquidate(self.contract) self.contract = None self.trade = False def GetPut(self): targetStrike = self.Securities[self.stock_symbol].Price * self.option_premium contracts = self.OptionChainProvider.GetOptionContractList(self.stock_symbol, self.Time) # self.Debug(f"SPY total contracts found: {len(contracts)}") puts = [x for x in contracts if x.ID.OptionRight == OptionRight.Put] puts = sorted(sorted(puts, key = lambda x: x.ID.Date), key = lambda x: x.ID.StrikePrice, reverse = False) # self.Debug(f"SPY puts found: {len(puts)}") puts = [x for x in puts if (x.ID.StrikePrice - targetStrike) >= 0 and (x.ID.StrikePrice - targetStrike) < 100] puts = [x for x in puts if self.option_dte < (x.ID.Date - self.Time).days <= self.option_dte+100] #self.option_dte+100 sets dte buffer of 100 days if len(puts) == 0: # self.Debug(f"!!! No puts available") return None # else: self.Debug(f"SPY puts w/ good strikes found: {len(puts)}") self.Debug(f"Selected option contract: {puts[0]} &, expiration: {puts[0].ID.Date} \ &, strike: {puts[0].ID.StrikePrice} &, SPY: {self.stock.Price} & , VIX: {self.vix.Price}") self.AddOptionContract(puts[0], Resolution.Minute) return puts[0] def InitiateTrade(self): if self.contract is not None: self.SetHoldings(self.contract, self.option_wt) self.trade = False #Reset trading flag