Overall Statistics |
Total Trades 13 Average Win 33.16% Average Loss -0.25% Compounding Annual Return 79228162514264337593543950335% Drawdown 1.300% Expectancy 110.103 Net Profit 429.014% Sharpe Ratio 2.5850910150313346E+21 Probabilistic Sharpe Ratio 100.000% Loss Rate 17% Win Rate 83% Profit-Loss Ratio 132.32 Alpha 9.431259192293879E+21 Beta 4.688 Annual Standard Deviation 3.648 Annual Variance 13.31 Information Ratio 2.614276119555494E+21 Tracking Error 3.608 Treynor Ratio 2.0116827907094746E+21 Total Fees $10.00 Estimated Strategy Capacity $290000.00 Lowest Capacity Asset QQQ Y4WV0TYZQ606|QQQ RIWIV7K5Z9LX |
#region imports from AlgorithmImports import * #endregion from datetime import timedelta class RSI_Slope(QCAlgorithm): def Initialize(self): self.SetStartDate(2023,1,1) self.SetEndDate(2023,1,10) self.SetCash(100000) self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage) self.SetWarmUp(5000, Resolution.Minute) #QQQ option initialize self.equityqqq = self.AddEquity("QQQ", Resolution.Minute) self.equityqqq.SetDataNormalizationMode(DataNormalizationMode.Raw) self.symbolqqq = self.equityqqq.Symbol self.SetSecurityInitializer(lambda x: x.SetMarketPrice(self.GetLastKnownPrice(self.equityqqq))) self.SetBenchmark(self.symbolqqq) #Make lists to guide trading algo self.qqqequitylist = dict() self.qqqequitylist[0] = 0 self.qqqcoveredcalllist = dict() self.qqqcoveredcalllist[0] = 0 self.callcontractqqq = str() self.callcontractsAddedqqq = set() self.numberofshares = dict() self.numberofshares[0] = 0 # parameters ------------------------------------------------------------ self.CallDTE = 14 # target days till expiration self.CallOTM = 1.0075 # target percentage OTM of call # ------------------------------------------------------------------------ self.Schedule.On(self.DateRules.EveryDay(),self.TimeRules.AfterMarketOpen("QQQ",-1), self.OpeningBarQQQ) self.Schedule.On(self.DateRules.EveryDay(),self.TimeRules.AfterMarketOpen("QQQ",1), self.Sellingcalls) def OpeningBarQQQ(self): if self.qqqcoveredcalllist[0] == 1: self.qqqcoveredcalllist[0] = 0 self.callcontractqqq = str() self.callcontractsAddedqqq = set() self.Log("Equitylist: {0}".format(self.qqqequitylist[0])) def Sellingcalls(self): if self.qqqcoveredcalllist[0] == 0: self.qqqcoveredcalllist[0] = 5 def OnData(self, data): if self.IsWarmingUp: return QQQprice = self.Securities["QQQ"].Price investedQQQequity = [symbol for symbol, holding in self.Portfolio.items() if holding.IsLong and holding.Type == SecurityType.Equity] shortcalloptioninvestedQQQ = [symbol for symbol, holding in self.Portfolio.items() if holding.IsShort and holding.Type == SecurityType.Option and symbol.Underlying.Equals(self.symbolqqq) and symbol.ID.OptionRight == OptionRight.Call] #trading logic for QQQ covered calls #if algo restarts and option invested this will update the lists and option logs if investedQQQequity: if self.qqqequitylist[0] == 0: self.qqqequitylist[0] = 1 if shortcalloptioninvestedQQQ: if self.qqqcoveredcalllist[0] == 0: self.qqqcoveredcalllist[0] = 1 if not self.Portfolio["QQQ"].Invested: self.qqqequitylist[0] = 0 self.Log("Out of QQQ") if self.qqqequitylist[0] == 0: quantity = self.CalculateOrderQuantity("QQQ", 0.5) rounded = round(quantity, -2) self.MarketOrder("QQQ", rounded) self.Log("Bought shares of QQQ") self.numberofshares[0] = rounded / 100 self.Log("Number of countracts to sell: {0}".format(self.numberofshares[0])) self.qqqequitylist[0] = 1 if self.qqqcoveredcalllist[0] == 5: self.Buyqqqcall(data) #options filter and buy logic will find a call and buy a call def Buyqqqcall(self, data): Contractstosell = self.numberofshares[0] # get option data if self.callcontractqqq == str(): self.Log("Obtaining QQQ call contract") self.callcontractqqq = self.OptionsFilterqqqcall(data) return # if not invested and option data added successfully, buy option if not self.Portfolio[self.callcontractqqq].Invested and data.ContainsKey(self.callcontractqqq): self.MarketOrder(self.callcontractqqq, -Contractstosell) self.qqqcoveredcalllist[0] = 1 def OptionsFilterqqqcall(self, data): ''' OptionChainProvider gets a list of option contracts for an underlying symbol at requested date. Then you can manually filter the contract list returned by GetOptionContractList. The manual filtering will be limited to the information included in the Symbol (strike, expiration, type, style) and/or prices from a History call ''' callcontractsqqq = self.OptionChainProvider.GetOptionContractList(self.symbolqqq, data.Time) self.underlyingPriceqqq = self.Securities[self.symbolqqq].Price # filter the out-of-money put options from the contract list which expire close to self.DTE num of days from now qqqotm_calls = [i for i in callcontractsqqq if i.ID.OptionRight == OptionRight.Call and i.ID.StrikePrice > self.CallOTM * self.underlyingPriceqqq and (i.ID.Date - data.Time).days < self.CallDTE] if len(qqqotm_calls) > 0: # sort options by closest to self.DTE days from now and desired strike, and pick first callqqqcontract = sorted(sorted(qqqotm_calls, key = lambda x: abs(x.ID.StrikePrice - self.underlyingPriceqqq)))[0] if callqqqcontract not in self.callcontractsAddedqqq: self.callcontractsAddedqqq.add(callqqqcontract) # use AddOptionContract() to subscribe the data for specified contract self.AddOptionContract(callqqqcontract, Resolution.Minute) self.Log("QQQ Call contract {0}".format(callqqqcontract)) return callqqqcontract else: return str() def OnOrderEvent(self, orderEvent): self.Log(str(orderEvent))