Overall Statistics |
Total Trades 5020 Average Win 0.65% Average Loss -0.33% Compounding Annual Return 123.069% Drawdown 16.500% Expectancy 0.137 Net Profit 186.567% Sharpe Ratio 3.121 Probabilistic Sharpe Ratio 96.575% Loss Rate 62% Win Rate 38% Profit-Loss Ratio 1.97 Alpha 0 Beta 0 Annual Standard Deviation 0.256 Annual Variance 0.066 Information Ratio 3.121 Tracking Error 0.256 Treynor Ratio 0 Total Fees $10793.00 Estimated Strategy Capacity $13000000.00 Lowest Capacity Asset NQ Y9CDFY0C6TXD Portfolio Turnover 1285.80% |
#region imports import pytz from AlgorithmImports import * from datetime import time #endregion class SimpleNQExample(QCAlgorithm): def Initialize(self): self.SetStartDate(2022, 1, 1) # Set Start Date self.SetEndDate(2023, 4, 25) self.SetCash(100000) # Set Strategy Cash self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin) self.SetTimeZone("America/New_York") # Set up the future we're looking at future = Futures.Indices.NASDAQ100EMini self._continuousContract = self.AddFuture(future, dataNormalizationMode = DataNormalizationMode.BackwardsRatio, dataMappingMode = DataMappingMode.OpenInterest, contractDepthOffset = 0, extendedMarketHours = True) self.commod = self._continuousContract.Symbol self._continuousContract.SetFilter(timedelta(days=1), timedelta(days=60)) # Set up a 10-period EMA on 5-minute bars self._10ema = ExponentialMovingAverage(10) self.previous_10ema = None # Add a variable to store the previous 10EMA value # Set up a 500-period EMA on 5-minute bars self._500ema = ExponentialMovingAverage(500) self.previous_500ema = None # Add a variable to store the previous 10EMA value # Set up a 14-period RSI on 5-minute bars self._rsi = RelativeStrengthIndex(12) self._5sma_rsi = SimpleMovingAverage(5) self.previous_5sma_rsi = None # Set up a MACD indicator on 5-minute bars self._macd = MovingAverageConvergenceDivergence(26, 100, 9) self.previous_macd_histogram = None # Set up a Momentum indicator on 5-minute bars self._momentum = Momentum(9) self._5ema_mom = ExponentialMovingAverage(3) self.previous_5ema_mom = None # Set up an Ultimate Oscillator indicator on 5-minute bars self._ultimate_oscillator = UltimateOscillator(7, 14, 28) self._5ema_UA = ExponentialMovingAverage(3) self.previous_5ema_UA = None # Set up a 9-period EMA on 1-minute bars self._9ema = ExponentialMovingAverage(3) self.previous_9ema = None # Add a variable to store the previous 9EMA value # Now the handler for that consolidator self.MyConsHandler = [] self.MyConsHandler.append(self.Consolidate(self.commod, timedelta(minutes=5), self._5BarHandler)) # Add a 1-minute consolidator self.MyConsHandler.append(self.Consolidate(self.commod, timedelta(minutes=1), self._1BarHandler)) self.slope9 = dict() self.slope9[0] = 0 self.slope = dict() self.slope[0] = 0 self.slope2 = dict() self.slope2[0] = 0 self.slope500 = dict() self.slope500[0] = 0 self.slope_rsi = dict() self.slope_rsi[0] = 0 self.slope_rsi2 = dict() self.slope_rsi2[0] = 0 self.slope_macd_histogram = dict() self.slope_macd_histogram[0] = 0 self.slope_macd_histogram2 = dict() self.slope_macd_histogram2[0] = 0 self.slope_mom = dict() self.slope_mom[0] = 0 self.slope_mom2 = dict() self.slope_mom2[0] = 0 self.slope_UA = dict() self.slope_UA[0] = 0 self.slope_UA2 = dict() self.slope_UA2[0] = 0 self.firsttradelong = dict() self.firsttradelong[0] = 0 self.firsttradeshort = dict() self.firsttradeshort[0] = 0 self.Schedule.On(self.DateRules.EveryDay(self._continuousContract.Symbol), \ self.TimeRules.At(23, 0), \ Action(self.ResetFirstTrade)) history = self.History(self.commod, 2500, Resolution.Minute) for index, row in history.iterrows(): bar = TradeBar(index[2]-Time.OneMinute, self.commod, row.open, row.high, row.low, row.close, row.volume) # Allow the consolidator to update for consolidator in self.MyConsHandler: consolidator.Update(bar) # Create a chart object for 10EMA and slope ema_slope_chart = Chart("EMA and Slope Chart") ema_slope_chart.AddSeries(Series("10EMA", SeriesType.Line)) ema_slope_chart.AddSeries(Series("Slope", SeriesType.Line)) self.AddChart(ema_slope_chart) def _5BarHandler(self, consolidatedBar): # EMA takes a data point, which is a time and a price self._10ema.Update(consolidatedBar.EndTime, consolidatedBar.Close) # Update 500 EMA self._500ema.Update(consolidatedBar.EndTime, consolidatedBar.Close) # Update RSI self._rsi.Update(consolidatedBar.EndTime, consolidatedBar.Close) # Update MACD self._macd.Update(consolidatedBar.EndTime, consolidatedBar.Close) # Update Momentum self._momentum.Update(consolidatedBar.EndTime, consolidatedBar.Close) # Update 3EMA of Momentum self._5ema_mom.Update(consolidatedBar.EndTime, self._momentum.Current.Value) # Update Ultimate Oscillator self._ultimate_oscillator.Update(consolidatedBar) # Update 3EMA of Ultimate Oscillator self._5ema_UA.Update(consolidatedBar.EndTime, self._ultimate_oscillator.Current.Value) if self._10ema.IsReady and self.previous_10ema is not None: # Calculate the slope self.slope2[0] = self.slope[0] slope = self._10ema.Current.Value - self.previous_10ema self.slope[0] = slope # Plot the 10EMA and slope #self.Plot("EMA and Slope Chart", "10EMA", self._10ema.Current.Value) #self.Plot("EMA and Slope Chart", "Slope", slope) if self._500ema.IsReady and self.previous_500ema is not None: # Calculate the slope slope500 = self._500ema.Current.Value - self.previous_500ema self.slope500[0] = slope500 if self._rsi.IsReady: # Update the 5EMA of RSI self._5sma_rsi.Update(consolidatedBar.EndTime, self._rsi.Current.Value) if self._5sma_rsi.IsReady and self.previous_5sma_rsi is not None: # Calculate the slope of the 5EMA of RSI self.slope_rsi2[0] = self.slope_rsi[0] slope_rsi = self._5sma_rsi.Current.Value - self.previous_5sma_rsi self.slope_rsi[0] = slope_rsi if self._macd.IsReady and self.previous_macd_histogram is not None: # Calculate the slope of the MACD histogram self.slope_macd_histogram2[0] = self.slope_macd_histogram[0] slope_macd_histogram = self._macd.Histogram.Current.Value - self.previous_macd_histogram self.slope_macd_histogram[0] = slope_macd_histogram if self._5ema_mom.IsReady and self.previous_5ema_mom is not None: # Calculate the slope of the 3EMA of momentum indicator self.slope_mom2[0] = self.slope_mom[0] slope_mom = self._5ema_mom.Current.Value - self.previous_5ema_mom self.slope_mom[0] = slope_mom if self._ultimate_oscillator.IsReady: # Update the 3EMA of Ultimate Oscillator self._5ema_UA.Update(consolidatedBar.EndTime, self._ultimate_oscillator.Current.Value) if self._5ema_UA.IsReady and self.previous_5ema_UA is not None: # Calculate the slope of the 3EMA of Ultimate Oscillator self.slope_UA2[0] = self.slope_UA[0] slope_UA = self._5ema_UA.Current.Value - self.previous_5ema_UA self.slope_UA[0] = slope_UA # Update the previous_500ema value after plotting if self._500ema.IsReady: self.previous_500ema = self._500ema.Current.Value # Update the previous_macd_histogram value after plotting if self._macd.IsReady: self.previous_macd_histogram = self._macd.Histogram.Current.Value # Update the previous_10ema value after plotting if self._10ema.IsReady: self.previous_10ema = self._10ema.Current.Value # Update the previous_5ema_rsi value after plotting if self._5sma_rsi.IsReady: self.previous_5sma_rsi = self._5sma_rsi.Current.Value # Update the previous_5ema_mom value after plotting if self._5ema_mom.IsReady: self.previous_5ema_mom = self._5ema_mom.Current.Value # Update the previous_5ema_UA value after plotting if self._5ema_UA.IsReady: self.previous_5ema_UA = self._5ema_UA.Current.Value #self.Log("10EMA: {0}, 10 EMA slope: {1}, 500 EMA: {2}, RSI5sma: {3}".format(round(self._10ema.Current.Value, 2), round(self.slope[0], 2), round(self._500ema.Current.Value, 2), round(self._5sma_rsi.Current.Value, 2))) def _1BarHandler(self, consolidatedBar): # EMA takes a data point, which is a time and a price self._9ema.Update(consolidatedBar.EndTime, consolidatedBar.Close) if self._9ema.IsReady and self.previous_9ema is not None: # Calculate the slope slope9 = self._9ema.Current.Value - self.previous_9ema self.slope9[0] = slope9 # Update the previous_9ema value after plotting if self._9ema.IsReady: self.previous_9ema = self._9ema.Current.Value def ResetFirstTrade(self): self.firsttradelong[0] = 0 self.firsttradeshort[0] = 0 def OnData(self, data: Slice): if not data.ContainsKey(self.commod): return if self.previous_10ema is None or not self._10ema.IsReady: return slope = self.slope[0] slope_rsi = self.slope_rsi[0] slope_macd_histogram = self.slope_macd_histogram[0] slope500 = self.slope500[0] slope2 = self.slope2[0] slope_rsi2 = self.slope_rsi2[0] slope_macd_histogram2 = self.slope_macd_histogram2[0] slope9 = self.slope9[0] momslope = self.slope_mom[0] momslope2 = self.slope_mom2[0] UAslope = self.slope_UA[0] UAslope2 = self.slope_UA2[0] futures_invested = [holding.Symbol for holding in self.Portfolio.Values if holding.Type == SecurityType.Future and holding.Invested] futures_invested_short = [(symbol, holding.Quantity) for symbol, holding in self.Portfolio.items() if holding.Type == SecurityType.Future and holding.Symbol.SecurityType == SecurityType.Future and holding.IsShort] futures_invested_long = [(symbol, holding.Quantity) for symbol, holding in self.Portfolio.items() if holding.Type == SecurityType.Future and holding.Symbol.SecurityType == SecurityType.Future and holding.IsLong] futures_invested_long1 = [symbol for symbol, holding in self.Portfolio.items() if holding.Type == SecurityType.Future and holding.Symbol.SecurityType == SecurityType.Future and holding.IsLong] futures_invested_short1 = [symbol for symbol, holding in self.Portfolio.items() if holding.Type == SecurityType.Future and holding.Symbol.SecurityType == SecurityType.Future and holding.IsShort] current_time = self.Time.time() trading_start = time(8, 0) trading_end = time(19, 30) #trading_allowed = trading_start <= current_time <= trading_end trading_not_allowed = current_time > trading_end trading_allowed = trading_start <= current_time <= trading_end and self.Time.weekday() != 6 if slope500 > 0 and trading_allowed: if slope > 0 and slope_rsi > 0 and slope9 > 0 and momslope > 0 and UAslope > 0 and not futures_invested_long1: if self.firsttradelong[0] == 0: self.firsttradelong[0] = 1 self.firsttradeshort[0] = 2 if self.firsttradelong[0] == 2: # Liquidate short positions if any for symbol, quantity in futures_invested_short: self.MarketOrder(symbol, -quantity) # Liquidate the short position self.Log("futures invested: {0}, Long {1}, Short {2}".format(futures_invested, futures_invested_long, futures_invested_short)) self.MarketOrder(self._continuousContract.Mapped, 1) self.Log("Going long") self.firsttradeshort[0] = 2 if slope < 0 and slope_rsi < 0 and slope9 < 0 and momslope < 0 and UAslope < 0 and not futures_invested_short1: if slope2 < 0 and slope_rsi2 < 0 and momslope2 < 0 and UAslope2 < 0: if self.firsttradeshort[0] == 0: self.firsttradeshort[0] = 1 self.firsttradelong[0] = 2 if self.firsttradeshort[0] == 2: for symbol, quantity in futures_invested_long: self.MarketOrder(symbol, -quantity) self.Log("futures invested: {0}, Long {1}, Short {2}".format(futures_invested, futures_invested_long, futures_invested_short)) self.MarketOrder(self._continuousContract.Mapped, -1) self.Log("Going short") self.firsttradelong[0] = 2 if slope500 < 0 and trading_allowed: if slope < 0 and slope_rsi < 0 and slope9 < 0 and momslope < 0 and UAslope < 0 and not futures_invested_short1: if self.firsttradeshort[0] == 0: self.firsttradeshort[0] = 1 self.firsttradelong[0] = 2 if self.firsttradeshort[0] == 2: for symbol, quantity in futures_invested_long: self.MarketOrder(symbol, -quantity) self.Log("futures invested: {0}, Long {1}, Short {2}".format(futures_invested, futures_invested_long, futures_invested_short)) self.MarketOrder(self._continuousContract.Mapped, -1) self.Log("Going short") self.firsttradelong[0] = 2 if slope > 0 and slope_rsi > 0 and slope9 > 0 and momslope > 0 and UAslope > 0 and not futures_invested_long1: if slope2 > 0 and slope_rsi2 > 0 and momslope2 > 0 and UAslope2 > 0: if self.firsttradelong[0] == 0: self.firsttradelong[0] = 1 self.firsttradeshort[0] = 2 if self.firsttradelong[0] == 2: # Liquidate short positions if any for symbol, quantity in futures_invested_short: self.MarketOrder(symbol, -quantity) # Liquidate the short position self.Log("futures invested: {0}, Long {1}, Short {2}".format(futures_invested, futures_invested_long, futures_invested_short)) self.MarketOrder(self._continuousContract.Mapped, 1) self.Log("Going long") self.firsttradeshort[0] = 2 if slope500 > 0 and trading_not_allowed: if slope > 0 and slope_rsi > 0 and slope9 > 0 and momslope > 0 and UAslope > 0 and not futures_invested_long1: # Liquidate short positions if any for symbol, quantity in futures_invested_short: self.MarketOrder(symbol, -quantity) # Liquidate the short position if slope < 0 and slope_rsi < 0 and slope9 < 0 and momslope < 0 and UAslope < 0 and not futures_invested_short1: if slope2 < 0 and slope_rsi2 < 0 and momslope2 < 0 and UAslope2 < 0: for symbol, quantity in futures_invested_long: self.MarketOrder(symbol, -quantity) if slope500 < 0 and trading_not_allowed: if slope < 0 and slope_rsi < 0 and slope9 < 0 and momslope < 0 and UAslope < 0 and not futures_invested_short1: for symbol, quantity in futures_invested_long: self.MarketOrder(symbol, -quantity) if slope > 0 and slope_rsi > 0 and slope9 > 0 and momslope > 0 and UAslope > 0 and not futures_invested_long1: if slope2 > 0 and slope_rsi2 > 0 and momslope2 > 0 and UAslope2 > 0: # Liquidate short positions if any for symbol, quantity in futures_invested_short: self.MarketOrder(symbol, -quantity) # Liquidate the short position friday_close_time = time(16, 58) if self.Time.weekday() == 4 and current_time == friday_close_time: for symbol in futures_invested: self.MarketOrder(symbol, -self.Portfolio[symbol].Quantity) # Liquidate the position