# Import necessary modules and classes from QuantConnect
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Algorithm")
from System import *
from QuantConnect import *
from QuantConnect.Algorithm import QCAlgorithm
# Import datetime for time-related operations
import pytz
class FairValueGapStrategy(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2020, 1, 1) # Set your backtest start date
self.SetEndDate(2020, 12, 31) # Set your backtest end date
self.SetCash(100000) # Set your starting capital
# Define the symbol to trade (NASDAQ E-mini 100 futures)
self.symbol = "NQ" # Symbol for NASDAQ E-mini 100 futures on QuantConnect
# Define strategy parameters
self.tolerance = 0.02 # Tolerance for equal highs/lows detection
self.risk_percentage = 0.01 # Risk 1% of total account per trade
self.stop_loss_ratio = 0.5 # Stop loss distance as fraction of ATR
self.take_profit_ratio = 1.0 # Take profit distance as multiple of ATR
# Initialize indicators and trade parameters
self.eqh = None
self.eql = None
self.entry_price = None
self.stop_loss_price = None
self.take_profit_price = None
self.trade_opened = False
# Schedule function to run every minute
self.Schedule.On(self.DateRules.EveryDay(self.symbol),
self.TimeRules.Every(TimeSpan.FromMinutes(1)),
self.CheckTimeAndTrade)
# Log initializations and strategy parameters
self.Log(f"Starting with symbol: {self.symbol}")
self.Log(f"Strategy parameters: tolerance={self.tolerance}, risk_percentage={self.risk_percentage}, stop_loss_ratio={self.stop_loss_ratio}, take_profit_ratio={self.take_profit_ratio}")
def OnData(self, data):
# Check for end of trading day at 3:31 PM EST
if self.Time.hour == 15 and self.Time.minute == 31:
self.Liquidate(self.symbol)
self.trade_opened = False
self.Log("End of trading day reached. Liquidating all positions.")
# Implement your trading logic here if needed
pass
def CheckTimeAndTrade(self):
# Check if current time is within trading hours (9:32 AM EST to 3:31 PM EST)
if not self.IsWithinTradingHours():
return
# Execute trading logic if no trade is currently open
if not self.trade_opened:
self.CheckTrade()
def IsWithinTradingHours(self):
# Convert current time to New York (Eastern Time)
new_york_tz = pytz.timezone('America/New_York')
eastern_time = self.Time.astimezone(new_york_tz)
# Extract hour and minute components
hour = eastern_time.hour
minute = eastern_time.minute
# Check if current time is within specified trading hours (9:32 AM EST to 3:31 PM EST)
if hour < 9 or (hour == 15 and minute > 31):
return False
elif hour == 9 and minute < 32:
return False
return True
def CheckTrade(self):
# Fetch historical data to analyze (15 minute timeframe)
history_15m = self.History(self.symbol, TimeSpan.FromMinutes(15), Resolution.Minute)
# Convert history_15m to a list to iterate over it
history_15m_list = list(history_15m)
# Check if history_15m_list is empty
if len(history_15m_list) == 0:
self.Log("No historical data available for 15 minute bars.")
return
# Detect equal highs (EQH) and equal lows (EQL) within the last 15 minutes
self.eqh, self.eql = self.DetectEqualHighsLows(history_15m_list)
if self.eqh is not None:
# Bullish scenario: FVG between EQH and current low
fvg_bullish = self.CalculateFairValueGap(self.eqh[1], history_15m_list[-1].Low)
self.Log(f"Bullish FVG: {fvg_bullish}")
if fvg_bullish > 0:
# Enter bullish trade
self.EnterTrade(self.eqh[1], history_15m_list[-1].Low, "bullish")
return # Exit function after entering trade
if self.eql is not None:
# Bearish scenario: FVG between EQL and current high
fvg_bearish = self.CalculateFairValueGap(self.eql[1], history_15m_list[-1].High)
self.Log(f"Bearish FVG: {fvg_bearish}")
if fvg_bearish > 0:
# Enter bearish trade
self.EnterTrade(self.eql[1], history_15m_list[-1].High, "bearish")
return # Exit function after entering trade
def DetectEqualHighsLows(self, history):
eqh = None
eql = None
for i in range(1, len(history)):
if abs(history[i].High - history[i - 1].High) < self.tolerance:
eqh = history[i].Time, history[i].High
if abs(history[i].Low - history[i - 1].Low) < self.tolerance:
eql = history[i].Time, history[i].Low
return eqh, eql
def CalculateFairValueGap(self, reference_price, current_price):
return current_price - reference_price
def EnterTrade(self, entry_price, reference_price, direction):
self.entry_price = entry_price
stop_loss_distance = abs(entry_price - reference_price)
take_profit_distance = abs(reference_price - entry_price)
self.stop_loss_price = entry_price - stop_loss_distance * self.stop_loss_ratio
self.take_profit_price = entry_price + take_profit_distance * self.take_profit_ratio
risk_amount = self.Portfolio.TotalPortfolioValue * self.risk_percentage
position_size = int(risk_amount / stop_loss_distance)
if direction == "bullish":
self.SetHoldings(self.symbol, position_size)
elif direction == "bearish":
self.SetHoldings(self.symbol, -position_size)
self.trade_opened = True
self.Log(f"Trade entered. Entry={self.entry_price}, StopLoss={self.stop_loss_price}, TakeProfit={self.take_profit_price}, Direction={direction}")
# End of FairValueGapStrategy class