| 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