Overall Statistics |
Total Trades 72 Average Win 5.48% Average Loss -3.78% Compounding Annual Return 12.866% Drawdown 34.300% Expectancy 0.369 Net Profit 125.477% Sharpe Ratio 0.75 Probabilistic Sharpe Ratio 21.866% Loss Rate 44% Win Rate 56% Profit-Loss Ratio 1.45 Alpha 0.1 Beta 0.395 Annual Standard Deviation 0.203 Annual Variance 0.041 Information Ratio 0.092 Tracking Error 0.219 Treynor Ratio 0.385 Total Fees $208.06 |
from QuantConnect.Securities.Option import OptionPriceModels class CallTailendSetDates(QCAlgorithm): #designed so that in backtesting, if there isn't data or it can't find an option, it should bug out. Final product will be human supervised def Initialize(self): self.SetStartDate(2014, 1, 1) self.SetCash(100000) # Set Strategy Cash stock = self.AddEquity("SPY", Resolution.Minute) stock.SetDataNormalizationMode(DataNormalizationMode.Raw) self.stock_symbol = stock.Symbol bond = self.AddEquity("TLT", Resolution.Minute) bond.SetDataNormalizationMode(DataNormalizationMode.Raw) self.bond_symbol = bond.Symbol option = self.AddOption("SPY", Resolution.Minute) option.SetFilter(lambda universe: universe.Strikes(-30, 30).Expiration(timedelta(366), timedelta(400))) option.PriceModel = OptionPriceModels.CrankNicolsonFD() self.option_symbol = option.Symbol self.purchaseDates = [None, None] self.callOptions = [None, None] self.putOption = None self.callWeight = .15 self.putWeight = 0.02 self.bondWeight = 1 - self.callWeight - self.putWeight self.month = 0 self.shouldCheckIndex = -1 self.shouldRebalance = True self.SetWarmUp(timedelta(1)) def OnData(self, data): if self.IsWarmingUp or self.Time.hour < 9 and self.Time.minute < 30: return if self.Time.month != self.month: self.month = self.Time.month if self.month == 6: self.shouldCheckIndex = 0 elif self.month == 12: self.shouldCheckIndex = 1 if self.shouldCheckIndex >= 0: self.ShouldRebalance(self.shouldCheckIndex) if self.shouldRebalance: self.Rebalance(self.shouldCheckIndex) self.shouldCheckIndex = -1 def GetStockOptions(self, optionType, portfolioPercent): optionchain = None for kvp in self.CurrentSlice.OptionChains: if kvp.Key != self.option_symbol: continue optionchain = kvp.Value maxValue = self.Portfolio.TotalPortfolioValue * portfolioPercent * (-1 if optionType == OptionRight.Call else 1) optionchain = [x for x in optionchain if x.Right == optionType] x = 1 optionchain = sorted(optionchain, key = lambda x: (abs((x.Expiry - self.Time).days - 365), maxValue // (x.AskPrice * 100) * x.Greeks.Delta)) return optionchain[0] def ShouldRebalance(self, index): self.shouldRebalance = not self.callOptions[index] or self.Portfolio[ self.callOptions[index].Symbol].UnrealizedProfit < 0 or (self.Time - self.purchaseDates[index]).days > 0 def Rebalance(self, index): self.Debug(f"Rebalance {self.Time}") if self.callOptions[index]: self.Liquidate(self.callOptions[index].Symbol) if self.putOption: self.Liquidate(self.putOption.Symbol) self.callOptions[index] = self.GetStockOptions(OptionRight.Call, self.callWeight/2) self.purchaseDates[index] = self.Time self.putOption = self.GetStockOptions(OptionRight.Put, self.putWeight) if self.callOptions[index - 1]: self.SetHoldings(self.callOptions[index - 1].Symbol, self.callWeight / 2) self.SetHoldings(self.bond_symbol, self.bondWeight) self.SetHoldings(self.putOption.Symbol, self.putWeight) self.SetHoldings(self.callOptions[index].Symbol, self.callWeight / 2) x = 1 def OnEndOfDay(self): for each in self.Portfolio: if each.Value.Invested and each.Value.Type == SecurityType.Option: self.Debug(f"{each.Key}: {self.Portfolio[each.Key].AbsoluteHoldingsValue}")