//+------------------------------------------------------------------+
//| ICT Enhanced Version.mq4 |
//| Based on Michael Huddleston Model |
//+------------------------------------------------------------------+
#property copyright ""
#property link ""
#property version "1.00"
#property strict
#property indicator_chart_window
#property indicator_buffers 18
// Indicator buffers for drawing
double LondonHighBuffer[];
double LondonLowBuffer[];
double NYHighBuffer[];
double NYLowBuffer[];
double FVGHighBuffer[];
double FVGLowBuffer[];
double DailyBiasBuffer[];
double AsianHighBuffer[];
double AsianLowBuffer[];
double BuySignalBuffer[];
double SellSignalBuffer[];
double BullishPatternBuffer[];
double BearishPatternBuffer[];
double BullishDivergenceBuffer[];
double BearishDivergenceBuffer[];
double adxBuffer[];
// Indicator buffers for market regime detection
double upperBBBuffer[];
double lowerBBBuffer[];
// New buffer for RSI values
double RSIValues[];
// Input parameters
input color RangeColor = clrYellow; // Range High/Low Color
input color AsianColor = clrPurple; // Asian Session High/Low Color
input color LondonColor = clrRed; // London Session High/Low Color
input color NYColor = clrBlue; // NY Session High/Low Color
input color FVGColor = clrLightGreen; // Fair Value Gap Color
input color BiasColor = clrMagenta; // Daily Bias Arrow Color
input bool ShowAsianFibo = true; // Show Asian Session Fibonacci
Retracement
input bool ShowLondonFibo = true; // Show London Session Fibonacci
Retracement
input bool ShowNYFibo = true; // Show NY Session Fibonacci Retracement
input bool ShowSessions = true; // Show Session Lines
input bool ShowFVG = true; // Show Fair Value Gaps
input bool ShowFibo = true; // Show Fibonacci Retracements
input bool ShowDailyBias = true; // Show Daily Bias Calculation
input int DailyBiasPeriod = 20; // Daily Bias Calculation Period
input bool AlertsOn = false; // Enable Alerts
input int GMT_Offset = 0; // Manual GMT Offset (used only if
AutoDetectGMT=false)
input bool UseLocalTime = false; // Use local PC time instead of server
time
input bool AutoDetectGMT = true; // Automatically detect GMT offset
input double BiasThresholdMultiplier = 1.0; // Bias threshold sensitivity (0.5-2.0)
input string GoldBiasParams = "--------- XAUUSD-Specific Bias Settings
---------"; // Separator
input bool UseGoldOptimizedSettings = false;// Use Gold-Optimized Bias Calculation
input double EMAAlignmentWeight = 2.0; // EMA Alignment Weight (2.5 recommended
for Gold)
input double MomentumWeight = 0.75; // Momentum Indicator Weight (1.25 for
Gold)
input double USDCorrelationWeight = 0.0; // USD Correlation Factor Weight (1.0
for Gold)
input int ATRPeriod = 14; // ATR Period (20 recommended for Gold)
input double VolatilityMultiplier = 1.5; // Volatility Threshold Multiplier (1.75
for Gold)
input bool IncludeAsianSession = false; // Include Asian Session High/Low
input double PivotPointWeight = 1.0; // Daily Pivot Point Weight (1.25 for
Gold)
input int EMA1Period = 20; // First EMA Period
input int EMA2Period = 50; // Second EMA Period (55 recommended for
Gold)
input int EMA3Period = 200; // Third EMA Period
input bool UseEMA89 = false; // Use Additional EMA 89 for Gold
input double EMA89Weight = 1.0; // EMA 89 Crossing Weight (1.5 for Gold)
input bool UseDXYCorrelation = false; // Use DXY Correlation for Bias
input bool UseRoundNumbers = false; // Consider Round Number
Support/Resistance
input double RoundNumberIncrement = 50.0; // Round Number Increment for Gold
input bool ConsiderPsychLevels = false; // Consider Psychological Price Levels
input int RSIPeriod = 14; // RSI Period (21 recommended for Gold)
input int RSIUpperThreshold = 60; // RSI Upper Threshold (65 for Gold)
input int RSILowerThreshold = 40; // RSI Lower Threshold (35 for Gold)
input double HighConfidenceMultiplier = 1.5;// High Confidence Threshold Multiplier
(1.8 for Gold)
input double MediumConfidenceMultiplier = 1.0;// Medium Confidence Threshold
Multiplier (1.2 for Gold)
// New multi-timeframe parameters
input bool UseTimeframeSpecificSettings = true; // Use different settings for
different timeframes
input int FastTimeframeEMA1 = 10; // EMA1 for 1-5min charts
input int FastTimeframeEMA2 = 20; // EMA2 for 1-5min charts
input int FastTimeframeRSI = 7; // RSI Period for 1-5min charts
input int MediumTimeframeEMA1 = 20; // EMA1 for 15min-1H charts
input int MediumTimeframeEMA2 = 50; // EMA2 for 15min-1H charts
input int MediumTimeframeRSI = 14; // RSI Period for 15min-1H charts
input int SlowTimeframeEMA1 = 50; // EMA1 for 4H-Daily charts
input int SlowTimeframeEMA2 = 200; // EMA2 for 4H-Daily charts
input int SlowTimeframeRSI = 21; // RSI Period for 4H-Daily charts
// Market Regime Detection Parameters
input double TrendStrengthThreshold = 25.0; // ADX threshold for trend strength
input int BBPeriod = 20; // Bollinger Bands period
input double BBDeviation = 2.0; // Bollinger Bands standard deviation
// Price Action Confirmation Parameters
input int PriceActionLookback = 5; // Number of bars to analyze for price action
patterns
input double PinBarMinSize = 0.0005; // Minimum size for pin bars
input double EngulfingMinSize = 0.001; // Minimum size for engulfing patterns
// Multi-Timeframe Alignment Parameters
input int HigherTFPeriod = PERIOD_H4; // Higher timeframe to check alignment
input int LowerTFPeriod = PERIOD_M15; // Lower timeframe to check alignment
// Candlestick Pattern Parameters
input bool ShowCandlestickPatterns = true; // Show candlestick patterns
input int PatternLookback = 5; // Number of recent bars to analyze for patterns
input color BullishPatternColor = clrGreen; // Bullish pattern color
input color BearishPatternColor = clrRed; // Bearish pattern color
// RSI Divergence Parameters
input bool ShowRSIDivergence = true; // Show RSI Divergence
input int RSIDivergencePeriod = 14; // RSI Period for divergence
input int RSIDivergenceLookback = 5; // Lookback period for divergence
input double RSIDivergenceThreshold = 5.0; // Minimum divergence threshold
input color BullishDivergenceColor = clrGreen; // Bullish divergence color
input color BearishDivergenceColor = clrRed; // Bearish divergence color
// Arrow parameters
input color BuyArrowColor = clrGreen;
input color SellArrowColor = clrRed;
input int ArrowSize = 2;
// Time variables
datetime londonOpen, nyOpen, newDayStart;
datetime prevLondonOpen, prevNYOpen, prevAsianOpen;
double londonHigh, londonLow;
double nyHigh, nyLow;
double asianHigh, asianLow;
bool newLondonSession = false;
bool newNYSession = false;
bool newAsianSession = false;
int dailyBias = 0; // 1 for bullish, -1 for bearish, 0 for neutral
int autoGMTOffset = 0; // Auto-detected GMT offset
datetime asianOpen, asianClose; // Add these declarations
// Array to store FVG levels
struct FairValueGap {
datetime time;
double high;
double low;
int direction; // 1 for bullish, -1 for bearish
};
FairValueGap fvgArray[100];
int fvgCount = 0;
// Market regime variables
int marketRegime = 0; // 0 = ranging, 1 = bullish trend, -1 = bearish trend
double adxValue = 0.0;
double upperBB = 0.0;
double lowerBB = 0.0;
double middleBB = 0.0;
double biasThresholdMultiplierValue; // New variable to hold the value
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit() {
// Dynamically resize arrays based on available bars
int rates_total = Bars;
ArrayResize(LondonHighBuffer, rates_total);
ArrayResize(LondonLowBuffer, rates_total);
ArrayResize(NYHighBuffer, rates_total);
ArrayResize(NYLowBuffer, rates_total);
ArrayResize(FVGHighBuffer, rates_total);
ArrayResize(FVGLowBuffer, rates_total);
ArrayResize(DailyBiasBuffer, rates_total);
ArrayResize(AsianHighBuffer, rates_total);
ArrayResize(AsianLowBuffer, rates_total);
ArrayResize(BuySignalBuffer, rates_total);
ArrayResize(SellSignalBuffer, rates_total);
ArrayResize(BullishPatternBuffer, rates_total);
ArrayResize(BearishPatternBuffer, rates_total);
ArrayResize(BullishDivergenceBuffer, rates_total);
ArrayResize(BearishDivergenceBuffer, rates_total);
ArrayResize(adxBuffer, rates_total);
ArrayResize(upperBBBuffer, rates_total);
ArrayResize(lowerBBBuffer, rates_total);
ArrayResize(RSIValues, rates_total);
// Set empty value for proper indicator drawing
SetIndexEmptyValue(0, 0);
SetIndexEmptyValue(1, 0);
SetIndexEmptyValue(2, 0);
SetIndexEmptyValue(3, 0);
SetIndexEmptyValue(4, 0);
SetIndexEmptyValue(5, 0);
SetIndexEmptyValue(6, EMPTY_VALUE);
SetIndexEmptyValue(7, EMPTY_VALUE);
SetIndexEmptyValue(8, 0);
SetIndexEmptyValue(9, EMPTY_VALUE);
SetIndexEmptyValue(10, EMPTY_VALUE);
SetIndexEmptyValue(11, EMPTY_VALUE);
SetIndexEmptyValue(12, EMPTY_VALUE);
SetIndexEmptyValue(13, EMPTY_VALUE);
SetIndexEmptyValue(14, EMPTY_VALUE);
SetIndexEmptyValue(15, EMPTY_VALUE);
SetIndexEmptyValue(16, 0); // Added for upperBBBuffer
SetIndexEmptyValue(17, 0); // Added for lowerBBBuffer
// Initialize indicator buffers
SetIndexBuffer(0, LondonHighBuffer);
SetIndexBuffer(1, LondonLowBuffer);
SetIndexBuffer(2, NYHighBuffer);
SetIndexBuffer(3, NYLowBuffer);
SetIndexBuffer(4, FVGHighBuffer);
SetIndexBuffer(5, FVGLowBuffer);
SetIndexBuffer(6, DailyBiasBuffer);
SetIndexBuffer(7, AsianHighBuffer);
SetIndexBuffer(8, AsianLowBuffer);
SetIndexBuffer(9, BuySignalBuffer);
SetIndexBuffer(10, SellSignalBuffer);
SetIndexBuffer(11, BullishPatternBuffer);
SetIndexBuffer(12, BearishPatternBuffer);
SetIndexBuffer(13, BullishDivergenceBuffer);
SetIndexBuffer(14, BearishDivergenceBuffer);
SetIndexBuffer(15, adxBuffer);
SetIndexBuffer(16, upperBBBuffer);
SetIndexBuffer(17, lowerBBBuffer);
// Set indicator line styles
SetIndexStyle(0, DRAW_LINE, STYLE_DASH, 1, LondonColor);
SetIndexStyle(1, DRAW_LINE, STYLE_DASH, 1, LondonColor);
SetIndexStyle(2, DRAW_LINE, STYLE_DASH, 1, NYColor);
SetIndexStyle(3, DRAW_LINE, STYLE_DASH, 1, NYColor);
SetIndexStyle(4, DRAW_HISTOGRAM, STYLE_SOLID, 1, FVGColor);
SetIndexStyle(5, DRAW_HISTOGRAM, STYLE_SOLID, 1, FVGColor);
SetIndexStyle(6, DRAW_ARROW, STYLE_SOLID, 2, BiasColor);
SetIndexStyle(7, DRAW_LINE, STYLE_DASH, 1, AsianColor);
SetIndexStyle(8, DRAW_LINE, STYLE_DASH, 1, AsianColor);
SetIndexStyle(9, DRAW_ARROW, STYLE_SOLID, ArrowSize, BuyArrowColor);
SetIndexStyle(10, DRAW_ARROW, STYLE_SOLID, ArrowSize, SellArrowColor);
SetIndexStyle(11, DRAW_ARROW, STYLE_SOLID, ArrowSize, BullishPatternColor);
SetIndexStyle(12, DRAW_ARROW, STYLE_SOLID, ArrowSize, BearishPatternColor);
SetIndexStyle(13, DRAW_ARROW, STYLE_SOLID, ArrowSize, BullishDivergenceColor);
SetIndexStyle(14, DRAW_ARROW, STYLE_SOLID, ArrowSize, BearishDivergenceColor);
SetIndexStyle(15, DRAW_LINE, STYLE_SOLID, 1, clrGray);
SetIndexStyle(16, DRAW_LINE, STYLE_SOLID, 1, clrGray);
SetIndexStyle(17, DRAW_LINE, STYLE_SOLID, 1, clrGray);
// Set indicator labels
SetIndexLabel(0, "London High");
SetIndexLabel(1, "London Low");
SetIndexLabel(2, "NY High");
SetIndexLabel(3, "NY Low");
SetIndexLabel(4, "FVG High");
SetIndexLabel(5, "FVG Low");
SetIndexLabel(6, "Daily Bias");
SetIndexLabel(7, "Asian High");
SetIndexLabel(8, "Asian Low");
SetIndexLabel(9, "Buy Signal");
SetIndexLabel(10, "Sell Signal");
SetIndexLabel(11, "Bullish Pattern");
SetIndexLabel(12, "Bearish Pattern");
SetIndexLabel(13, "Bullish RSI Divergence");
SetIndexLabel(14, "Bearish RSI Divergence");
SetIndexLabel(15, "ADX");
SetIndexLabel(16, "Upper Bollinger Band");
SetIndexLabel(17, "Lower Bollinger Band");
// Parameter validation
biasThresholdMultiplierValue = BiasThresholdMultiplier;
if (biasThresholdMultiplierValue < 0.5 || biasThresholdMultiplierValue > 2.0) {
Alert("Error: BiasThresholdMultiplier out of range. Resetting to 1.0.");
biasThresholdMultiplierValue = 1.0;
}
// Precompute session times
static datetime lastSessionCalculation = 0;
datetime currentTime = TimeCurrent();
if (IsNewDay(currentTime, lastSessionCalculation)) {
CalculateSessionTimes();
lastSessionCalculation = currentTime;
}
// Auto-detect GMT offset if enabled
if (AutoDetectGMT) {
DetectGMTOffset();
} else {
autoGMTOffset = GMT_Offset;
}
// Initialize time variables
CalculateSessionTimes();
// Set up timer for optimal refreshing
EventSetTimer(60); // Refresh every 60 seconds
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Auto-detect GMT offset based on broker server time |
//+------------------------------------------------------------------+
void DetectGMTOffset() {
// Get current UTC time
datetime utcTime = TimeGMT();
// Get current server time
datetime serverTime = TimeCurrent();
// Calculate the difference in hours
int diffSeconds = (int)(serverTime - utcTime);
autoGMTOffset = (int)MathRound(diffSeconds / 3600.0);
// Display detected GMT offset
Print("Auto-detected GMT offset: ", autoGMTOffset);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[]) {
static datetime lastCalculationTime = 0;
static int lastRatesTotal = 0;
datetime currentTime = time[0];
// Detect timeframe change or significant data change
if (rates_total != lastRatesTotal) {
// Resize all buffers to match the new number of bars
ArrayResize(LondonHighBuffer, rates_total);
ArrayResize(LondonLowBuffer, rates_total);
ArrayResize(NYHighBuffer, rates_total);
ArrayResize(NYLowBuffer, rates_total);
ArrayResize(FVGHighBuffer, rates_total);
ArrayResize(FVGLowBuffer, rates_total);
ArrayResize(DailyBiasBuffer, rates_total);
ArrayResize(AsianHighBuffer, rates_total);
ArrayResize(AsianLowBuffer, rates_total);
ArrayResize(BuySignalBuffer, rates_total);
ArrayResize(SellSignalBuffer, rates_total);
ArrayResize(BullishPatternBuffer, rates_total);
ArrayResize(BearishPatternBuffer, rates_total);
ArrayResize(BullishDivergenceBuffer, rates_total);
ArrayResize(BearishDivergenceBuffer, rates_total);
ArrayResize(adxBuffer, rates_total);
ArrayResize(upperBBBuffer, rates_total);
ArrayResize(lowerBBBuffer, rates_total);
ArrayResize(RSIValues, rates_total);
// Reset session variables
newLondonSession = true;
newNYSession = true;
newAsianSession = true;
lastRatesTotal = rates_total;
}
// Only recalculate session times when day changes or on first run
if(IsNewDay(currentTime, lastCalculationTime) || lastCalculationTime == 0) {
if(AutoDetectGMT) {
DetectGMTOffset();
}
CalculateSessionTimes();
lastCalculationTime = currentTime;
}
// Check if we have enough data
if(rates_total < DailyBiasPeriod + 10) return(0);
int limit;
if(prev_calculated > rates_total || prev_calculated <= 0) {
limit = MathMax(0, rates_total - 100); // Calculate only the most recent 100
bars on first load
} else {
limit = MathMax(0, rates_total - prev_calculated); // Calculate only new bars
}
// Calculate Daily Bias
if (ShowDailyBias) {
CalculateDailyBias(rates_total, time, high, low, open, close);
}
// Calculate session ranges and key levels
CalculateRanges(rates_total, time, high, low);
// Find Fair Value Gaps (if enabled)
if (ShowFVG) {
FindFairValueGaps(rates_total, time, high, low, open, close);
}
// Draw levels on the chart
DrawLevels(rates_total, time);
// Check for trading setups based on ICT model
CheckForTradingSetups(rates_total, time, high, low, open, close);
// Detect market regime
DetectMarketRegime(rates_total);
// Draw price action arrows
DrawPriceActionArrows(rates_total, time, open, high, low, close, tick_volume);
// Detect and visualize candlestick patterns
if (ShowCandlestickPatterns) {
DetectAndDrawPatterns(rates_total, time, open, high, low, close);
}
// Calculate and visualize RSI divergence
if (ShowRSIDivergence) {
CalculateRSI(rates_total, time, close);
DetectRSIDivergence(rates_total, time, high, low, close);
}
// Visualize market regime
VisualizeMarketRegime(rates_total, time);
return(rates_total);
}
//+------------------------------------------------------------------+
//| Calculate session times with GMT offset |
//+------------------------------------------------------------------+
void CalculateSessionTimes() {
// Store previous session times
prevLondonOpen = londonOpen;
prevNYOpen = nyOpen;
prevAsianOpen = asianOpen;
// Get current time based on setting
datetime currentTime;
int actualGMTOffset = AutoDetectGMT ? autoGMTOffset : GMT_Offset;
if (UseLocalTime) {
// Use local PC time
currentTime = TimeLocal();
} else {
// Use server time with GMT offset adjustment
currentTime = TimeCurrent() + (actualGMTOffset * 3600);
}
// Calculate midnight in specified time zone
int dayOfWeek = TimeDayOfWeek(currentTime);
datetime midnight = currentTime - TimeHour(currentTime) * 3600
- TimeMinute(currentTime) * 60
- TimeSeconds(currentTime);
// Calculate session times based on GMT offset
// London Open: Standard time is 08:00 AM GMT (03:00 AM EST)
londonOpen = midnight + 8 * 3600;
// NY Open: Standard time is 13:00 PM GMT (08:00 AM EST)
nyOpen = midnight + 13 * 3600;
// Asian Open: Standard time is 00:00 AM GMT (Tokyo session)
asianOpen = midnight;
// Asian Close: Standard time is 08:00 AM GMT (when London opens)
asianClose = londonOpen;
// Start of new day
newDayStart = midnight;
// Reset session flags
newLondonSession = (prevLondonOpen != londonOpen);
newNYSession = (prevNYOpen != nyOpen);
newAsianSession = (prevAsianOpen != asianOpen);
// Initialize session high/low levels
if (newLondonSession) {
londonHigh = 0;
londonLow = 999999;
}
if (newNYSession) {
nyHigh = 0;
nyLow = 999999;
}
if (newAsianSession) {
asianHigh = 0;
asianLow = 999999;
}
// Draw vertical lines for sessions if enabled
if (ShowSessions) {
ObjectDelete("LondonOpen");
ObjectDelete("NYOpen");
ObjectDelete("AsianOpen");
ObjectCreate("LondonOpen", OBJ_VLINE, 0, londonOpen, 0);
ObjectSetInteger(0, "LondonOpen", OBJPROP_COLOR, LondonColor);
ObjectSetInteger(0, "LondonOpen", OBJPROP_STYLE, STYLE_DASH);
ObjectSetInteger(0, "LondonOpen", OBJPROP_WIDTH, 1);
ObjectSetText("LondonOpen", "London Open", 8);
ObjectCreate("NYOpen", OBJ_VLINE, 0, nyOpen, 0);
ObjectSetInteger(0, "NYOpen", OBJPROP_COLOR, NYColor);
ObjectSetInteger(0, "NYOpen", OBJPROP_STYLE, STYLE_DASH);
ObjectSetInteger(0, "NYOpen", OBJPROP_WIDTH, 1);
ObjectSetText("NYOpen", "NY Open", 8);
ObjectCreate("AsianOpen", OBJ_VLINE, 0, asianOpen, 0);
ObjectSetInteger(0, "AsianOpen", OBJPROP_COLOR, AsianColor);
ObjectSetInteger(0, "AsianOpen", OBJPROP_STYLE, STYLE_DASH);
ObjectSetInteger(0, "AsianOpen", OBJPROP_WIDTH, 1);
ObjectSetText("AsianOpen", "Asian Open", 8);
}
// Display time zone information on chart
string timeZoneText = "Time Zone: GMT" + (actualGMTOffset > 0 ? "+" : "") +
IntegerToString(actualGMTOffset) +
(AutoDetectGMT ? " (Auto-detected)" : "") +
(UseLocalTime ? " (Local PC Time)" : " (Server Time)");
ObjectDelete("TimeZoneLabel");
ObjectCreate("TimeZoneLabel", OBJ_LABEL, 0, 0, 0);
ObjectSetText("TimeZoneLabel", timeZoneText, 8, "Arial", clrWhite);
ObjectSet("TimeZoneLabel", OBJPROP_CORNER, 1);
ObjectSet("TimeZoneLabel", OBJPROP_XDISTANCE, 10);
ObjectSet("TimeZoneLabel", OBJPROP_YDISTANCE, 40);
}
//+------------------------------------------------------------------+
//| Calculate Daily Bias with Gold-Optimized Settings |
//+------------------------------------------------------------------+
void CalculateDailyBias(const int rates_total, const datetime &time[],
const double &high[], const double &low[],
const double &open[], const double &close[]) {
double biasScore = 0.0; // Declare biasScore here
// Only recalculate daily bias once per new day
static datetime lastBiasCalc = 0;
static double cachedBiasScore = 0;
// Use cached value if within same day
if(time[0] > 0 && lastBiasCalc > 0 &&
TimeDay(time[0]) == TimeDay(lastBiasCalc) &&
TimeMonth(time[0]) == TimeMonth(lastBiasCalc) &&
TimeYear(time[0]) == TimeYear(lastBiasCalc)) {
// Only recalculate every 30 minutes during trading hours
if(TimeHour(time[0]) == TimeHour(lastBiasCalc) &&
MathAbs(TimeMinute(time[0]) - TimeMinute(lastBiasCalc)) < 30) {
biasScore = cachedBiasScore;
return; // Use cached value
}
}
// Core data points
double dailyOpen = iOpen(Symbol(), PERIOD_D1, 0);
double prevDayHigh = iHigh(Symbol(), PERIOD_D1, 1);
double prevDayLow = iLow(Symbol(), PERIOD_D1, 1);
double weeklyOpen = iOpen(Symbol(), PERIOD_W1, 0);
double monthlyOpen = iOpen(Symbol(), PERIOD_MN1, 0);
// === ASIAN SESSION ANALYSIS (GOLD-SPECIFIC) ===
// Use global variables directly
if (IncludeAsianSession || (UseGoldOptimizedSettings && Symbol() == "XAUUSD")) {
// Calculate Asian session times (approx. 00:00-08:00 GMT)
datetime asianStart = newDayStart;
datetime asianEnd = newDayStart + 8*3600;
// Find Asian session high/low
for (int i = rates_total - 1; i >= 0; i--) {
if (time[i] >= asianStart && time[i] < asianEnd) {
if (high[i] > asianHigh) asianHigh = high[i];
if (low[i] < asianLow) asianLow = low[i];
}
}
}
// === PIVOT POINT CALCULATION ===
double pivot = 0;
double r1 = 0, r2 = 0, s1 = 0, s2 = 0;
if (PivotPointWeight > 0 || (UseGoldOptimizedSettings && Symbol() == "XAUUSD"))
{
// Calculate standard pivot points
double prevHigh = iHigh(Symbol(), PERIOD_D1, 1);
double prevLow = iLow(Symbol(), PERIOD_D1, 1);
double prevClose = iClose(Symbol(), PERIOD_D1, 1);
pivot = (prevHigh + prevLow + prevClose) / 3;
r1 = (2 * pivot) - prevLow;
r2 = pivot + (prevHigh - prevLow);
s1 = (2 * pivot) - prevHigh;
s2 = pivot - (prevHigh - prevLow);
}
// === MULTI-TIMEFRAME ANALYSIS ===
double h4Close = iClose(Symbol(), PERIOD_H4, 0);
double h4MA20 = iMA(Symbol(), PERIOD_H4, EMA1Period, 0, MODE_EMA, PRICE_CLOSE,
0);
// Use appropriate EMA periods based on settings
int ema1Period = EMA1Period;
int ema2Period = EMA2Period;
int ema3Period = EMA3Period;
// For Gold, use optimized EMA settings if specified
if (UseGoldOptimizedSettings && Symbol() == "XAUUSD") {
ema2Period = 55; // Use EMA 55 instead of EMA 50 for gold
}
// Calculate EMAs
double ma20 = iMA(Symbol(), PERIOD_D1, ema1Period, 0, MODE_EMA, PRICE_CLOSE, 0);
double ma50 = iMA(Symbol(), PERIOD_D1, ema2Period, 0, MODE_EMA, PRICE_CLOSE, 0);
double ma200 = iMA(Symbol(), PERIOD_D1, ema3Period, 0, MODE_EMA, PRICE_CLOSE,
0);
// Add EMA 89 for Gold if enabled
double ma89 = 0;
bool aboveEMA89 = false;
if (UseEMA89 || (UseGoldOptimizedSettings && Symbol() == "XAUUSD")) {
ma89 = iMA(Symbol(), PERIOD_D1, 89, 0, MODE_EMA, PRICE_CLOSE, 0);
aboveEMA89 = Close[0] > ma89;
}
// === ENHANCED MARKET STRUCTURE ANALYSIS ===
bool bullishStructure = true;
bool bearishStructure = true;
// Check the last 5 swings for market structure
for (int i = 1; i < 5; i++) {
// Cannot confirm bullish structure if we have a lower low
if (Low[i] < Low[i+1]) bullishStructure = false;
// Cannot confirm bearish structure if we have a higher high
if (High[i] > High[i+1]) bearishStructure = false;
}
// === EMA ALIGNMENT ANALYSIS ===
bool emaAlignment = false;
int emaStrength = 0;
// Apply appropriate EMA alignment weight
double actualEMAWeight = UseGoldOptimizedSettings && Symbol() == "XAUUSD" ?
2.5 : EMAAlignmentWeight;
// Check if EMAs are aligned
if (ma20 > ma50 && ma50 > ma200) {
emaAlignment = true;
emaStrength = 3; // Strong bullish
}
else if (ma20 < ma50 && ma50 < ma200) {
emaAlignment = false;
emaStrength = -3; // Strong bearish
}
else if (ma20 > ma50) {
emaAlignment = true;
emaStrength = 1; // Weak bullish
}
else if (ma20 < ma50) {
emaAlignment = false;
emaStrength = -1; // Weak bearish
}
// === MOMENTUM CONFIRMATION WITH OPTIMIZED RSI SETTINGS ===
int actualRSIPeriod = UseGoldOptimizedSettings && Symbol() == "XAUUSD" ? 21 :
RSIPeriod;
int actualUpperThreshold = UseGoldOptimizedSettings && Symbol() == "XAUUSD" ? 65
: RSIUpperThreshold;
int actualLowerThreshold = UseGoldOptimizedSettings && Symbol() == "XAUUSD" ? 35
: RSILowerThreshold;
// Apply appropriate momentum weight
double actualMomentumWeight = UseGoldOptimizedSettings && Symbol() == "XAUUSD" ?
1.25 : MomentumWeight;
double rsiDaily = iRSI(Symbol(), PERIOD_D1, actualRSIPeriod, PRICE_CLOSE, 0);
// === USD CORRELATION FOR GOLD ===
double usdCorrelation = 0;
if ((UseDXYCorrelation || (UseGoldOptimizedSettings && Symbol() == "XAUUSD")) &&
(Symbol() == "XAUUSD" || Symbol() == "GOLD")) {
// Try to get DXY data - use multiple possible symbols for DXY index
double dxyClose = 0;
double dxyPrevClose = 0;
bool dxyDataFound = false;
string dxySymbols[6] = {"DXY.cash", "USDX", "DXY", "USDIndex", "DOLLAR",
"USD"};
for (int i = 0; i < 5; i++) {
dxyClose = iClose(dxySymbols[i], PERIOD_D1, 0);
dxyPrevClose = iClose(dxySymbols[i], PERIOD_D1, 1);
// If we found a valid DXY symbol
if (dxyClose > 0 && dxyPrevClose > 0) {
dxyDataFound = true;
Print("DXY symbol detected: " + dxySymbols[i]); // This line shows
which symbol was found
break;
}
}
// Calculate USD correlation (negative for gold typically)
if (dxyDataFound) {
double dxyChange = dxyClose - dxyPrevClose;
if (dxyChange > 0) usdCorrelation = -1.0; // Typically negative
correlation
else if (dxyChange < 0) usdCorrelation = 1.0; // Typically positive
correlation
} else {
usdCorrelation = 0.0;
Print("Error: DXY data not found. USD correlation set to neutral.");
}
}
// === ROUND NUMBER ANALYSIS FOR GOLD ===
double roundNumberEffect = 0;
if ((UseRoundNumbers || (UseGoldOptimizedSettings && Symbol() == "XAUUSD")) &&
(Symbol() == "XAUUSD" || Symbol() == "GOLD")) {
double actualIncrement = RoundNumberIncrement;
double currentPrice = Close[0];
// Check proximity to round numbers
double roundedPrice = MathRound(currentPrice / actualIncrement) *
actualIncrement;
double distanceToRound = MathAbs(currentPrice - roundedPrice);
double proximityThreshold = actualIncrement * 0.05; // Within 5% of increment
// Check psychological levels
bool nearPsychLevel = false;
if (ConsiderPsychLevels || (UseGoldOptimizedSettings && Symbol() ==
"XAUUSD")) {
int hundreds = (int)currentPrice / 100;
double psychLevel = hundreds * 100;
double distanceToPsych = MathAbs(currentPrice - psychLevel);
if (distanceToPsych < 5.0) {
nearPsychLevel = true;
}
}
// Adjust bias for round number proximity - can cause reversals
if (distanceToRound < proximityThreshold || nearPsychLevel) {
// Check if approaching from above or below
if (currentPrice > roundedPrice) {
roundNumberEffect = -0.5; // Slight bearish tendency at resistance
} else {
roundNumberEffect = 0.5; // Slight bullish tendency at support
}
}
}
// === CUSTOM ATR VOLATILITY SETTINGS ===
int actualATRPeriod = UseGoldOptimizedSettings && Symbol() == "XAUUSD" ? 20 :
ATRPeriod;
double actualVolMultiplier = UseGoldOptimizedSettings && Symbol() == "XAUUSD" ?
1.75 : VolatilityMultiplier;
double atr = iATR(Symbol(), PERIOD_D1, actualATRPeriod, 0);
double avgATR = 0;
// Calculate average ATR for volatility context
for (int i = 0; i < 5; i++) {
avgATR += iATR(Symbol(), PERIOD_D1, actualATRPeriod, i);
}
avgATR /= 5;
// === COMPREHENSIVE WEIGHTED SCORING SYSTEM ===
// Market structure (highest weight: 2.5)
if (bullishStructure) biasScore += 2.5;
if (bearishStructure) biasScore -= 2.5;
// EMA alignment with custom weight
biasScore += emaStrength * (actualEMAWeight / 3.0); // Scale to actual weight
// EMA89 for gold if enabled
if ((UseEMA89 || (UseGoldOptimizedSettings && Symbol() == "XAUUSD")) && ma89 >
0) {
if (Close[0] > ma89) biasScore += EMA89Weight;
if (Close[0] < ma89) biasScore -= EMA89Weight;
}
// H4 vs Daily EMA (weight: 1.5)
if (h4Close > h4MA20) biasScore += 1.5;
if (h4Close < h4MA20) biasScore -= 1.5;
// Current price vs key levels (weight: 1.0)
if (Close[0] > prevDayHigh) biasScore += 1.0;
if (Close[0] < prevDayLow) biasScore -= 1.0;
// Asian session levels for Gold
if ((IncludeAsianSession || (UseGoldOptimizedSettings && Symbol() == "XAUUSD"))
&&
asianHigh > 0 && asianLow < 999999) {
if (Close[0] > asianHigh) biasScore += 1.0;
if (Close[0] < asianLow) biasScore -= 1.0;
}
// Pivot points with custom weight
if ((PivotPointWeight > 0 || (UseGoldOptimizedSettings && Symbol() == "XAUUSD"))
&& pivot > 0) {
double actualPivotWeight = UseGoldOptimizedSettings && Symbol() == "XAUUSD" ?
1.25 : PivotPointWeight;
if (Close[0] > r1) biasScore += actualPivotWeight;
else if (Close[0] > pivot) biasScore += actualPivotWeight * 0.5;
else if (Close[0] < s1) biasScore -= actualPivotWeight;
else if (Close[0] < pivot) biasScore -= actualPivotWeight * 0.5;
}
// Daily close vs open (weight: 0.75)
if (Close[0] > dailyOpen) biasScore += 0.75;
if (Close[0] < dailyOpen) biasScore -= 0.75;
// Weekly open assessment (weight: 0.5)
if (Close[0] > weeklyOpen) biasScore += 0.5;
if (Close[0] < weeklyOpen) biasScore -= 0.5;
// Monthly open assessment (weight: 0.5)
if (Close[0] > monthlyOpen) biasScore += 0.5;
if (Close[0] < monthlyOpen) biasScore -= 0.5;
// RSI momentum with custom weight and thresholds
if (rsiDaily > actualUpperThreshold) biasScore += actualMomentumWeight;
else if (rsiDaily < actualLowerThreshold) biasScore -= actualMomentumWeight;
// USD correlation for Gold
if ((UseDXYCorrelation || (UseGoldOptimizedSettings && Symbol() == "XAUUSD")) &&
(Symbol() == "XAUUSD" || Symbol() == "GOLD")) {
double actualUSDWeight = UseGoldOptimizedSettings && Symbol() == "XAUUSD" ?
1.0 : USDCorrelationWeight;
biasScore += usdCorrelation * actualUSDWeight;
}
// Round number effect for Gold
biasScore += roundNumberEffect;
// === DYNAMIC THRESHOLD BASED ON VOLATILITY ===
double biasThreshold = 2.0 * biasThresholdMultiplierValue;
// Adjust threshold based on volatility
if (atr > avgATR * actualVolMultiplier) {
// Higher volatility requires stronger signal
biasThreshold *= 1.25;
}
// === OPTIMIZED BIAS CONFIDENCE LEVELS FOR GOLD ===
string confidenceLevel = "";
color biasDisplayColor;
// Use custom confidence multipliers - higher for Gold
double actualHighMultiplier = UseGoldOptimizedSettings && Symbol() == "XAUUSD" ?
1.8 : HighConfidenceMultiplier;
double actualMediumMultiplier = UseGoldOptimizedSettings && Symbol() == "XAUUSD"
? 1.2 : MediumConfidenceMultiplier;
if (biasScore >= biasThreshold * actualHighMultiplier) {
dailyBias = 1; // Strong bullish
confidenceLevel = "HIGH";
biasDisplayColor = clrLime;
}
else if (biasScore >= biasThreshold * actualMediumMultiplier) {
dailyBias = 1; // Bullish
confidenceLevel = "MEDIUM";
biasDisplayColor = clrGreen;
}
else if (biasScore <= -biasThreshold * actualHighMultiplier) {
dailyBias = -1; // Strong bearish
confidenceLevel = "HIGH";
biasDisplayColor = clrRed;
}
else if (biasScore <= -biasThreshold * actualMediumMultiplier) {
dailyBias = -1; // Bearish
confidenceLevel = "MEDIUM";
biasDisplayColor = clrCrimson;
}
else if (biasScore > 0) {
dailyBias = 1; // Weak bullish
confidenceLevel = "LOW";
biasDisplayColor = clrDarkGreen;
}
else if (biasScore < 0) {
dailyBias = -1; // Weak bearish
confidenceLevel = "LOW";
biasDisplayColor = clrMaroon;
}
else {
dailyBias = 0; // Neutral
confidenceLevel = "NEUTRAL";
biasDisplayColor = clrGray;
}
// === ENHANCED DISPLAY WITH GOLD-SPECIFIC INDICATORS ===
string biasDirection = "";
if (dailyBias == 1) biasDirection = "BULLISH";
else if (dailyBias == -1) biasDirection = "BEARISH";
else biasDirection = "NEUTRAL";
string instrumentSpecific = "";
if (UseGoldOptimizedSettings && (Symbol() == "XAUUSD" || Symbol() == "GOLD")) {
instrumentSpecific = " [GOLD-OPTIMIZED]";
}
string biasText = "ICT Daily Bias: " + biasDirection + " (" + confidenceLevel +
")" + instrumentSpecific;
string scoreText = "Bias Score: " + DoubleToString(biasScore, 1) + " |
Threshold: " + DoubleToString(biasThreshold, 1);
// Create label for Daily Bias
ObjectDelete("DailyBiasLabel");
ObjectCreate("DailyBiasLabel", OBJ_LABEL, 0, 0, 0);
ObjectSetText("DailyBiasLabel", biasText, 10, "Arial Bold", biasDisplayColor);
ObjectSet("DailyBiasLabel", OBJPROP_CORNER, 1);
ObjectSet("DailyBiasLabel", OBJPROP_XDISTANCE, 10);
ObjectSet("DailyBiasLabel", OBJPROP_YDISTANCE, 20);
// Create label for Bias Score
ObjectDelete("BiasScoreLabel");
ObjectCreate("BiasScoreLabel", OBJ_LABEL, 0, 0, 0);
ObjectSetText("BiasScoreLabel", scoreText, 8, "Arial", biasDisplayColor);
ObjectSet("BiasScoreLabel", OBJPROP_CORNER, 1);
ObjectSet("BiasScoreLabel", OBJPROP_XDISTANCE, 10);
ObjectSet("BiasScoreLabel", OBJPROP_YDISTANCE, 35);
// Fill buffer for the daily bias indicator
int arrowOffset = (int)(MathMax(10, atr / Point / 2));
for (int i = 0; i < rates_total; i++) {
// Only show bias arrow on current bar
if (i == 0) {
if (dailyBias > 0) {
// Place bullish arrow below the bar
DailyBiasBuffer[i] = Low[i] - arrowOffset * Point;
}
else if (dailyBias < 0) {
// Place bearish arrow above the bar
DailyBiasBuffer[i] = High[i] + arrowOffset * Point;
}
else {
DailyBiasBuffer[i] = 0; // No arrow for neutral
}
} else {
DailyBiasBuffer[i] = 0; // Empty for past bars
}
}
// Update cached values
lastBiasCalc = time[0];
cachedBiasScore = biasScore;
}
//+------------------------------------------------------------------+
//| Calculate session ranges and key levels |
//+------------------------------------------------------------------+
void CalculateRanges(const int rates_total, const datetime &time[],
const double &high[], const double &low[]) {
static datetime lastRangeCalc = 0;
// Only recalculate if new bar or new session
if(time[0] == lastRangeCalc && !newLondonSession && !newNYSession && !
newAsianSession) {
// Just update current session if needed
if(time[0] >= londonOpen && time[0] < nyOpen) {
if(high[0] > londonHigh) londonHigh = high[0];
if(low[0] < londonLow) londonLow = low[0];
} else if(time[0] >= nyOpen) {
if(high[0] > nyHigh) nyHigh = high[0];
if(low[0] < nyLow) nyLow = low[0];
} else if(time[0] >= asianOpen && time[0] < asianClose) {
if(high[0] > asianHigh) asianHigh = high[0];
if(low[0] < asianLow) asianLow = low[0];
} else if(time[0] >= newDayStart && time[0] < londonOpen) {
// No range calculation needed since we removed full daily range
}
} else {
// Full recalculation
// Update London session high/low
for (int i = rates_total - 1; i >= 0; i--) {
if (time[i] >= londonOpen && time[i] < nyOpen) {
if (high[i] > londonHigh) londonHigh = high[i];
if (low[i] < londonLow) londonLow = low[i];
}
}
// Update NY session high/low
for (int i = rates_total - 1; i >= 0; i--) {
if (time[i] >= nyOpen) {
if (high[i] > nyHigh) nyHigh = high[i];
if (low[i] < nyLow) nyLow = low[i];
}
}
// Update Asian session high/low
for (int i = rates_total - 1; i >= 0; i--) {
if (time[i] >= asianOpen && time[i] < asianClose) {
if (high[i] > asianHigh) asianHigh = high[i];
if (low[i] < asianLow) asianLow = low[i];
}
}
}
// Fill buffer values for the levels
for (int i = 0; i < rates_total; i++) {
if (time[i] >= londonOpen) {
LondonHighBuffer[i] = londonHigh;
LondonLowBuffer[i] = londonLow;
}
if (time[i] >= nyOpen) {
NYHighBuffer[i] = nyHigh;
NYLowBuffer[i] = nyLow;
}
if (time[i] >= asianOpen) {
AsianHighBuffer[i] = asianHigh;
AsianLowBuffer[i] = asianLow;
}
}
// Update calculation timestamp
lastRangeCalc = time[0];
}
//+------------------------------------------------------------------+
//| Find Fair Value Gaps |
//+------------------------------------------------------------------+
void FindFairValueGaps(const int rates_total, const datetime &time[],
const double &high[], const double &low[],
const double &open[], const double &close[]) {
// Reset FVG buffers
ArrayInitialize(FVGHighBuffer, EMPTY_VALUE);
ArrayInitialize(FVGLowBuffer, EMPTY_VALUE);
// Reset FVG count
fvgCount = 0;
// Only scan the most recent 100 bars for FVGs
int startBar = MathMin(rates_total-1, 100);
// Look for FVGs in the recent data
for (int i = 2; i < startBar; i++) {
// Bullish FVG: Low[i] > High[i+2]
if (low[i] > high[i+2]) {
// Store the FVG
if(fvgCount < 100) {
fvgArray[fvgCount].time = time[i+1];
fvgArray[fvgCount].high = low[i];
fvgArray[fvgCount].low = high[i+2];
fvgArray[fvgCount].direction = 1; // Bullish
fvgCount++;
}
// Fill the buffer for only the relevant bars
for (int j = 0; j <= MathMin(i+1, rates_total - 1); j++) {
FVGHighBuffer[j] = low[i];
FVGLowBuffer[j] = high[i+2];
}
}
// Bearish FVG: High[i] < Low[i+2]
if (high[i] < low[i+2]) {
// Store the FVG
if(fvgCount < 100) {
fvgArray[fvgCount].time = time[i+1];
fvgArray[fvgCount].high = low[i+2];
fvgArray[fvgCount].low = high[i];
fvgArray[fvgCount].direction = -1; // Bearish
fvgCount++;
}
// Fill the buffer for only the relevant bars
for (int j = 0; j <= MathMin(i+1, rates_total - 1); j++) {
FVGHighBuffer[j] = low[i+2];
FVGLowBuffer[j] = high[i];
}
}
// Optimize by limiting calculation to only most relevant FVGs
if (fvgCount >= 5) break;
}
}
//+------------------------------------------------------------------+
//| Draw levels on the chart |
//+------------------------------------------------------------------+
void DrawLevels(const int rates_total, const datetime &time[]) {
// Draw Fibonacci levels if enabled
if (ShowFibo) {
// Draw Fibonacci from London session low to high if both exist
if (ShowLondonFibo && londonHigh > 0 && londonLow < 999999) {
string fiboName = "LondonFibo";
ObjectDelete(fiboName);
ObjectCreate(fiboName, OBJ_FIBO, 0, londonOpen, londonLow, nyOpen,
londonHigh);
ObjectSetInteger(0, fiboName, OBJPROP_COLOR, LondonColor);
ObjectSetInteger(0, fiboName, OBJPROP_STYLE, STYLE_SOLID);
ObjectSetInteger(0, fiboName, OBJPROP_WIDTH, 1);
// Set Fibonacci levels for ICT Optimal Trade Entry (OTE)
ObjectSetDouble(0, fiboName, OBJPROP_LEVELVALUE, 0, 0.0);
ObjectSetDouble(0, fiboName, OBJPROP_LEVELVALUE, 1, 0.382);
ObjectSetDouble(0, fiboName, OBJPROP_LEVELVALUE, 2, 0.5);
ObjectSetDouble(0, fiboName, OBJPROP_LEVELVALUE, 3, 0.618);
ObjectSetDouble(0, fiboName, OBJPROP_LEVELVALUE, 4, 0.786);
ObjectSetDouble(0, fiboName, OBJPROP_LEVELVALUE, 5, 1.0);
// Set level descriptions
ObjectSetString(0, fiboName, OBJPROP_LEVELTEXT, 0, "0.0");
ObjectSetString(0, fiboName, OBJPROP_LEVELTEXT, 1, "38.2% - OTE Zone");
ObjectSetString(0, fiboName, OBJPROP_LEVELTEXT, 2, "50.0% - OTE Zone");
ObjectSetString(0, fiboName, OBJPROP_LEVELTEXT, 3, "61.8% - OTE Zone");
ObjectSetString(0, fiboName, OBJPROP_LEVELTEXT, 4, "78.6% - OTE Zone");
ObjectSetString(0, fiboName, OBJPROP_LEVELTEXT, 5, "100.0%");
// Add tooltip
ObjectSetString(0, fiboName, OBJPROP_TOOLTIP, "Fibonacci retracement
levels for session ranges.");
}
// Draw Fibonacci from NY session low to high if both exist
if (ShowNYFibo && nyHigh > 0 && nyLow < 999999) {
string fiboName = "NYFibo";
ObjectDelete(fiboName);
ObjectCreate(fiboName, OBJ_FIBO, 0, nyOpen, nyLow, Time[0], nyHigh);
ObjectSetInteger(0, fiboName, OBJPROP_COLOR, NYColor);
ObjectSetInteger(0, fiboName, OBJPROP_STYLE, STYLE_SOLID);
ObjectSetInteger(0, fiboName, OBJPROP_WIDTH, 1);
// Set Fibonacci levels for ICT Optimal Trade Entry (OTE)
ObjectSetDouble(0, fiboName, OBJPROP_LEVELVALUE, 0, 0.0);
ObjectSetDouble(0, fiboName, OBJPROP_LEVELVALUE, 1, 0.382);
ObjectSetDouble(0, fiboName, OBJPROP_LEVELVALUE, 2, 0.5);
ObjectSetDouble(0, fiboName, OBJPROP_LEVELVALUE, 3, 0.618);
ObjectSetDouble(0, fiboName, OBJPROP_LEVELVALUE, 4, 0.786);
ObjectSetDouble(0, fiboName, OBJPROP_LEVELVALUE, 5, 1.0);
// Set level descriptions
ObjectSetString(0, fiboName, OBJPROP_LEVELTEXT, 0, "0.0");
ObjectSetString(0, fiboName, OBJPROP_LEVELTEXT, 1, "38.2% - OTE Zone");
ObjectSetString(0, fiboName, OBJPROP_LEVELTEXT, 2, "50.0% - OTE Zone");
ObjectSetString(0, fiboName, OBJPROP_LEVELTEXT, 3, "61.8% - OTE Zone");
ObjectSetString(0, fiboName, OBJPROP_LEVELTEXT, 4, "78.6% - OTE Zone");
ObjectSetString(0, fiboName, OBJPROP_LEVELTEXT, 5, "100.0%");
// Add tooltip
ObjectSetString(0, fiboName, OBJPROP_TOOLTIP, "Fibonacci retracement
levels for session ranges.");
}
// Draw Fibonacci from Asian session low to high if both exist
if (ShowAsianFibo && asianHigh > 0 && asianLow < 999999) {
string fiboName = "AsianFibo";
ObjectDelete(fiboName);
ObjectCreate(fiboName, OBJ_FIBO, 0, asianOpen, asianLow, asianClose,
asianHigh);
ObjectSetInteger(0, fiboName, OBJPROP_COLOR, AsianColor);
ObjectSetInteger(0, fiboName, OBJPROP_STYLE, STYLE_SOLID);
ObjectSetInteger(0, fiboName, OBJPROP_WIDTH, 1);
// Set Fibonacci levels for ICT Optimal Trade Entry (OTE)
ObjectSetDouble(0, fiboName, OBJPROP_LEVELVALUE, 0, 0.0);
ObjectSetDouble(0, fiboName, OBJPROP_LEVELVALUE, 1, 0.382);
ObjectSetDouble(0, fiboName, OBJPROP_LEVELVALUE, 2, 0.5);
ObjectSetDouble(0, fiboName, OBJPROP_LEVELVALUE, 3, 0.618);
ObjectSetDouble(0, fiboName, OBJPROP_LEVELVALUE, 4, 0.786);
ObjectSetDouble(0, fiboName, OBJPROP_LEVELVALUE, 5, 1.0);
// Set level descriptions
ObjectSetString(0, fiboName, OBJPROP_LEVELTEXT, 0, "0.0");
ObjectSetString(0, fiboName, OBJPROP_LEVELTEXT, 1, "38.2% - OTE Zone");
ObjectSetString(0, fiboName, OBJPROP_LEVELTEXT, 2, "50.0% - OTE Zone");
ObjectSetString(0, fiboName, OBJPROP_LEVELTEXT, 3, "61.8% - OTE Zone");
ObjectSetString(0, fiboName, OBJPROP_LEVELTEXT, 4, "78.6% - OTE Zone");
ObjectSetString(0, fiboName, OBJPROP_LEVELTEXT, 5, "100.0%");
// Add tooltip
ObjectSetString(0, fiboName, OBJPROP_TOOLTIP, "Fibonacci retracement
levels for session ranges.");
}
}
}
//+------------------------------------------------------------------+
//| Check for trading setups based on ICT model |
//+------------------------------------------------------------------+
void CheckForTradingSetups(const int rates_total, const datetime &time[],
const double &high[], const double &low[],
const double &open[], const double &close[]) {
// Get current price
double currentPrice = Close[0];
// Only check if we're past London open
if (Time[0] < londonOpen) return;
// Check for London Session Liquidity Sweep and Reversal
if (Time[0] >= londonOpen && Time[0] < nyOpen) {
// Check for liquidity sweep of London session high
if (high[0] > londonHigh && high[1] <= londonHigh) {
// Liquidity sweep of London high occurred
if (AlertsOn) Alert("Liquidity sweep of London high occurred at London
session");
// If daily bias is bearish, this is a good opportunity
if (dailyBias < 0) {
// Check for potential market structure shift down
if (close[0] < open[0]) {
Alert("ICT Setup: Bearish London high sweep aligned with daily
bias");
}
}
}
// Check for liquidity sweep of London session low
if (low[0] < londonLow && low[1] >= londonLow) {
// Liquidity sweep of London low occurred
if (AlertsOn) Alert("Liquidity sweep of London low occurred at London
session");
// If daily bias is bullish, this is a good opportunity
if (dailyBias > 0) {
// Check for potential market structure shift up
if (close[0] > open[0]) {
Alert("ICT Setup: Bullish London low sweep aligned with daily
bias");
}
}
}
}
// Check for NY Session Liquidity Sweep and Reversal
if (Time[0] >= nyOpen) {
// Check for liquidity sweep of NY session high
if (high[0] > nyHigh && high[1] <= nyHigh) {
// Liquidity sweep of NY high occurred
if (AlertsOn) Alert("Liquidity sweep of NY high occurred at NY session");
// If daily bias is bearish, this is a good opportunity
if (dailyBias < 0) {
// Check for potential market structure shift down
if (close[0] < open[0]) {
Alert("ICT Setup: Bearish NY high sweep aligned with daily bias");
}
}
}
// Check for liquidity sweep of NY session low
if (low[0] < nyLow && low[1] >= nyLow) {
// Liquidity sweep of NY low occurred
if (AlertsOn) Alert("Liquidity sweep of NY low occurred at NY session");
// If daily bias is bullish, this is a good opportunity
if (dailyBias > 0) {
// Check for potential market structure shift up
if (close[0] > open[0]) {
Alert("ICT Setup: Bullish NY low sweep aligned with daily bias");
}
}
}
// Check for OTE zones in relation to London range
double londonRange = londonHigh - londonLow;
double fib50 = londonLow + londonRange * 0.5;
double fib618 = londonLow + londonRange * 0.618;
double fib382 = londonLow + londonRange * 0.382;
// Check if price is near OTE zones
if ((currentPrice >= fib382 * 0.99 && currentPrice <= fib382 * 1.01) ||
(currentPrice >= fib50 * 0.99 && currentPrice <= fib50 * 1.01) ||
(currentPrice >= fib618 * 0.99 && currentPrice <= fib618 * 0.01)) {
if (AlertsOn) {
if (dailyBias > 0 && currentPrice <= fib618 * 1.01) {
Alert("ICT Bullish OTE: Price testing bullish OTE zone with
bullish bias");
}
else if (dailyBias < 0 && currentPrice >= fib382 * 0.99) {
Alert("ICT Bearish OTE: Price testing bearish OTE zone with
bearish bias");
}
else {
Alert("Price is testing ICT Optimal Trade Entry zone");
}
}
}
// Check for Asian Session OTE entries
double asianRange = asianHigh - asianLow;
double asianFib50 = asianLow + asianRange * 0.5;
double asianFib618 = asianLow + asianRange * 0.618;
double asianFib382 = asianLow + asianRange * 0.382;
// Check if price is near Asian OTE zones during London or NY
if ((currentPrice >= asianFib382 * 0.99 && currentPrice <= asianFib382 *
1.01) ||
(currentPrice >= asianFib50 * 0.99 && currentPrice <= asianFib50 * 1.01)
||
(currentPrice >= asianFib618 * 0.99 && currentPrice <= asianFib618 *
0.01)) {
if (AlertsOn) {
if (dailyBias > 0 && currentPrice <= asianFib618 * 1.01) {
Alert("ICT Asian Bullish OTE: Price testing Asian OTE zone with
bullish bias");
}
else if (dailyBias < 0 && currentPrice >= asianFib382 * 0.99) {
Alert("ICT Asian Bearish OTE: Price testing Asian OTE zone with
bearish bias");
}
else {
Alert("Price is testing Asian session ICT Optimal Trade Entry
zone");
}
}
}
}
// Check if price is approaching any active FVG aligned with daily bias
for (int i = 0; i < fvgCount; i++) {
// Only consider FVGs that align with daily bias
if ((fvgArray[i].direction == 1 && dailyBias > 0) ||
(fvgArray[i].direction == -1 && dailyBias < 0)) {
if (currentPrice >= fvgArray[i].low && currentPrice <= fvgArray[i].high) {
string fvgDirection = fvgArray[i].direction > 0 ? "Bullish" :
"Bearish";
if (AlertsOn) Alert("ICT Setup: Price testing " + fvgDirection + " Fair
Value Gap aligned with daily bias");
}
}
}
}
//+------------------------------------------------------------------+
//| Detect market regime |
//+------------------------------------------------------------------+
void DetectMarketRegime(const int rates_total) {
// Calculate ADX
adxValue = (double)iADX(Symbol(), (ENUM_TIMEFRAMES)PERIOD_CURRENT, 14,
(int)PRICE_CLOSE, (int)MODE_MAIN, 0);
// Calculate Bollinger Bands
upperBB = (double)iBands(Symbol(), (ENUM_TIMEFRAMES)PERIOD_CURRENT,
(int)BBPeriod, (int)BBDeviation, (int)BBDeviation, (int)PRICE_CLOSE,
(int)MODE_UPPER, 0);
lowerBB = (double)iBands(Symbol(), (ENUM_TIMEFRAMES)PERIOD_CURRENT,
(int)BBPeriod, (int)BBDeviation, (int)BBDeviation, (int)PRICE_CLOSE,
(int)MODE_LOWER, 0);
// Calculate middle band manually as SMA
middleBB = (double)iMA(Symbol(), (ENUM_TIMEFRAMES)PERIOD_CURRENT, (int)BBPeriod,
0, (int)MODE_SMA, (int)PRICE_CLOSE, 0);
// Determine market regime
if (adxValue > TrendStrengthThreshold) {
// Trending market
double diPlus = (double)iADX(Symbol(), (ENUM_TIMEFRAMES)PERIOD_CURRENT, 14,
(int)PRICE_CLOSE, (int)MODE_PLUSDI, 0);
double diMinus = (double)iADX(Symbol(), (ENUM_TIMEFRAMES)PERIOD_CURRENT, 14,
(int)PRICE_CLOSE, (int)MODE_MINUSDI, 0);
if (diPlus > diMinus) {
marketRegime = 1; // Bullish trend
} else {
marketRegime = -1; // Bearish trend
}
} else {
// Ranging market
marketRegime = 0;
}
}
//+------------------------------------------------------------------+
//| Visualize market regime |
//+------------------------------------------------------------------+
void VisualizeMarketRegime(const int rates_total, const datetime &time[]) {
// Draw background color based on market regime
if(marketRegime == 1) { // Bullish trend
DrawBackground(time[0], clrGreen);
} else if(marketRegime == -1) { // Bearish trend
DrawBackground(time[0], clrRed);
} else { // Ranging
DrawBackground(time[0], clrYellow);
}
// Display text label indicating market regime
string regimeText = "Market Regime: ";
if(marketRegime == 1) {
regimeText += "Bullish Trend";
} else if(marketRegime == -1) {
regimeText += "Bearish Trend";
} else {
regimeText += "Ranging";
}
// Create or update regime label
ObjectDelete("RegimeLabel");
ObjectCreate("RegimeLabel", OBJ_LABEL, 0, 0, 0);
ObjectSetText("RegimeLabel", regimeText, 10, "Arial", clrWhite);
ObjectSet("RegimeLabel", OBJPROP_CORNER, 1);
ObjectSet("RegimeLabel", OBJPROP_XDISTANCE, 10);
ObjectSet("RegimeLabel", OBJPROP_YDISTANCE, 60);
}
//+------------------------------------------------------------------+
//| Draw background color |
//+------------------------------------------------------------------+
void DrawBackground(datetime currentTime, color bgColor) {
string backgroundName = "MarketRegimeBackground";
ObjectDelete(backgroundName);
ObjectCreate(backgroundName, OBJ_RECTANGLE, 0, D'2023.01.01', 0, TimeCurrent(),
0);
ObjectSetInteger(0, backgroundName, OBJPROP_COLOR, bgColor);
ObjectSetInteger(0, backgroundName, OBJPROP_BACK, true);
ObjectSetInteger(0, backgroundName, OBJPROP_SELECTABLE, false);
ObjectSetInteger(0, backgroundName, OBJPROP_ZORDER, 0);
}
//+------------------------------------------------------------------+
//| Detect price action patterns with enhanced confirmation |
//+------------------------------------------------------------------+
enum PriceActionPattern {
NO_PATTERN,
BULLISH_PIN_BAR,
BEARISH_PIN_BAR,
BULLISH_ENGULFING,
BEARISH_ENGULFING,
INSIDE_BAR,
BREAKOUT_BAR,
BULLISH_HAMMER,
BEARISH_HANGING_MAN,
BULLISH_SWALLOW,
BEARISH_SWALLOW
};
PriceActionPattern DetectPriceActionPattern(
const int rates_total,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &volume[]
) {
PriceActionPattern pattern = NO_PATTERN;
double currentBody = MathAbs(close[0] - open[0]);
double previousBody = MathAbs(close[1] - open[1]);
double currentRange = high[0] - low[0];
double previousRange = high[1] - low[1];
double atr = iATR(Symbol(), PERIOD_CURRENT, 14, 0);
// Minimum size requirements
double minPinBarSize = 2 * atr;
double minEngulfingSize = 1.5 * atr;
double minInsideBarSize = 0.5 * atr;
double minBreakoutSize = 2 * atr;
// Detect pin bars with enhanced confirmation
if (currentBody > 0 && currentRange > 0) {
double upperWick = high[0] - MathMax(open[0], close[0]);
double lowerWick = MathMin(open[0], close[0]) - low[0];
// Bullish pin bar
if (lowerWick >= 2 * currentBody && lowerWick >= 0.6 * currentRange &&
close[0] > open[0] && close[0] < open[1] &&
currentRange >= minPinBarSize &&
close[1] > open[1]) {
pattern = BULLISH_PIN_BAR;
}
// Bearish pin bar
if (upperWick >= 2 * currentBody && upperWick >= 0.6 * currentRange &&
close[0] < open[0] && close[0] > open[1] &&
currentRange >= minPinBarSize &&
close[1] < open[1]) {
pattern = BEARISH_PIN_BAR;
}
}
// Detect engulfing patterns with confirmation
if (close[0] > open[0] && close[1] < open[1] &&
close[0] > open[1] && close[0] > high[1] &&
currentBody >= minEngulfingSize &&
close[2] > open[2]) {
pattern = BULLISH_ENGULFING;
} else if (close[0] < open[0] && close[1] > open[1] &&
open[0] < close[1] && open[0] < low[1] &&
currentBody >= minEngulfingSize &&
close[2] < open[2]) {
pattern = BEARISH_ENGULFING;
}
// Detect inside bars with breakout confirmation
if (high[0] < high[1] && low[0] > low[1] &&
currentRange >= minInsideBarSize &&
(high[2] > high[1] || low[2] < low[1])) {
pattern = INSIDE_BAR;
}
// Detect breakout bars with confirmation
if (high[0] > high[1] && low[0] < low[1] &&
currentRange >= minBreakoutSize &&
(high[0] > high[2] || low[0] < low[2])) {
pattern = BREAKOUT_BAR;
}
// Detect hammer and hanging man patterns
if (currentBody > 0 && currentRange > 0) {
double upperWick = high[0] - MathMax(open[0], close[0]);
double lowerWick = MathMin(open[0], close[0]) - low[0];
// Bullish hammer
if (lowerWick >= 2 * currentBody && lowerWick >= 0.6 * currentRange &&
close[0] > open[0] && close[0] < open[1] &&
currentRange >= minPinBarSize &&
close[1] > open[1]) {
pattern = BULLISH_HAMMER;
}
// Bearish hanging man
if (lowerWick >= 2 * currentBody && lowerWick >= 0.6 * currentRange &&
close[0] < open[0] && close[0] > open[1] &&
currentRange >= minPinBarSize &&
close[1] < open[1]) {
pattern = BEARISH_HANGING_MAN;
}
}
// Detect bullish and bearish swallowing patterns
if (close[0] > open[0] && close[0] > high[1] && open[0] < low[1] &&
currentBody >= minEngulfingSize &&
close[2] > open[2]) {
pattern = BULLISH_SWALLOW;
} else if (close[0] < open[0] && close[0] < low[1] && open[0] > high[1] &&
currentBody >= minEngulfingSize &&
close[2] < open[2]) {
pattern = BEARISH_SWALLOW;
}
return pattern;
}
//+------------------------------------------------------------------+
//| Draw price action arrows with enhanced confirmation |
//+------------------------------------------------------------------+
void DrawPriceActionArrows(
const int rates_total,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &volume[]
) {
PriceActionPattern pattern = DetectPriceActionPattern(rates_total, time, open,
high, low, close, volume);
double arrowPrice = 0; // Initialize arrowPrice here
// Only draw arrow if pattern is detected and confirmed
if (pattern != NO_PATTERN) {
int arrowCode = 0;
color arrowColor;
switch(pattern) {
case BULLISH_PIN_BAR:
case BULLISH_HAMMER:
case BULLISH_SWALLOW:
arrowPrice = low[0] - (high[0] - low[0]) * 0.3;
arrowCode = 233; // Up arrow
arrowColor = BuyArrowColor;
break;
case BEARISH_PIN_BAR:
case BEARISH_HANGING_MAN:
case BEARISH_SWALLOW:
arrowPrice = high[0] + (high[0] - low[0]) * 0.3;
arrowCode = 234; // Down arrow
arrowColor = SellArrowColor;
break;
case BULLISH_ENGULFING:
arrowPrice = low[0] - (high[0] - low[0]) * 0.2;
arrowCode = 22; // Hollow up arrow
arrowColor = BuyArrowColor;
break;
case BEARISH_ENGULFING:
arrowPrice = high[0] + (high[0] - low[0]) * 0.2;
arrowCode = 23; // Hollow down arrow
arrowColor = SellArrowColor;
break;
case INSIDE_BAR:
arrowPrice = (high[0] + low[0]) / 2;
arrowCode = 162; // Diamond
arrowColor = clrOrange;
break;
case BREAKOUT_BAR:
if (high[0] > high[1]) {
arrowPrice = high[1] + (high[0] - high[1]) * 0.5;
arrowCode = 24; // Small up arrow
arrowColor = BuyArrowColor;
} else {
arrowPrice = low[1] - (low[1] - low[0]) * 0.5;
arrowCode = 25; // Small down arrow
arrowColor = SellArrowColor;
}
break;
}
// Additional confirmation from subsequent bars
if (pattern == BULLISH_PIN_BAR || pattern == BULLISH_HAMMER || pattern ==
BULLISH_SWALLOW ||
pattern == BULLISH_ENGULFING) {
if (close[1] > open[1] && high[1] > high[0]) {
BuySignalBuffer[0] = arrowPrice;
SetIndexArrow(9, arrowCode);
}
} else if (pattern == BEARISH_PIN_BAR || pattern == BEARISH_HANGING_MAN ||
pattern == BEARISH_SWALLOW ||
pattern == BEARISH_ENGULFING) {
if (close[1] < open[1] && low[1] < low[0]) {
SellSignalBuffer[0] = arrowPrice;
SetIndexArrow(10, arrowCode);
}
} else if (pattern == INSIDE_BAR || pattern == BREAKOUT_BAR) {
// For neutral patterns, use a different buffer or visual style
// This would require adding additional buffers to the indicator
}
}
// Clear previous arrows for all bars except the current one
for (int i = 1; i < rates_total; i++) {
BuySignalBuffer[i] = EMPTY_VALUE;
SellSignalBuffer[i] = EMPTY_VALUE;
}
// Ensure the current bar's arrow is displayed
if (pattern != NO_PATTERN) {
BuySignalBuffer[0] = arrowPrice;
SellSignalBuffer[0] = arrowPrice;
}
}
//+------------------------------------------------------------------+
//| Detect and draw candlestick patterns |
//+------------------------------------------------------------------+
void DetectAndDrawPatterns(const int rates_total, const datetime &time[],
const double &open[], const double &high[],
const double &low[], const double &close[]) {
// Clear previous pattern arrows for all bars except the current one
if (rates_total < 1) return; // Added check for rates_total
for (int i = 1; i < rates_total; i++) {
BullishPatternBuffer[i] = EMPTY_VALUE;
BearishPatternBuffer[i] = EMPTY_VALUE;
}
// Detect patterns on the most recent bars
for (int i = rates_total - 1; i >= MathMax(0, rates_total - PatternLookback);
i--) {
if (DetectBullishPattern(i, time, open, high, low, close)) {
// Place bullish pattern arrow below the bar
BullishPatternBuffer[i] = low[i] - (high[i] - low[i]) * 0.1;
}
if (DetectBearishPattern(i, time, open, high, low, close)) {
// Place bearish pattern arrow above the bar
BearishPatternBuffer[i] = high[i] + (high[i] - low[i]) * 0.1;
}
}
// Ensure the current bar's pattern arrows are displayed
if (DetectBullishPattern(0, time, open, high, low, close)) {
BullishPatternBuffer[0] = low[0] - (high[0] - low[0]) * 0.1;
}
if (DetectBearishPattern(0, time, open, high, low, close)) {
BearishPatternBuffer[0] = high[0] + (high[0] - low[0]) * 0.1;
}
}
//+------------------------------------------------------------------+
//| Detect bullish candlestick patterns |
//+------------------------------------------------------------------+
bool DetectBullishPattern(const int index, const datetime &time[],
const double &open[], const double &high[],
const double &low[], const double &close[]) {
// Hammer pattern
if (IsHammer(index, open, high, low, close)) {
return true;
}
// Inverted Hammer pattern
if (IsInvertedHammer(index, open, high, low, close)) {
return true;
}
// Bullish Engulfing pattern
if (IsBullishEngulfing(index, open, high, low, close)) {
return true;
}
// Morning Star pattern
if (IsMorningStar(index, open, high, low, close)) {
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Detect bearish candlestick patterns |
//+------------------------------------------------------------------+
bool DetectBearishPattern(const int index, const datetime &time[],
const double &open[], const double &high[],
const double &low[], const double &close[]) {
// Hanging Man pattern
if (IsHangingMan(index, open, high, low, close)) {
return true;
}
// Shooting Star pattern
if (IsShootingStar(index, open, high, low, close)) {
return true;
}
// Bearish Engulfing pattern
if (IsBearishEngulfing(index, open, high, low, close)) {
return true;
}
// Evening Star pattern
if (IsEveningStar(index, open, high, low, close)) {
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Check for Hammer pattern |
//+------------------------------------------------------------------+
bool IsHammer(int index, const double &open[], const double &high[],
const double &low[], const double &close[]) {
double body = MathAbs(close[index] - open[index]);
double lowerWick = open[index] - low[index];
if (body > 0 && lowerWick >= 2 * body && lowerWick >= 0.6 * (high[index] -
low[index])) {
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Check for Inverted Hammer pattern |
//+------------------------------------------------------------------+
bool IsInvertedHammer(int index, const double &open[], const double &high[],
const double &low[], const double &close[]) {
double body = MathAbs(close[index] - open[index]);
double upperWick = high[index] - close[index];
if (body > 0 && upperWick >= 2 * body && upperWick >= 0.6 * (high[index] -
low[index])) {
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Check for Bullish Engulfing pattern |
//+------------------------------------------------------------------+
bool IsBullishEngulfing(int index, const double &open[], const double &high[],
const double &low[], const double &close[]) {
if (close[index] > open[index] && close[index-1] < open[index-1] &&
close[index] > open[index-1] && close[index] > high[index-1]) {
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Check for Morning Star pattern |
//+------------------------------------------------------------------+
bool IsMorningStar(int index, const double &open[], const double &high[],
const double &low[], const double &close[]) {
if (index < 2) return false;
if (close[index-2] < open[index-2] &&
MathAbs(close[index-1] - open[index-1]) < 0.2 * (high[index-1] - low[index-
1]) &&
close[index] > open[index] &&
close[index] > (open[index-2] + close[index-2]) / 2) {
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Check for Hanging Man pattern |
//+------------------------------------------------------------------+
bool IsHangingMan(int index, const double &open[], const double &high[],
const double &low[], const double &close[]) {
double body = MathAbs(close[index] - open[index]);
double lowerWick = open[index] - low[index];
if (body > 0 && lowerWick >= 2 * body && lowerWick >= 0.6 * (high[index] -
low[index]) &&
close[index] < open[index] &&
close[index] > (high[index-1] + low[index-1]) / 2) {
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Check for Shooting Star pattern |
//+------------------------------------------------------------------+
bool IsShootingStar(int index, const double &open[], const double &high[],
const double &low[], const double &close[]) {
double body = MathAbs(close[index] - open[index]);
double upperWick = high[index] - close[index];
if (body > 0 && upperWick >= 2 * body && upperWick >= 0.6 * (high[index] -
low[index]) &&
close[index] < open[index] &&
close[index] > (high[index-1] + low[index-1]) / 2) {
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Check for Bearish Engulfing pattern |
//+------------------------------------------------------------------+
bool IsBearishEngulfing(int index, const double &open[], const double &high[],
const double &low[], const double &close[]) {
if (close[index] < open[index] && close[index-1] > open[index-1] &&
close[index] < open[index-1] && close[index] < low[index-1]) {
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Check for Evening Star pattern |
//+------------------------------------------------------------------+
bool IsEveningStar(int index, const double &open[], const double &high[],
const double &low[], const double &close[]) {
if (index < 2) return false;
if (close[index-2] > open[index-2] &&
MathAbs(close[index-1] - open[index-1]) < 0.2 * (high[index-1] - low[index-
1]) &&
close[index] < open[index] &&
close[index] < (open[index-2] + close[index-2]) / 2) {
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Calculate RSI values |
//+------------------------------------------------------------------+
void CalculateRSI(const int rates_total, const datetime &time[], const double
&close[]) {
for (int i = 0; i < rates_total; i++) {
RSIValues[i] = iRSI(Symbol(), Period(), RSIDivergencePeriod, PRICE_CLOSE, i);
}
}
//+------------------------------------------------------------------+
//| Detect and draw RSI divergence |
//+------------------------------------------------------------------+
void DetectRSIDivergence(const int rates_total, const datetime &time[],
const double &high[], const double &low[],
const double &close[]) {
// Clear previous divergence arrows for all bars except the current one
for (int i = 1; i < rates_total; i++) {
BullishDivergenceBuffer[i] = EMPTY_VALUE;
BearishDivergenceBuffer[i] = EMPTY_VALUE;
}
// Detect divergence on the most recent bars
for (int i = rates_total - 1; i >= MathMax(0, rates_total -
RSIDivergenceLookback); i--) {
if (DetectBullishRSIDivergence(i, time, low, RSIValues)) {
// Place bullish divergence arrow below the bar
BullishDivergenceBuffer[i] = low[i] - (high[i] - low[i]) * 0.1;
}
if (DetectBearishRSIDivergence(i, time, high, RSIValues)) {
// Place bearish divergence arrow above the bar
BearishDivergenceBuffer[i] = high[i] + (high[i] - low[i]) * 0.1;
}
}
// Ensure the current bar's divergence arrows are displayed
if (DetectBullishRSIDivergence(0, time, low, RSIValues)) {
BullishDivergenceBuffer[0] = low[0] - (high[0] - low[0]) * 0.1;
}
if (DetectBearishRSIDivergence(0, time, high, RSIValues)) {
BearishDivergenceBuffer[0] = high[0] + (high[0] - low[0]) * 0.1;
}
}
//+------------------------------------------------------------------+
//| Detect bullish RSI divergence |
//+------------------------------------------------------------------+
bool DetectBullishRSIDivergence(const int index, const datetime &time[],
const double &low[], const double &rsiValues[]) {
// Check if we have enough data to look back
if (index < RSIDivergenceLookback || index < 0) return false;
// Check for lower price lows
if (low[index] >= low[index - RSIDivergenceLookback]) return false;
// Check for higher RSI lows
double currentRSILow = rsiValues[index];
double previousRSILow = rsiValues[index - RSIDivergenceLookback];
if (currentRSILow <= previousRSILow) return false;
// Check for sufficient divergence
if (previousRSILow - currentRSILow < RSIDivergenceThreshold) return false;
return true;
}
//+------------------------------------------------------------------+
//| Detect bearish RSI divergence |
//+------------------------------------------------------------------+
bool DetectBearishRSIDivergence(const int index, const datetime &time[],
const double &high[], const double &rsiValues[]) {
// Check if we have enough data to look back
if (index < RSIDivergenceLookback || index < 0) return false;
// Check for higher price highs
if (high[index] <= high[index - RSIDivergenceLookback]) return false;
// Check for lower RSI highs
double currentRSIHigh = rsiValues[index];
double previousRSIHigh = rsiValues[index - RSIDivergenceLookback];
if (currentRSIHigh >= previousRSIHigh) return false;
// Check for sufficient divergence
if (previousRSIHigh - currentRSIHigh < RSIDivergenceThreshold) return false;
return true;
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
// Clean up objects
ObjectDelete("LondonOpen");
ObjectDelete("NYOpen");
ObjectDelete("LondonFibo");
ObjectDelete("NYFibo");
ObjectDelete("AsianFibo");
ObjectDelete("DailyBiasLabel");
ObjectDelete("TimeZoneLabel");
ObjectDelete("AsianOpen");
ObjectDelete("RegimeLabel");
// Clean up timer
EventKillTimer();
}
//+------------------------------------------------------------------+
//| Timer function for optimal refreshing |
//+------------------------------------------------------------------+
void OnTimer() {
// Refresh indicator only during market hours
datetime currentTime = TimeCurrent();
int currentHour = TimeHour(currentTime);
int currentMinute = TimeMinute(currentTime);
// Only refresh during active trading hours (Asian, London, NY sessions)
// Avoid unnecessary calculations during off-hours
if((currentHour >= 0 && currentHour < 17) || // 0:00-17:00 GMT
(currentHour == 17 && currentMinute < 30)) { // Until 17:30 GMT
ChartRedraw(); // Force indicator recalculation
}
}
//+------------------------------------------------------------------+
//| Check if it's a new day |
//+------------------------------------------------------------------+
bool IsNewDay(datetime currentTime, datetime lastTime) {
return (TimeDay(currentTime) != TimeDay(lastTime)) ||
(TimeMonth(currentTime) != TimeMonth(lastTime)) ||
(TimeYear(currentTime) != TimeYear(lastTime));
}
//+------------------------------------------------------------------+
//| Detect recent price trend |
//+------------------------------------------------------------------+
int DetectPriceTrend(const int rates_total, const double &high[], const double
&low[]) {
int trend = 0; // 0 for no clear trend, 1 for bullish, -1 for bearish
// Check for bullish trend: higher highs and higher lows
if (high[0] > high[1] && high[1] > high[2] &&
low[0] > low[1] && low[1] > low[2]) {
trend = 1;
}
// Check for bearish trend: lower highs and lower lows
if (high[0] < high[1] && high[1] < high[2] &&
low[0] < low[1] && low[1] < low[2]) {
trend = -1;
}
return trend;
}
//+------------------------------------------------------------------+