To convert to MT4, the core logic is identical, but you replace CopyBuffer calls with standard iMA/iATR calls and SymbolInfoInteger with MarketInfo(Symbol(), MODE_SPREAD).
This MQL5 script includes dynamic Spread Protection (vital for EURGBP) and a Live Quantitative HUD overlay.
Code: Select all
//+------------------------------------------------------------------+
//| EURGBP_Quant_Execution_Engine.mq5 |
//| Institutional Mean-Reversion Framework |
//+------------------------------------------------------------------+
#property copyright "Quantitative Research Desk"
#property version "2.00"
#property indicator_chart_window
#property indicator_buffers 5
#property indicator_plots 5
// --- Aesthetics
#property indicator_label1 "Fair Value (Mean)"
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrDimGray
#property indicator_style1 STYLE_SOLID
#property indicator_label2 "Upper Statistical Bound"
#property indicator_type2 DRAW_LINE
#property indicator_color2 clrCrimson
#property indicator_style2 STYLE_DASH
#property indicator_label3 "Lower Statistical Bound"
#property indicator_type3 DRAW_LINE
#property indicator_color3 clrMediumSeaGreen
#property indicator_style3 STYLE_DASH
#property indicator_label4 "Institutional Fade Long"
#property indicator_type4 DRAW_ARROW
#property indicator_color4 clrLimeGreen
#property indicator_width4 3
#property indicator_label5 "Institutional Fade Short"
#property indicator_type5 DRAW_ARROW
#property indicator_color5 clrRed
#property indicator_width5 3
// --- Quantitative Inputs
input string InpGrp1 = "--- Statistical Engine ---";
input int InpZLength = 21; // Baseline Window
input double InpZThresh = 2.2; // Standard Deviation Extraction Target
input string InpGrp2 = "--- Microstructure & Cost ---";
input double InpVolZMin = 1.5; // Min Tick Volume Spike (Z-Score)
input int InpMaxSpread = 15; // Max Allowable Spread in Points (1.5 pips)
input string InpGrp3 = "--- Regime Constraints ---";
input int InpAtrLen = 14;
input int InpAtrAvg = 100;
input double InpVolLimit = 1.15; // Suppress if Volatility expands > 15% above norm
// --- Buffers & Handles
double BufferMean[], BufferUpper[], BufferLower[], BufferBuy[], BufferSell[];
int handleMA, handleStdDev, handleATR, handleVolMA, handleVolStd;
//+------------------------------------------------------------------+
//| Initialization |
//+------------------------------------------------------------------+
int OnInit()
{
SetIndexBuffer(0, BufferMean, INDICATOR_DATA);
SetIndexBuffer(1, BufferUpper, INDICATOR_DATA);
SetIndexBuffer(2, BufferLower, INDICATOR_DATA);
SetIndexBuffer(3, BufferBuy, INDICATOR_DATA);
SetIndexBuffer(4, BufferSell, INDICATOR_DATA);
PlotIndexSetInteger(3, PLOT_ARROW, 233);
PlotIndexSetInteger(4, PLOT_ARROW, 234);
handleMA = iMA(_Symbol, _Period, InpZLength, 0, MODE_SMA, PRICE_CLOSE);
handleStdDev = iStdDev(_Symbol, _Period, InpZLength, 0, MODE_SMA, PRICE_CLOSE);
handleATR = iATR(_Symbol, _Period, InpAtrLen);
// Volume handlers for Microstructure verification
handleVolMA = iMA(_Symbol, _Period, 20, 0, MODE_SMA, VOLUME_TICK);
handleVolStd = iStdDev(_Symbol, _Period, 20, 0, MODE_SMA, VOLUME_TICK);
EventSetMillisecondTimer(500); // UI Refresh Rate
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Deinitialization (Cleanup) |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
IndicatorRelease(handleMA);
IndicatorRelease(handleStdDev);
IndicatorRelease(handleATR);
IndicatorRelease(handleVolMA);
IndicatorRelease(handleVolStd);
EventKillTimer();
Comment(""); // Clear HUD
}
//+------------------------------------------------------------------+
//| UI HUD Timer Update |
//+------------------------------------------------------------------+
void OnTimer()
{
int currentSpread = (int)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
string spreadWarn = (currentSpread > InpMaxSpread) ? "[!] SPREAD HIGH - SIGNALS BLOCKED" : "SPREAD OPTIMAL";
string hud = "\n=== EURGBP QUANT ENGINE ===\n" +
"Live Spread: " + IntegerToString(currentSpread) + " pts | Limit: " + IntegerToString(InpMaxSpread) + "\n" +
"Execution Status: " + spreadWarn + "\n" +
"Algorithm: Z-Score Absorption Reversion";
Comment(hud);
}
//+------------------------------------------------------------------+
//| Core Processing Engine |
//+------------------------------------------------------------------+
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[])
{
if(rates_total < InpAtrAvg + InpZLength) return(0);
ArraySetAsSeries(time, true);
ArraySetAsSeries(open, true);
ArraySetAsSeries(high, true);
ArraySetAsSeries(low, true);
ArraySetAsSeries(close, true);
ArraySetAsSeries(tick_volume, true);
ArraySetAsSeries(BufferMean, true);
ArraySetAsSeries(BufferUpper, true);
ArraySetAsSeries(BufferLower, true);
ArraySetAsSeries(BufferBuy, true);
ArraySetAsSeries(BufferSell, true);
double maVal[], stdVal[], atrVal[], vMaVal[], vStdVal[];
ArraySetAsSeries(maVal, true); ArraySetAsSeries(stdVal, true); ArraySetAsSeries(atrVal, true);
ArraySetAsSeries(vMaVal, true); ArraySetAsSeries(vStdVal, true);
int count = rates_total;
if(CopyBuffer(handleMA, 0, 0, count, maVal) <= 0 || CopyBuffer(handleStdDev, 0, 0, count, stdVal) <= 0) return 0;
if(CopyBuffer(handleATR, 0, 0, count, atrVal) <= 0) return 0;
if(CopyBuffer(handleVolMA, 0, 0, count, vMaVal) <= 0 || CopyBuffer(handleVolStd, 0, 0, count, vStdVal) <= 0) return 0;
int limit = (prev_calculated > 0) ? rates_total - prev_calculated + 1 : rates_total - InpAtrAvg;
for(int i = limit; i >= 0; i--)
{
double mean = maVal[i];
double stdDev = stdVal[i];
double upper = mean + (stdDev * InpZThresh);
double lower = mean - (stdDev * InpZThresh);
BufferMean[i] = mean;
BufferUpper[i] = upper;
BufferLower[i] = lower;
BufferBuy[i] = EMPTY_VALUE;
BufferSell[i] = EMPTY_VALUE;
// 1. Regime Filter
double sumAtr = 0;
for(int j = 0; j < InpAtrAvg; j++) sumAtr += atrVal[i+j];
double volRatio = atrVal[i] / (sumAtr / InpAtrAvg);
bool isRange = (volRatio < InpVolLimit);
// 2. Volume Exhaustion Check (Tick Volume Anomaly)
double volStdDev = vStdVal[i];
double currentVolZ = (volStdDev == 0) ? 0 : ((double)tick_volume[i] - vMaVal[i]) / volStdDev;
bool isVolClimactic = (currentVolZ >= InpVolZMin);
// 3. Intra-Bar Rejection (Candle must close aggressively away from the sweep)
double candleSize = high[i] - low[i];
bool validShortClose = close[i] < (high[i] - (candleSize * 0.5));
bool validLongClose = close[i] > (low[i] + (candleSize * 0.5));
// 4. Spread Execution Filter (Historical via spread array, live via symbol query)
bool validSpread = (spread[i] <= InpMaxSpread);
// EXECUTION LOGIC
bool sweepShort = (high[i] > upper) && (close[i] < upper) && isRange && isVolClimactic && validShortClose && validSpread;
bool sweepLong = (low[i] < lower) && (close[i] > lower) && isRange && isVolClimactic && validLongClose && validSpread;
if(sweepLong) BufferBuy[i] = low[i] - (stdDev * 0.3);
if(sweepShort) BufferSell[i] = high[i] + (stdDev * 0.3);
}
return(rates_total);
}