Because MQL5 uses array copies rather than direct time-series access, the calculation explicitly pulls the last N closing prices into arrays using CopyClose before running the Pearson formula. It also utilizes a 1-second timer (EventSetTimer(1)) so the dashboard updates live even when the symbol you are currently watching isn't ticking.
Code: Select all
//+------------------------------------------------------------------+
//| Correlation Risk Dashboard - Theme Cap (MT5) |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property indicator_plots 0
input string InpSymbol1 = "EURUSD"; // Exposure 1
input string InpSymbol2 = "XAUUSD"; // Exposure 2
input string InpSymbol3 = "GBPUSD"; // Exposure 3
input int InpCorrLength = 20; // Correlation Lookback
input double InpWarnThresh = 0.75; // Warning Threshold
int OnInit() {
EventSetTimer(1);
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason) {
ObjectsDeleteAll(0, "CorrDash_");
EventKillTimer();
}
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[]) {
UpdateDashboard();
return(rates_total);
}
void OnTimer() {
UpdateDashboard();
}
double CalculateCorrelation(string symMain, string symTarget, int lookback) {
if(symMain == symTarget) return 1.0;
double arrMain[], arrTarget[];
ArraySetAsSeries(arrMain, true);
ArraySetAsSeries(arrTarget, true);
// Ensure both symbols have enough history loaded
if(CopyClose(symMain, PERIOD_CURRENT, 0, lookback, arrMain) < lookback) return 0.0;
if(CopyClose(symTarget, PERIOD_CURRENT, 0, lookback, arrTarget) < lookback) return 0.0;
double sumX = 0, sumY = 0;
for(int i = 0; i < lookback; i++) {
sumX += arrMain[i];
sumY += arrTarget[i];
}
double meanX = sumX / lookback;
double meanY = sumY / lookback;
double sumXY = 0, sumX2 = 0, sumY2 = 0;
for(int i = 0; i < lookback; i++) {
double devX = arrMain[i] - meanX;
double devY = arrTarget[i] - meanY;
sumXY += devX * devY;
sumX2 += devX * devX;
sumY2 += devY * devY;
}
if(sumX2 * sumY2 == 0) return 0.0;
return sumXY / MathSqrt(sumX2 * sumY2);
}
void DrawPanel(string name, int x, int y, int w, int h) {
if(ObjectFind(0, name) < 0) {
ObjectCreate(0, name, OBJ_RECTANGLE_LABEL, 0, 0, 0);
ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_RIGHT_LOWER);
ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_RIGHT_LOWER);
ObjectSetInteger(0, name, OBJPROP_BGCOLOR, clrBlack);
ObjectSetInteger(0, name, OBJPROP_BORDER_COLOR, clrGray);
ObjectSetInteger(0, name, OBJPROP_BACK, true);
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);
}
void DrawCell(string name, string text, int x, int y, color clr) {
if(ObjectFind(0, name) < 0) {
ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_RIGHT_LOWER);
ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_RIGHT_LOWER);
ObjectSetString(0, name, OBJPROP_FONT, "Arial");
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 9);
}
ObjectSetString(0, name, OBJPROP_TEXT, text);
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
}
void UpdateDashboard() {
double corr1 = CalculateCorrelation(_Symbol, InpSymbol1, InpCorrLength);
double corr2 = CalculateCorrelation(_Symbol, InpSymbol2, InpCorrLength);
double corr3 = CalculateCorrelation(_Symbol, InpSymbol3, InpCorrLength);
color c1 = (MathAbs(corr1) >= InpWarnThresh) ? clrRed : clrLimeGreen;
color c2 = (MathAbs(corr2) >= InpWarnThresh) ? clrRed : clrLimeGreen;
color c3 = (MathAbs(corr3) >= InpWarnThresh) ? clrRed : clrLimeGreen;
DrawPanel("CorrDash_BG", 10, 10, 160, 90);
int xSym = 90;
int xVal = 20;
DrawCell("CorrDash_Hdr_Sym", "Theme", xSym, 80, clrSilver);
DrawCell("CorrDash_Hdr_Val", "Corr", xVal, 80, clrSilver);
DrawCell("CorrDash_S1_Sym", InpSymbol1, xSym, 60, c1);
DrawCell("CorrDash_S1_Val", DoubleToString(corr1, 2), xVal, 60, c1);
DrawCell("CorrDash_S2_Sym", InpSymbol2, xSym, 40, c2);
DrawCell("CorrDash_S2_Val", DoubleToString(corr2, 2), xVal, 40, c2);
DrawCell("CorrDash_S3_Sym", InpSymbol3, xSym, 20, c3);
DrawCell("CorrDash_S3_Val", DoubleToString(corr3, 2), xVal, 20, c3);
ChartRedraw();
}