Overall Statistics |
Total Trades 2407 Average Win 0.47% Average Loss -0.51% Compounding Annual Return -4.299% Drawdown 58.400% Expectancy -0.056 Net Profit -12.993% Sharpe Ratio 0.124 Probabilistic Sharpe Ratio 3.878% Loss Rate 51% Win Rate 49% Profit-Loss Ratio 0.92 Alpha 0.011 Beta 0.295 Annual Standard Deviation 0.423 Annual Variance 0.179 Information Ratio -0.198 Tracking Error 0.442 Treynor Ratio 0.177 Total Fees $6706.25 Estimated Strategy Capacity $0 |
class CalculatingYellowGreenAnguilline(QCAlgorithm): def Initialize(self): self.SetStartDate(2018, 1, 1) self.SetEndDate(2021, 3, 1) self.initialCash = 1000000 self.SetCash(self.initialCash) # Take profit after our portfolio profit/loss is greater than this percentage self.takeProfitPercent = 0.05 # Liquidate our portfolio when our profit/loss drops below this percentage self.stopLossPercent = -0.20 self.lastTraded = datetime(1, 1, 1) # CL Futures with expiries between 30 and 90 days cl = self.AddFuture("CL", Resolution.Minute, Market.NYMEX) cl.SetFilter(30, 90) self.AddFutureOption(cl.Symbol, self.FilterFuturesOptionsContracts) # EMA indicators keyed by future option symbol self.ema = {} # Used to store Symbols with matching strike prices self.futureOptionCache = {} def FilterFuturesOptionsContracts(self, filterUniverse): return filterUniverse.Strikes(-1, 1) def OnData(self, data): # Check if all indicators are warmed up before we continue if not self.AllIndicatorsReady(): return # Only trade once a day if self.Time - self.lastTraded < timedelta(days=1): return pnlPercent = self.Portfolio.TotalUnrealizedProfit / self.initialCash if pnlPercent >= self.takeProfitPercent or pnlPercent <= self.stopLossPercent: self.Liquidate() self.lastTraded = self.Time return expiring_options = [] for symbol, emas in self.ema.items(): # Loop on call options if symbol.ID.OptionRight == OptionRight.Put: continue # Remove contracts close to expiry from our portfolio if symbol.ID.Date - self.Time <= timedelta(days=30): self.Liquidate(symbol) self.Liquidate(symbol.Underlying) self.Debug(f'Removing {symbol} due to impending expiry (15 days)') expiring_options.append(symbol) continue # Slow and fast EMA (2 hours/6 hours) indicators for the call option slow = emas[0] fast = emas[1] call = symbol put = self.InvertOption(symbol) if fast > slow and self.Portfolio[put].Quantity >= 0: self.Liquidate(put) self.MarketOrder(symbol, 1) self.lastTraded = self.Time elif fast > slow and self.Portfolio[call].Quantity >= 0: self.Liquidate(call) self.MarketOrder(put, 1) self.lastTraded = self.Time # Remove all options we won't trade anymore from the # indicators dictionary we created for symbol in expiring_options: del self.ema[symbol] def AllIndicatorsReady(self): ''' Checks if all indicators are ready to be used ''' for symbol in self.ema: for indicator in self.ema[symbol]: if not indicator.IsReady: return False return True def OnSecuritiesChanged(self, changes): ''' When any future or future option is added to the algorithm, this method will execute. For added futures options, we setup EMA indicators (slow/fast) for them. For removed futures options, we remove them from the dictionary of EMA indicators ''' for security in changes.AddedSecurities: symbol = security.Symbol if symbol.SecurityType != SecurityType.FutureOption: continue if symbol not in self.ema: self.ema[symbol] = [] emas = self.ema[symbol] if len(emas) == 0: emas.append(self.EMA(symbol, 120, Resolution.Minute)) emas.append(self.EMA(symbol, 360, Resolution.Minute)) for security in changes.RemovedSecurities: symbol = security.Symbol if symbol in self.ema: del self.ema[symbol] def InvertOption(self, symbol): ''' Converts a call option symbol to a put option symbol, and vice versa. ''' if symbol not in self.futureOptionCache: self.futureOptionCache[symbol] = {} cache = self.futureOptionCache[symbol] strike = symbol.ID.StrikePrice right = symbol.ID.OptionRight if strike not in cache: # Adds both calls and puts to the collection cache[strike] = [ symbol, Symbol.CreateOption( symbol.Underlying, symbol.ID.Market, symbol.ID.OptionStyle, OptionRight.Put if right == OptionRight.Call else OptionRight.Call, symbol.ID.StrikePrice, symbol.ID.Date) ] for option in cache[strike]: if right != option.ID.OptionRight: return option