Overall Statistics |
Total Trades 18 Average Win 24.12% Average Loss -5.81% Compounding Annual Return 113.712% Drawdown 9.900% Expectancy 0.546 Net Profit 30.155% Sharpe Ratio 5.231 Probabilistic Sharpe Ratio 89.719% Loss Rate 70% Win Rate 30% Profit-Loss Ratio 4.15 Alpha -0.132 Beta 1.041 Annual Standard Deviation 0.23 Annual Variance 0.053 Information Ratio -4.017 Tracking Error 0.02 Treynor Ratio 1.155 Total Fees $22.50 |
# https://quantpedia.com/Screener/Details/20 from datetime import timedelta from decimal import Decimal class BullCallSpreadAlgorithm(QCAlgorithm): def Initialize(self): self.SetStartDate(2020, 5, 1) self.SetEndDate(2020, 9, 4) self.SetCash(100000) equity = self.AddEquity("QQQ", Resolution.Minute) option = self.AddOption("QQQ", Resolution.Minute) self.symbol = equity.Symbol option.SetFilter(self.UniverseFunc) self.SetBenchmark(equity.Symbol) # self.delta50_call = None # self.delta50_put = None # self.delta25_put = None def OnData(self,slice): for i in slice.OptionChains: chains = i.Value if not self.Portfolio.Invested: # divide option chains into call and put options calls = list(filter(lambda x: x.Right == OptionRight.Call, chains)) puts = list(filter(lambda x: x.Right == OptionRight.Put, chains)) # if lists are empty return if not calls or not puts: return underlying_price = self.Securities[self.symbol].Price expiries = [i.Expiry for i in puts] #sell_delta50_call_expiry = [call if call.Expiry == self.delta50_call.Expiry for call in calls] #sell_delta50_call = [call if call.Strike == self.delta50_call.Strike for call in sell_delta50_call_expiry] #sell_delta50_put = [put if put.Expiry == self.delta50_put.Expiry if #put.Strike == self.delta50_put.Strike for put in puts] # determine expiration date nearly one month expiry = min(expiries, key=lambda x: abs((x.date()-self.Time.date()).days-30)) strikes = [i.Strike for i in puts] # determine at-the-money strike strike = min(strikes, key=lambda x: abs(x-Decimal(0.50)*underlying_price)) # determine 15% out-of-the-money strike otm_strike = min(strikes, key = lambda x:abs(x-Decimal(0.25)*underlying_price)) self.atm_call = [i for i in calls if i.Expiry == expiry and i.Strike == strike] self.atm_put = [i for i in puts if i.Expiry == expiry and i.Strike == strike] self.otm_put = [i for i in puts if i.Expiry == expiry and i.Strike == otm_strike] #if (self.delta25_put.Expiry - self.Time).days <= 2: if self.atm_call and self.atm_put and self.otm_put: self.Debug("Underlying Price: " + str(underlying_price)) self.delta50_call = self.atm_call[0] self.Debug("50 Delta Call: " + str(self.delta50_call.Strike)) self.delta50_put = self.atm_put[0] self.Debug("50 Delta Put: " + str(self.delta50_put.Strike)) self.delta25_put = self.otm_put[0] self.Debug("25 Delta Put: " + str(self.delta25_put.Strike)) # sell at-the-money straddle self.Buy(self.delta50_call.Symbol, 5) self.Buy(self.delta50_put.Symbol, 5) # buy 25% out-of-the-money put self.Sell(self.delta25_put.Symbol, 5) if self.Portfolio.Invested: # if (self.delta50_call.Expiry - self.Time).days <= 2: # days = (self.delta50_call.Expiry-self.Time).days # self.Debug(days) self.Liquidate(self.symbol) # self.delta50_call = None # self.delta50_put = None # self.delta25_put = None def OnOrderEvent(self, orderEvent): self.Log(str(orderEvent)) def UniverseFunc(self, universe): return universe.IncludeWeeklys().Strikes(-40, 40).Expiration(timedelta(25), timedelta(35))