Here is the "Pro" build for both platforms. It features a dark-mode graphical panel, spread monitoring, ADR exhaustion, and bulletproof data loading.
Code: Select all
//+------------------------------------------------------------------+
//| LondonDeskMatrix_Pro.mq5 |
//| Institutional Pro Desk |
//+------------------------------------------------------------------+
#property copyright "Pro Desk Matrix"
#property indicator_chart_window
#property indicator_buffers 0
input string InpSessionStart = "08:00";
input string InpSessionEnd = "12:00";
input string InpBenchmark = "DXY";
input int InpLookback = 20;
input double InpMaxSpread = 1.5; // Max Acceptable Spread (Pips)
input string Sym1 = "EURUSD";
input string Sym2 = "GBPUSD";
input string Sym3 = "GBPJPY";
input string Sym4 = "USDJPY";
// GUI Coordinates
int startX = 20, startY = 20, rowH = 22, colW = 65;
int OnInit() {
// Force symbols into Market Watch for async data access
string syms[4] = {Sym1, Sym2, Sym3, Sym4};
for(int i=0; i<4; i++) {
SymbolSelect(syms[i], true);
}
SymbolSelect(InpBenchmark, true);
DrawPanel();
EventSetTimer(1);
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason) {
EventKillTimer();
ObjectsDeleteAll(0, "Mat_");
ChartRedraw();
}
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[]) {
return(rates_total);
}
//--- GUI Engine
void CreateRect(string name, int x, int y, int w, int h, color bgClr, color borderClr) {
if(ObjectFind(0, name) < 0) {
ObjectCreate(0, name, OBJ_RECTANGLE_LABEL, 0, 0, 0);
ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_RIGHT_UPPER);
ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_RIGHT_UPPER);
ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
}
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
ObjectSetInteger(0, name, OBJPROP_XSIZE, w);
ObjectSetInteger(0, name, OBJPROP_YSIZE, h);
ObjectSetInteger(0, name, OBJPROP_BGCOLOR, bgClr);
ObjectSetInteger(0, name, OBJPROP_COLOR, borderClr);
}
void DrawLabel(string name, int x, int y, string text, color clr, int fontSize=9, bool bold=false) {
if(ObjectFind(0, name) < 0) {
ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_RIGHT_UPPER);
ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_RIGHT_UPPER);
ObjectSetString(0, name, OBJPROP_FONT, bold ? "Consolas Bold" : "Consolas");
ObjectSetInteger(0, name, OBJPROP_BACK, false);
ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
}
ObjectSetString(0, name, OBJPROP_TEXT, text);
ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, fontSize);
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
}
void DrawPanel() {
CreateRect("Mat_BG", startX, startY, (colW*6)+10, (rowH*6)+10, clrBlack, clrDimGray);
CreateRect("Mat_HeadBG", startX, startY, (colW*6)+10, rowH+5, color'20,20,20', clrDimGray);
DrawLabel("Mat_H1", startX + colW*5.5, startY+5, "ASSET", clrGray, 9, true);
DrawLabel("Mat_H2", startX + colW*4.5, startY+5, "SPREAD", clrGray, 9, true);
DrawLabel("Mat_H3", startX + colW*3.5, startY+5, "VOL Z", clrGray, 9, true);
DrawLabel("Mat_H4", startX + colW*2.5, startY+5, "ADR %", clrGray, 9, true);
DrawLabel("Mat_H5", startX + colW*1.5, startY+5, "BETA", clrGray, 9, true);
DrawLabel("Mat_H6", startX + colW*0.5, startY+5, "STATUS", clrGray, 9, true);
}
//--- Math & Metric Engines
double GetPipMultiplier(string sym) {
long digits = SymbolInfoInteger(sym, SYMBOL_DIGITS);
return (digits == 3 || digits == 5) ? 10.0 : 1.0;
}
double GetLiveSpread(string sym) {
long spr = SymbolInfoInteger(sym, SYMBOL_SPREAD);
double point = SymbolInfoDouble(sym, SYMBOL_POINT);
return (spr * point) / (point * GetPipMultiplier(sym));
}
double GetADRExhaustion(string sym) {
double high[], low[];
if(CopyHigh(sym, PERIOD_D1, 0, 15, high) < 15) return 0.0;
if(CopyLow(sym, PERIOD_D1, 0, 15, low) < 15) return 0.0;
double adrSum = 0;
for(int i=1; i<=14; i++) adrSum += (high[i] - low[i]);
double currentRange = high[0] - low[0];
if(adrSum == 0) return 0;
return (currentRange / (adrSum / 14.0)) * 100.0;
}
// (VolZScore and Correlation functions remain identical to previous version, omitted for brevity but required in compile. Paste them here).
double GetVolZScore(string sym, int lookback) {
long vols[];
if(CopyTickVolume(sym, 0, 0, lookback+1, vols) < lookback+1) return 0.0;
double mean = 0.0;
for(int i = 0; i < lookback; i++) mean += (double)vols[i];
mean /= lookback;
double variance = 0.0;
for(int i = 0; i < lookback; i++) { double d = (double)vols[i] - mean; variance += (d * d); }
double stddev = MathSqrt(variance / lookback);
if(stddev == 0.0) return 0.0;
return ((double)vols[lookback] - mean) / stddev;
}
double GetCorrelation(string symA, string symB, int lookback) {
double arrA[], arrB[];
if(CopyClose(symA, 0, 1, lookback, arrA) < lookback) return 0.0;
if(CopyClose(symB, 0, 1, lookback, arrB) < lookback) return 0.0;
double meanA = 0, meanB = 0;
for(int i = 0; i < lookback; i++) { meanA += arrA[i]; meanB += arrB[i]; }
meanA /= lookback; meanB /= lookback;
double sumAB = 0, sumA2 = 0, sumB2 = 0;
for(int i = 0; i < lookback; i++) {
double dA = arrA[i] - meanA; double dB = arrB[i] - meanB;
sumAB += (dA * dB); sumA2 += (dA * dA); sumB2 += (dB * dB);
}
if(sumA2 * sumB2 == 0) return 0.0;
return sumAB / MathSqrt(sumA2 * sumB2);
}
bool IsInSession(string startHM, string endHM) {
MqlDateTime tm; TimeToStruct(TimeCurrent(), tm);
int currentMins = tm.hour * 60 + tm.min;
string sArr[], eArr[]; StringSplit(startHM, ':', sArr); StringSplit(endHM, ':', eArr);
int sMins = (int)StringToInteger(sArr[0]) * 60 + (int)StringToInteger(sArr[1]);
int eMins = (int)StringToInteger(eArr[0]) * 60 + (int)StringToInteger(eArr[1]);
return (sMins <= eMins) ? (currentMins >= sMins && currentMins <= eMins) : (currentMins >= sMins || currentMins <= eMins);
}
void OnTimer() {
bool isLive = IsInSession(InpSessionStart, InpSessionEnd);
string syms[4] = {Sym1, Sym2, Sym3, Sym4};
for(int i = 0; i < 4; i++) {
int y = startY + 30 + (i * rowH);
string id = "Mat_R" + IntegerToString(i);
double spread = GetLiveSpread(syms[i]);
double volZ = GetVolZScore(syms[i], InpLookback);
double adrPct = GetADRExhaustion(syms[i]);
double beta = GetCorrelation(syms[i], InpBenchmark, InpLookback);
color cSpr = (spread <= InpMaxSpread) ? clrWhite : clrRed;
color cVol = (volZ > 1.5) ? clrAqua : clrWhite;
color cAdr = (adrPct > 80) ? clrOrange : ((adrPct < 30) ? clrDimGray : clrWhite);
color cBeta = (MathAbs(beta) > 0.8) ? clrOrange : clrWhite;
color cStat = isLive ? clrLime : clrDimGray;
DrawLabel(id+"_Sym", startX + colW*5.5, y, syms[i], clrWhite, 9, true);
DrawLabel(id+"_Spr", startX + colW*4.5, y, DoubleToString(spread, 1), cSpr);
DrawLabel(id+"_Vol", startX + colW*3.5, y, DoubleToString(volZ, 2), cVol);
DrawLabel(id+"_Adr", startX + colW*2.5, y, DoubleToString(adrPct, 0)+"%", cAdr);
DrawLabel(id+"_Beta", startX + colW*1.5, y, DoubleToString(beta, 2), cBeta);
DrawLabel(id+"_Stat", startX + colW*0.5, y, isLive ? "LIVE" : "WAIT", cStat);
}
ChartRedraw();
}