Overall Statistics |
Total Trades 16 Average Win 0.09% Average Loss -0.17% Compounding Annual Return -0.574% Drawdown 0.500% Expectancy -0.119 Net Profit -0.121% Sharpe Ratio -0.721 Probabilistic Sharpe Ratio 20.825% Loss Rate 43% Win Rate 57% Profit-Loss Ratio 0.54 Alpha 0.005 Beta -0.011 Annual Standard Deviation 0.007 Annual Variance 0 Information Ratio -5.123 Tracking Error 0.179 Treynor Ratio 0.467 Total Fees $12.00 Estimated Strategy Capacity $1300000.00 |
################################################################################ # The Weekly QQQ Call Write # ---------------------------------- # # Entry: # ------- # On every Friday 30 minutes before market close, short as many calls with 50% # of portfolio cash DTE=5-9 day(Weekly), Strike Price >= Number of sigma of current price # Test different sigma for sweet spot # # Exit: # ------- # Close the call with a stop loss order when loss is 100%(schedule price check # every hour or use a stop loss order in OnData ?), # or # Close the call 30 minutes before market close next Friday # ################################################################################ from QuantConnect.Indicators import * from datetime import timedelta, datetime import numpy as np class WeeklyCall(QCAlgorithm): # ================================================================================== # Main entry point for the algo # ================================================================================== def Initialize(self): # Set the initial cash self.SetCash(100000) # Start and end dates self.SetStartDate(2020,11,1) self.SetEndDate(2021,1,16) # parameters ------------------------------------------------------------ self.minDTE = 5 # minimum target days till expiration self.maxDTE = 9 # maximum target days till expiration self.numSigma = 1.5 # To calculate strike Price self.numEntryPosition = 0.5 # Number of short selling call option self.ToleranceOfLoss = 2 # 2 represents for stop loss in 100% loss self.DaysSTD = 10 # Number of days to calculate Standard Deviation # ------------------------------------------------------------------------ self.SetWarmup(self.DaysSTD, Resolution.Daily) self.CurrentContract = str() self.PreparedContract = str() self.CostOfContract = 0 self.SetSecurityInitializer(lambda x: x.SetMarketPrice(self.GetLastKnownPrice(x))) self.symbol = self.AddEquity("QQQ", Resolution.Minute).Symbol self.Securities["QQQ"].SetDataNormalizationMode(DataNormalizationMode.Raw); self.qqq_std_price = self.STD("QQQ", self.DaysSTD, Resolution.Daily) # self.window = [] # Set Benchmark self.SetBenchmark("QQQ") #self.Schedule.On(self.DateRules.WeekEnd("QQQ"), \ # self.TimeRules.BeforeMarketClose("QQQ", 31), \ # self.PrepareContract) self.Schedule.On(self.DateRules.WeekEnd("QQQ"), \ self.TimeRules.BeforeMarketClose("QQQ", 30), \ self.SellCall) self.contract = None def OnData(self, data): if self.contract != None and self.Portfolio[self.contract].Price >= 2 * self.CostOfContract: self.Liquidate() self.contract = None if self.CurrentContract == str() and self.Time.weekday() == 4 and self.Time.hour == 15 and self.Time.minute == 29: self.OptionFilter(data) def SellCall(self): if self.contract is None: return self.AddOptionContract(self.contract, Resolution.Minute) if not self.Securities[self.contract].IsTradable: self.contract = None return self.CostOfContract = self.MarketOrder(self.contract, -1).AverageFillPrice def OptionFilter(self, data): if not(data.ContainsKey(self.symbol) and data[self.symbol] is not None): return str() UnderlyingPrice = data[self.symbol].Close std = self.qqq_std_price.Current.Value est_strike = self.MyRound(self.numSigma * std + UnderlyingPrice) contracts = self.OptionChainProvider.GetOptionContractList("QQQ", data.Time) Contracts_Expiry = [contract for contract in contracts if contract.ID.OptionRight == OptionRight.Call and self.minDTE <= (contract.ID.Date - data.Time).days <= self.maxDTE and contract.ID.StrikePrice >= est_strike] if len(Contracts_Expiry) == 0: return str() Final_Contract = sorted(Contracts_Expiry, key=lambda x: abs(x.ID.StrikePrice - est_strike)) self.contract = Final_Contract[0] return self.contract # Round the target number to its closest integer divisible by the baseinteger divisible by the base def MyRound(self, target, base=5): return base * round(target/base)