Code: Select all
//+------------------------------------------------------------------+
//| OneTicket_Matrix_MT5.mq5 |
//+------------------------------------------------------------------+
#property copyright "Risk-Off Correlation Matrix"
#property indicator_chart_window
#property indicator_plots 0
input string SecTicker = "XAUUSD"; // Secondary Ticker (Match Market Watch)
input int CorrLen = 20; // Correlation Period
input int AtrLen = 14; // ATR Period
input double WarnThresh = 0.75; // Warning Threshold
int atrPriHandle;
int atrSecHandle;
int OnInit() {
atrPriHandle = iATR(_Symbol, PERIOD_CURRENT, AtrLen);
atrSecHandle = iATR(SecTicker, PERIOD_CURRENT, AtrLen);
if(atrPriHandle == INVALID_HANDLE || atrSecHandle == INVALID_HANDLE) {
Print("Failed to load indicators. Check if Secondary Ticker exists.");
return INIT_FAILED;
}
ObjectsDeleteAll(0, "OT_");
return INIT_SUCCEEDED;
}
void OnDeinit(const int reason) {
ObjectsDeleteAll(0, "OT_");
IndicatorRelease(atrPriHandle);
IndicatorRelease(atrSecHandle);
}
void DrawCell(int col, int row, string text, color bg, color fg, int colspan=1)
{
int w = 150, h = 25;
int cellW = w * colspan;
int xDist = 10 + (2 - (col + colspan - 1)) * w;
int yDist = 10 + (4 - row) * h;
string bgName = "OT_BG_" + IntegerToString(col) + "_" + IntegerToString(row);
if(ObjectFind(0, bgName) < 0) {
ObjectCreate(0, bgName, OBJ_RECTANGLE_LABEL, 0, 0, 0);
ObjectSetInteger(0, bgName, OBJPROP_CORNER, CORNER_RIGHT_LOWER);
ObjectSetInteger(0, bgName, OBJPROP_BORDER_TYPE, BORDER_FLAT);
ObjectSetInteger(0, bgName, OBJPROP_BACK, false);
ObjectSetInteger(0, bgName, OBJPROP_ZORDER, 0);
}
ObjectSetInteger(0, bgName, OBJPROP_XDISTANCE, xDist);
ObjectSetInteger(0, bgName, OBJPROP_YDISTANCE, yDist);
ObjectSetInteger(0, bgName, OBJPROP_XSIZE, cellW);
ObjectSetInteger(0, bgName, OBJPROP_YSIZE, h);
ObjectSetInteger(0, bgName, OBJPROP_BGCOLOR, bg);
ObjectSetInteger(0, bgName, OBJPROP_COLOR, clrDimGray);
string txtName = "OT_TXT_" + IntegerToString(col) + "_" + IntegerToString(row);
if(ObjectFind(0, txtName) < 0) {
ObjectCreate(0, txtName, OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(0, txtName, OBJPROP_CORNER, CORNER_RIGHT_LOWER);
ObjectSetInteger(0, txtName, OBJPROP_ANCHOR, ANCHOR_LEFT_UPPER);
ObjectSetString(0, txtName, OBJPROP_FONT, "Arial");
ObjectSetInteger(0, txtName, OBJPROP_FONTSIZE, 9);
ObjectSetInteger(0, txtName, OBJPROP_BACK, false);
ObjectSetInteger(0, txtName, OBJPROP_ZORDER, 1);
}
ObjectSetInteger(0, txtName, OBJPROP_XDISTANCE, xDist + cellW - 10);
ObjectSetInteger(0, txtName, OBJPROP_YDISTANCE, yDist + h - 5);
ObjectSetString(0, txtName, OBJPROP_TEXT, text);
ObjectSetInteger(0, txtName, OBJPROP_COLOR, fg);
}
void UpdateDashboard(double rawCorr, double absCorr, double priAtrPct, double secAtrPct, double priAtr, double secAtr)
{
color bgTitle = clrBlack;
color bgData = C'40,40,40';
color fg = clrWhite;
color corrColor = (absCorr >= WarnThresh) ? clrCrimson : clrForestGreen;
color ruleBg = clrDodgerBlue;
string tighterAsset = (priAtrPct < secAtrPct) ? _Symbol : SecTicker;
int priDig = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
int secDig = (int)SymbolInfoInteger(SecTicker, SYMBOL_DIGITS);
DrawCell(0, 0, "METRIC", bgTitle, fg);
DrawCell(1, 0, _Symbol + " (Pri)", bgTitle, fg);
DrawCell(2, 0, SecTicker + " (Sec)", bgTitle, fg);
DrawCell(0, 1, "Correlation", bgData, fg);
DrawCell(1, 1, DoubleToString(rawCorr, 2), corrColor, fg);
DrawCell(2, 1, (absCorr >= WarnThresh ? "STACKED RISK" : "DIVERSIFIED"), corrColor, fg);
DrawCell(0, 2, "Volatility (ATR %)", bgData, fg);
DrawCell(1, 2, DoubleToString(priAtrPct, 3) + "%", bgData, fg);
DrawCell(2, 2, DoubleToString(secAtrPct, 3) + "%", bgData, fg);
DrawCell(0, 3, "Avg Inval. (Price)", bgData, fg);
DrawCell(1, 3, DoubleToString(priAtr, priDig), bgData, fg);
DrawCell(2, 3, DoubleToString(secAtr, secDig), bgData, fg);
DrawCell(0, 4, "SYSTEM RULE", ruleBg, fg);
string actionText = (absCorr >= WarnThresh) ? "CHOOSE ONE: " + tighterAsset + " is tighter." : "Markets decoupled. Trade independent setups.";
DrawCell(1, 4, actionText, ruleBg, fg, 2);
}
int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
{
if(rates_total < CorrLen) return 0;
// 1. Data Fetching & Strict Time Synchronization
datetime times[];
double priC[];
if(CopyTime(_Symbol, PERIOD_CURRENT, 0, CorrLen, times) < CorrLen) return 0;
if(CopyClose(_Symbol, PERIOD_CURRENT, 0, CorrLen, priC) < CorrLen) return 0;
double meanX = 0, meanY = 0;
int validBars = 0;
double x[], y[];
ArrayResize(x, CorrLen);
ArrayResize(y, CorrLen);
for(int i = 0; i < CorrLen; i++) {
double secCTemp[];
if(CopyClose(SecTicker, PERIOD_CURRENT, times[i], 1, secCTemp) > 0) {
x[validBars] = priC[i];
y[validBars] = secCTemp[0];
meanX += priC[i];
meanY += secCTemp[0];
validBars++;
}
}
// 2. Pearson Correlation Calculation
double rawCorr = 0;
if(validBars > 1) {
meanX /= validBars;
meanY /= validBars;
double cov = 0, varX = 0, varY = 0;
for(int i = 0; i < validBars; i++) {
cov += (x[i] - meanX) * (y[i] - meanY);
varX += MathPow(x[i] - meanX, 2);
varY += MathPow(y[i] - meanY, 2);
}
if(varX > 0 && varY > 0) {
rawCorr = cov / MathSqrt(varX * varY);
}
}
double absCorr = MathAbs(rawCorr);
// 3. Volatility / ATR Calculations via Handles
double priAtrArr[1], secAtrArr[1], curPriArr[1], curSecArr[1];
if(CopyBuffer(atrPriHandle, 0, 0, 1, priAtrArr) <= 0) return 0;
if(CopyBuffer(atrSecHandle, 0, 0, 1, secAtrArr) <= 0) return 0;
if(CopyClose(_Symbol, PERIOD_CURRENT, 0, 1, curPriArr) <= 0) return 0;
if(CopyClose(SecTicker, PERIOD_CURRENT, 0, 1, curSecArr) <= 0) return 0;
double priAtr = priAtrArr[0];
double secAtr = secAtrArr[0];
double priC = curPriArr[0];
double secC = curSecArr[0];
double priAtrPct = (priC > 0) ? (priAtr / priC) * 100.0 : 0;
double secAtrPct = (secC > 0) ? (secAtr / secC) * 100.0 : 0;
// 4. GUI Rendering
UpdateDashboard(rawCorr, absCorr, priAtrPct, secAtrPct, priAtr, secAtr);
return rates_total;
}