//+------------------------------------------------------------------+ //| Correlation Matrix Dashboard PART1.mq5 | //| Copyright 2026, Allan Munene Mutiiria. | //| https://t.me/Forex_Algo_Trader | //+------------------------------------------------------------------+ #property copyright "Copyright 2026, Allan Munene Mutiiria." #property link "https://t.me/Forex_Algo_Trader" #property version "1.00" #include //+------------------------------------------------------------------+ //| Inputs | //+------------------------------------------------------------------+ input string SymbolsList = "EURUSDm,GBPUSDm,USDJPYm,AUDUSDm,BTCUSDm,NZDUSDm,US500m,XAUUSDm"; // Comma-separated symbols (up to 30) input ENUM_TIMEFRAMES CorrelationTimeframe = PERIOD_CURRENT; // Timeframe for correlation calculation input int CorrelationBars = 100; // Number of bars for correlation calculation (min 20) input double StrongPositiveThresholdPct = 70.0; // Strong positive threshold in % (e.g., 70.0 for >=0.70) input double StrongNegativeThresholdPct = -70.0; // Strong negative threshold in % (e.g., -70.0 for <=-0.70) input double PValueThreshold1 = 0.01; // P-value for *** significance input double PValueThreshold2 = 0.05; // P-value for ** significance input double PValueThreshold3 = 0.10; // P-value for * significance input color ColorStrongPositiveBg = clrLimeGreen; // Background for strong positive input color ColorStrongNegativeBg = clrOrangeRed; // Background for strong negative input color ColorNeutralBg = C'70,70,70'; // Background for neutral/mild/zero/diagonal cells input color ColorDiagonalBg = C'40,40,40'; // Background for diagonal cells input color ColorTextStrong = clrWhite; // Text color for strong correlations input color ColorTextPositive = clrDeepSkyBlue; // Text color for mild positive input color ColorTextNegative = clrRed; // Text color for mild negative input color ColorTextZero = clrWhite; // Text color for zero or diagonal //+------------------------------------------------------------------+ //| Enumerations | //+------------------------------------------------------------------+ enum DisplayMode { MODE_STANDARD, // Standard Thresholds MODE_HEATMAP // Heatmap Gradient }; input DisplayMode DashboardMode = MODE_STANDARD; // Dashboard Display Mode enum CorrelationMethod { PEARSON, // Pearson correlation SPEARMAN, // Spearman rank correlation KENDALL // Kendall tau correlation }; input CorrelationMethod CorrMethod = PEARSON; // Correlation calculation method //+------------------------------------------------------------------+ //| Defines | //+------------------------------------------------------------------+ #define MAIN_PANEL "PANEL_MAIN" // Define main panel rectangle identifier #define HEADER_PANEL "PANEL_HEADER" // Define header panel rectangle identifier #define LEGEND_PANEL "PANEL_LEGEND" // Define legend panel rectangle identifier #define HEADER_PANEL_ICON "PANEL_HEADER_ICON" // Define header icon label identifier #define HEADER_PANEL_TEXT "PANEL_HEADER_TEXT" // Define header title label identifier #define CLOSE_BUTTON "BUTTON_CLOSE" // Define close button identifier #define TOGGLE_BUTTON "BUTTON_TOGGLE" // Define toggle (minimize/maximize) button identifier #define HEATMAP_BUTTON "BUTTON_HEATMAP" // Define heatmap toggle button identifier #define PVAL_BUTTON "BUTTON_PVAL" // Define P-value toggle button identifier #define SORT_BUTTON "BUTTON_SORT" // Define sort button identifier #define THEME_BUTTON "BUTTON_THEME" // Define theme toggle button identifier #define TF_CELL_RECT "TF_CELL_RECT_" // Define timeframe cell rectangle prefix #define TF_CELL_TEXT "TF_CELL_TEXT_" // Define timeframe cell text prefix #define SYMBOL_ROW_RECTANGLE "SYMBOL_ROW_" // Define row symbol rectangle prefix #define SYMBOL_ROW_TEXT "SYMBOL_ROW_TEXT_" // Define row symbol text label prefix #define SYMBOL_COL_RECTANGLE "SYMBOL_COL_" // Define column symbol rectangle prefix #define SYMBOL_COL_TEXT "SYMBOL_COL_TEXT_" // Define column symbol text label prefix #define CELL_RECTANGLE "CELL_" // Define correlation cell rectangle prefix #define CELL_TEXT "CELL_TEXT_" // Define correlation cell text label prefix #define LEGEND_CELL_RECTANGLE "LEGEND_CELL_" // Define legend cell rectangle prefix #define LEGEND_CELL_TEXT "LEGEND_CELL_TEXT_" // Define legend cell text prefix #define WIDTH_SYMBOL 80 // Define width of symbol rectangles #define WIDTH_CELL 80 // Define width of correlation cells #define WIDTH_TF_CELL 45 // Define width of TF cells #define WIDTH_LEGEND_CELL 45 // Define width of legend cells #define HEIGHT_RECTANGLE 30 // Define height of all rectangles #define HEIGHT_HEADER 27 // Define height of header #define HEIGHT_TF_CELL 25 // Define height of TF cells #define HEIGHT_LEGEND 30 // Define height of legend cells #define HEIGHT_LEGEND_PANEL 34 // Define height of legend panel (with padding) #define LEGEND_SPACING 5 // Define spacing between legend cells #define NUM_LEGEND_ITEMS 15 // Define increased to cover max possible (e.g., 11 in heatmap) #define GAP_HEIGHT 8 // Define gap between sections #define GAP_MAIN_LEGEND 2 // Define vertical gap between main panel and legend #define COLOR_WHITE clrWhite // Define white color for text and backgrounds #define COLOR_BLACK clrBlack // Define black color for borders and text #define COLOR_LIGHT_GRAY C'230,230,230' // Define light gray for neutral cells #define COLOR_DARK_GRAY C'105,105,105' // Define dark gray for headers #define MAX_SYMBOLS 30 // Define maximum symbols supported #define NUM_TF 8 // Define number of timeframes //+------------------------------------------------------------------+ //| Global Variables | //+------------------------------------------------------------------+ int panel_x = 20, panel_y = 40; //--- Initialize panel position coordinates string symbols_array[MAX_SYMBOLS]; //--- Declare array to store symbols int num_symbols = 0; //--- Initialize number of valid symbols double correlation_matrix[MAX_SYMBOLS][MAX_SYMBOLS]; //--- Declare matrix to store correlations double pvalue_matrix[MAX_SYMBOLS][MAX_SYMBOLS]; //--- Declare matrix to store p-values DisplayMode global_display_mode; //--- Declare runtime display mode ENUM_TIMEFRAMES global_correlation_tf; //--- Declare runtime timeframe int current_tf_index = -1; //--- Initialize index of current TF int num_tf_visible; //--- Declare dynamic number of visible TF cells int num_legend_visible; //--- Declare dynamic number of visible legend items double visible_corr_vals[]; //--- Declare array of visible correlation values for legend ENUM_TIMEFRAMES tf_list[NUM_TF] = {PERIOD_M1, PERIOD_M5, PERIOD_M15, PERIOD_M30, PERIOD_H1, PERIOD_H4, PERIOD_D1, PERIOD_W1}; //--- Initialize timeframe list string tf_strings[NUM_TF] = {"M1", "M5", "M15", "M30", "H1", "H4", "D1", "W1"}; //--- Initialize timeframe strings // Enhanced gradient colors for heatmap color heatmap_colors[] = {clrRed, clrOrangeRed, clrOrange, clrYellow, clrLightGray, clrLime, clrLimeGreen, clrGreen}; //--- Initialize heatmap color gradient array //+------------------------------------------------------------------+ //| Approximate Normal CDF | //+------------------------------------------------------------------+ bool NormalCDF(double mean, double stddev, double x, double &cdf) { if (stddev <= 0.0) return false; //--- Check for invalid standard deviation double z = (x - mean) / stddev; //--- Compute z-score if (z < -10) { //--- Handle extreme low z-value cdf = 0.0; //--- Set CDF to 0 return true; //--- Return success } if (z > 10) { //--- Handle extreme high z-value cdf = 1.0; //--- Set CDF to 1 return true; //--- Return success } double t = 1 / (1 + 0.2316419 * MathAbs(z)); //--- Compute t for approximation double d = 0.3989423 * MathExp(-z * z / 2); //--- Compute density d cdf = d * t * (0.3193815 + t * (-0.3565638 + t * (1.7814779 + t * (-1.821256 + t * 1.3302744)))); //--- Calculate CDF approximation if (z > 0) cdf = 1 - cdf; //--- Adjust for positive z return true; //--- Return success } //+------------------------------------------------------------------+ //| Approximate Student t CDF | //+------------------------------------------------------------------+ bool StudentCDF(int df, double x, double &cdf) { if (df <= 0) return false; //--- Check for invalid degrees of freedom double a = df / 2.0; //--- Compute alpha parameter double b = 0.5; //--- Set beta parameter double xt = df / (df + x * x); //--- Compute xt for incomplete beta double ib = MathBetaIncomplete(xt, a, b); //--- Compute incomplete beta double beta = MathExp(MathGammaLog(a) + MathGammaLog(b) - MathGammaLog(a + b)); //--- Compute beta function double regularized = ib / beta; //--- Compute regularized incomplete beta if (x >= 0) { //--- Handle non-negative x cdf = 1 - 0.5 * regularized; //--- Set CDF for positive side } else { //--- Handle negative x cdf = 0.5 * regularized; //--- Set CDF for negative side } return true; //--- Return success } //+------------------------------------------------------------------+ //| Calculate p-value based on method and correlation | //+------------------------------------------------------------------+ double calculate_pvalue(double corr, CorrelationMethod method, int n) { if (n < 3) return 1.0; //--- Return invalid if insufficient samples double cdf = 0.0; //--- Initialize CDF variable if (method == KENDALL) { //--- Handle Kendall method double sigma = MathSqrt((4.0 * n + 10.0) / (9.0 * n * (n - 1.0))); //--- Compute sigma if (sigma == 0) return 1.0; //--- Return invalid if sigma zero double z = corr / sigma; //--- Compute z-score if (!NormalCDF(0, 1, MathAbs(z), cdf)) return 1.0; //--- Compute Normal CDF or return invalid return 2 * (1 - cdf); //--- Return two-tailed p-value } else { //--- Handle PEARSON or SPEARMAN double r2 = corr * corr; //--- Compute squared correlation if (r2 >= 1.0) return 0.0; //--- Return zero for perfect correlation double denom = 1.0 - r2; //--- Compute denominator if (denom <= 0.0) return 0.0; //--- Avoid division by zero double t = corr * MathSqrt((n - 2.0) / denom); //--- Compute t-statistic if (!StudentCDF(n - 2, MathAbs(t), cdf)) return 1.0; //--- Compute Student CDF or return invalid return 2 * (1 - cdf); //--- Return two-tailed p-value } } //+------------------------------------------------------------------+ //| Parse symbols list into array | //+------------------------------------------------------------------+ void parse_symbols() { string temp = SymbolsList; //--- Copy input symbols list num_symbols = 0; //--- Reset symbol count while (StringFind(temp, ",") >= 0 && num_symbols < MAX_SYMBOLS) { //--- Loop through comma-separated symbols int pos = StringFind(temp, ","); //--- Find comma position string sym = StringSubstr(temp, 0, pos); //--- Extract symbol if (SymbolSelect(sym, true)) { //--- Select symbol if available symbols_array[num_symbols] = sym; //--- Store valid symbol num_symbols++; //--- Increment count } else { //--- Handle unavailable symbol Print("Warning: Symbol ", sym, " not available."); //--- Print warning } temp = StringSubstr(temp, pos + 1); //--- Update remaining string } if (StringLen(temp) > 0 && num_symbols < MAX_SYMBOLS) { //--- Handle last symbol if (SymbolSelect(temp, true)) { //--- Select last symbol if available symbols_array[num_symbols] = temp; //--- Store last valid symbol num_symbols++; //--- Increment count } else { //--- Handle unavailable last symbol Print("Warning: Symbol ", temp, " not available."); //--- Print warning } } if (num_symbols < 2) { //--- Check minimum symbols Print("Error: At least 2 valid symbols required. Found: ", num_symbols); //--- Print error ExpertRemove(); //--- Remove expert } } //+------------------------------------------------------------------+ //| Rank data for Spearman correlation | //+------------------------------------------------------------------+ void rank_data(const double &data[], double &ranks[]) { int size = ArraySize(data); //--- Get data size int indices[]; //--- Declare indices array ArrayResize(indices, size); //--- Resize indices for (int i = 0; i < size; i++) indices[i] = i; //--- Initialize indices // Sort indices based on data values for (int i = 0; i < size - 1; i++) { //--- Loop outer for sorting for (int j = i + 1; j < size; j++) { //--- Loop inner for comparison if (data[indices[i]] > data[indices[j]]) { //--- Check if swap needed int temp = indices[i]; //--- Store temporary indices[i] = indices[j]; //--- Swap indices indices[j] = temp; //--- Complete swap } } } // Assign ranks, handling ties for (int i = 0; i < size; ) { //--- Loop through sorted indices int start = i; //--- Set start of tie group double value = data[indices[i]]; //--- Get current value while (i < size && data[indices[i]] == value) i++; //--- Skip ties double rank = (start + i - 1) / 2.0 + 1.0; //--- Compute average rank for (int k = start; k < i; k++) { //--- Assign rank to group ranks[indices[k]] = rank; //--- Set rank } } } //+------------------------------------------------------------------+ //| Calculate Pearson correlation | //+------------------------------------------------------------------+ double pearson_correlation(const double &deltas1[], const double &deltas2[], int size) { double mean1 = 0, mean2 = 0; //--- Initialize means for (int i = 0; i < size; i++) { //--- Loop to compute sums mean1 += deltas1[i]; //--- Accumulate first deltas mean2 += deltas2[i]; //--- Accumulate second deltas } mean1 /= size; //--- Compute first mean mean2 /= size; //--- Compute second mean double var1 = 0, var2 = 0, cov = 0; //--- Initialize variances and covariance for (int i = 0; i < size; i++) { //--- Loop to compute deviations double dev1 = deltas1[i] - mean1; //--- Compute first deviation double dev2 = deltas2[i] - mean2; //--- Compute second deviation var1 += dev1 * dev1; //--- Accumulate first variance var2 += dev2 * dev2; //--- Accumulate second variance cov += dev1 * dev2; //--- Accumulate covariance } if (var1 == 0 || var2 == 0) return 0.0; //--- Return zero if no variance return cov / MathSqrt(var1 * var2); //--- Return correlation } //+------------------------------------------------------------------+ //| Calculate Spearman correlation | //+------------------------------------------------------------------+ double spearman_correlation(const double &deltas1[], const double &deltas2[], int size) { double ranks1[], ranks2[]; //--- Declare rank arrays ArrayResize(ranks1, size); //--- Resize first ranks ArrayResize(ranks2, size); //--- Resize second ranks rank_data(deltas1, ranks1); //--- Rank first deltas rank_data(deltas2, ranks2); //--- Rank second deltas return pearson_correlation(ranks1, ranks2, size); //--- Return Pearson on ranks } //+------------------------------------------------------------------+ //| Calculate Kendall correlation | //+------------------------------------------------------------------+ double kendall_correlation(const double &deltas1[], const double &deltas2[], int size) { int concordant = 0, discordant = 0; //--- Initialize pair counts for (int i = 0; i < size - 1; i++) { //--- Loop outer pairs for (int j = i + 1; j < size; j++) { //--- Loop inner pairs double sign1 = deltas1[i] - deltas1[j]; //--- Compute first sign double sign2 = deltas2[i] - deltas2[j]; //--- Compute second sign if (sign1 * sign2 > 0) concordant++; //--- Increment concordant else if (sign1 * sign2 < 0) discordant++; //--- Increment discordant // Ties are ignored in basic Kendall tau } } int total_pairs = size * (size - 1) / 2; //--- Compute total pairs if (total_pairs == 0) return 0.0; //--- Return zero if no pairs return (concordant - discordant) / (double)total_pairs; //--- Return tau } //+------------------------------------------------------------------+ //| Calculate correlation based on method | //+------------------------------------------------------------------+ double calculate_correlation(string sym1, string sym2) { if (sym1 == sym2) return 1.0; //--- Return self-correlation double prices1[], prices2[]; //--- Declare price arrays ArrayResize(prices1, CorrelationBars); //--- Resize first prices ArrayResize(prices2, CorrelationBars); //--- Resize second prices if (CopyClose(sym1, global_correlation_tf, 0, CorrelationBars, prices1) < CorrelationBars || //--- Copy first closes or check failure CopyClose(sym2, global_correlation_tf, 0, CorrelationBars, prices2) < CorrelationBars) { return 0.0; //--- Return insufficient data } // Compute price changes (deltas) double deltas1[], deltas2[]; //--- Declare delta arrays ArrayResize(deltas1, CorrelationBars - 1); //--- Resize first deltas ArrayResize(deltas2, CorrelationBars - 1); //--- Resize second deltas for (int i = 0; i < CorrelationBars - 1; i++) { //--- Loop to compute deltas deltas1[i] = prices1[i + 1] - prices1[i]; //--- Set first delta deltas2[i] = prices2[i + 1] - prices2[i]; //--- Set second delta } int size = CorrelationBars - 1; //--- Set effective size switch (CorrMethod) { //--- Switch on method case PEARSON: //--- Handle Pearson return pearson_correlation(deltas1, deltas2, size); //--- Return Pearson result case SPEARMAN: //--- Handle Spearman return spearman_correlation(deltas1, deltas2, size); //--- Return Spearman result case KENDALL: //--- Handle Kendall return kendall_correlation(deltas1, deltas2, size); //--- Return Kendall result default: //--- Handle default return 0.0; //--- Return zero } } //+------------------------------------------------------------------+ //| Update correlation matrix values | //+------------------------------------------------------------------+ void update_correlations() { int n = CorrelationBars - 1; //--- Set sample size if (n < 2) { //--- Check minimum bars Print("Error: Insufficient bars for correlation (need at least 3)."); //--- Print error return; //--- Exit function } for (int i = 0; i < num_symbols; i++) { //--- Loop rows for (int j = 0; j < num_symbols; j++) { //--- Loop columns double corr = calculate_correlation(symbols_array[i], symbols_array[j]); //--- Compute correlation correlation_matrix[i][j] = corr; //--- Store correlation if (i == j) { //--- Handle diagonal pvalue_matrix[i][j] = 0.0; //--- Set p-value to zero } else if (corr == 0.0 && n < 3) { //--- Handle insufficient data pvalue_matrix[i][j] = 1.0; //--- Set p-value to one } else { //--- Handle normal case pvalue_matrix[i][j] = calculate_pvalue(corr, CorrMethod, n); //--- Compute and store p-value } } } } //+------------------------------------------------------------------+ //| Get significance stars based on p-value | //+------------------------------------------------------------------+ string get_significance_stars(double pval) { if (pval < PValueThreshold1) return "***"; //--- Return three stars if (pval < PValueThreshold2) return "**"; //--- Return two stars if (pval < PValueThreshold3) return "*"; //--- Return one star return ""; //--- Return empty } //+------------------------------------------------------------------+ //| Interpolate between multiple colors based on value (-1 to 1) | //+------------------------------------------------------------------+ color interpolate_heatmap_color(double value) { if (value == 0.0) return ColorNeutralBg; //--- Return neutral for zero double abs_val = MathAbs(value); //--- Compute absolute value int num_stops = ArraySize(heatmap_colors) / 2; //--- Compute stops per side double step = 1.0 / (num_stops - 1); //--- Compute step size if (value > 0.0) { //--- Handle positive int idx = (int)MathFloor(abs_val / step); //--- Compute index if (idx >= num_stops - 1) idx = num_stops - 2; //--- Clamp index double factor = (abs_val - idx * step) / step; //--- Compute factor return interpolate_color(heatmap_colors[idx + num_stops], heatmap_colors[idx + num_stops + 1], factor); //--- Interpolate positive } else { //--- Handle negative int idx = (int)MathFloor(abs_val / step); //--- Compute index if (idx >= num_stops - 1) idx = num_stops - 2; //--- Clamp index double factor = (abs_val - idx * step) / step; //--- Compute factor return interpolate_color(heatmap_colors[idx], heatmap_colors[idx + 1], factor); //--- Interpolate negative } } //+------------------------------------------------------------------+ //| Interpolate between two colors based on factor (0 to 1) | //+------------------------------------------------------------------+ color interpolate_color(color c1, color c2, double factor) { uchar r1 = (uchar)(c1 & 0xFF), g1 = (uchar)((c1 >> 8) & 0xFF), b1 = (uchar)((c1 >> 16) & 0xFF); //--- Extract RGB from first color uchar r2 = (uchar)(c2 & 0xFF), g2 = (uchar)((c2 >> 8) & 0xFF), b2 = (uchar)((c2 >> 16) & 0xFF); //--- Extract RGB from second color uchar r = (uchar)MathMax(0, MathMin(255, r1 + factor * (r2 - r1) + 0.5)); //--- Interpolate red uchar g = (uchar)MathMax(0, MathMin(255, g1 + factor * (g2 - g1) + 0.5)); //--- Interpolate green uchar b = (uchar)MathMax(0, MathMin(255, b1 + factor * (b2 - b1) + 0.5)); //--- Interpolate blue return (color)((b << 16) | (g << 8) | r); //--- Return interpolated color } //+------------------------------------------------------------------+ //| Create rectangle for UI | //+------------------------------------------------------------------+ bool create_rectangle(string object_name, int x_distance, int y_distance, int x_size, int y_size, color background_color, color border_color = clrNONE) { if (!ObjectCreate(0, object_name, OBJ_RECTANGLE_LABEL, 0, 0, 0)) { //--- Create rectangle or check failure Print(__FUNCTION__, ": failed to create Rectangle: ", GetLastError()); //--- Print error return false; //--- Return failure } ObjectSetInteger(0, object_name, OBJPROP_XDISTANCE, x_distance); //--- Set x distance ObjectSetInteger(0, object_name, OBJPROP_YDISTANCE, y_distance); //--- Set y distance ObjectSetInteger(0, object_name, OBJPROP_XSIZE, x_size); //--- Set x size ObjectSetInteger(0, object_name, OBJPROP_YSIZE, y_size); //--- Set y size ObjectSetInteger(0, object_name, OBJPROP_CORNER, CORNER_LEFT_UPPER); //--- Set corner ObjectSetInteger(0, object_name, OBJPROP_BGCOLOR, background_color); //--- Set background ObjectSetInteger(0, object_name, OBJPROP_COLOR, border_color); //--- Set border color ObjectSetInteger(0, object_name, OBJPROP_BORDER_TYPE, BORDER_FLAT); //--- Set border type ObjectSetInteger(0, object_name, OBJPROP_BACK, false); //--- Set back property return true; //--- Return success } //+------------------------------------------------------------------+ //| Create text label for UI | //+------------------------------------------------------------------+ bool create_label(string object_name, string text, int x_distance, int y_distance, int font_size = 10, color text_color = COLOR_WHITE, string font = "Arial Rounded MT Bold") { if (!ObjectCreate(0, object_name, OBJ_LABEL, 0, 0, 0)) { //--- Create label or check failure Print(__FUNCTION__, ": failed to create Label: ", GetLastError()); //--- Print error return false; //--- Return failure } ObjectSetInteger(0, object_name, OBJPROP_XDISTANCE, x_distance); //--- Set x distance ObjectSetInteger(0, object_name, OBJPROP_YDISTANCE, y_distance); //--- Set y distance ObjectSetInteger(0, object_name, OBJPROP_CORNER, CORNER_LEFT_UPPER); //--- Set corner ObjectSetString(0, object_name, OBJPROP_TEXT, text); //--- Set text ObjectSetString(0, object_name, OBJPROP_FONT, font); //--- Set font ObjectSetInteger(0, object_name, OBJPROP_FONTSIZE, font_size); //--- Set font size ObjectSetInteger(0, object_name, OBJPROP_COLOR, text_color); //--- Set text color ObjectSetInteger(0, object_name, OBJPROP_ANCHOR, ANCHOR_CENTER); //--- Set anchor return true; //--- Return success } //+------------------------------------------------------------------+ //| Update TF highlights | //+------------------------------------------------------------------+ void update_tf_highlights() { color inactive_bg = C'60,60,60'; //--- Set inactive background for (int i = 0; i < num_tf_visible; i++) { //--- Loop visible TFs string rect_name = TF_CELL_RECT + IntegerToString(i); //--- Get rectangle name color bg = (i == current_tf_index) ? ColorStrongPositiveBg : inactive_bg; //--- Set background ObjectSetInteger(0, rect_name, OBJPROP_BGCOLOR, bg); //--- Update background } ChartRedraw(0); //--- Redraw chart } //+------------------------------------------------------------------+ //| Recreate legend objects based on current mode | //+------------------------------------------------------------------+ void recreate_legend() { // Delete existing legend objects for (int i = 0; i < NUM_LEGEND_ITEMS; i++) { //--- Loop legend items ObjectDelete(0, LEGEND_CELL_RECTANGLE + IntegerToString(i)); //--- Delete rectangle ObjectDelete(0, LEGEND_CELL_TEXT + IntegerToString(i)); //--- Delete text } // Define full correlation values based on mode (more points for finer legend) double full_corr_vals[]; //--- Declare full values array if (global_display_mode == MODE_HEATMAP) { //--- Handle heatmap mode double heatmap_vals[] = {-1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0}; //--- Set heatmap values ArrayCopy(full_corr_vals, heatmap_vals); //--- Copy to full } else { //--- Handle standard mode double standard_vals[] = {StrongNegativeThresholdPct / 100.0, -0.75, -0.5, -0.25, 0.0, 0.25, 0.5, 0.75, StrongPositiveThresholdPct / 100.0, 1.0}; //--- Set standard values ArrayCopy(full_corr_vals, standard_vals); //--- Copy to full } // Copy to visible and reduce dynamically if needed ArrayCopy(visible_corr_vals, full_corr_vals); //--- Copy to visible int panel_width = WIDTH_SYMBOL + num_symbols * (WIDTH_CELL - 1) + 4; //--- Compute panel width int available_width = panel_width - 4; //--- Compute available width double item_cost = WIDTH_LEGEND_CELL + LEGEND_SPACING; //--- Compute item cost int max_fit = (int)MathFloor((available_width + LEGEND_SPACING) / item_cost); //--- Compute max fit if (max_fit < 1) max_fit = 1; //--- Ensure minimum fit while (ArraySize(visible_corr_vals) > max_fit) { //--- Loop to reduce int sz = ArraySize(visible_corr_vals); //--- Get current size int zero_pos = -1; //--- Initialize zero position for (int p = 0; p < sz; p++) { //--- Loop to find zero if (visible_corr_vals[p] == 0.0) { //--- Check for zero zero_pos = p; //--- Set position break; //--- Exit loop } } if (zero_pos >= 0) { //--- Handle found zero ArrayRemove(visible_corr_vals, zero_pos, 1); //--- Remove zero continue; //--- Continue reduction } // Find min abs > 0 double min_abs = DBL_MAX; //--- Initialize min abs for (int p = 0; p < sz; p++) { //--- Loop to find min double av = MathAbs(visible_corr_vals[p]); //--- Get absolute if (av > 0 && av < min_abs) min_abs = av; //--- Update min } if (min_abs == DBL_MAX) break; //--- Exit if no more // Remove all == ±min_abs for (int p = sz - 1; p >= 0; p--) { //--- Loop backward to remove if (MathAbs(visible_corr_vals[p]) == min_abs) ArrayRemove(visible_corr_vals, p, 1); //--- Remove match } } num_legend_visible = ArraySize(visible_corr_vals); //--- Set visible count // Calculate positions int panel_height = HEIGHT_HEADER + HEIGHT_TF_CELL + GAP_HEIGHT + HEIGHT_RECTANGLE * (num_symbols + 1) - num_symbols + 2; //--- Compute panel height int legend_y = panel_y + panel_height + GAP_MAIN_LEGEND; //--- Compute legend y int total_legend_width = num_legend_visible * WIDTH_LEGEND_CELL + (num_legend_visible - 1) * LEGEND_SPACING; //--- Compute total width int x_start = panel_x + (panel_width - total_legend_width) / 2; //--- Compute start x color neutral_bg = ColorNeutralBg; //--- Set neutral background color text_color = COLOR_WHITE; //--- Set text color // Create new legend objects for (int i = 0; i < num_legend_visible; i++) { //--- Loop to create int x_offset = x_start + i * (WIDTH_LEGEND_CELL + LEGEND_SPACING); //--- Compute offset string rect_name = LEGEND_CELL_RECTANGLE + IntegerToString(i); //--- Get rectangle name string text_name = LEGEND_CELL_TEXT + IntegerToString(i); //--- Get text name create_rectangle(rect_name, x_offset, legend_y + 2, WIDTH_LEGEND_CELL, HEIGHT_LEGEND, neutral_bg); //--- Create rectangle create_label(text_name, "0%", x_offset + WIDTH_LEGEND_CELL / 2, legend_y + 2 + HEIGHT_LEGEND / 2 - 1, 10, text_color, "Arial"); //--- Create label } } //+------------------------------------------------------------------+ //| Update legend colors and texts based on mode | //+------------------------------------------------------------------+ void update_legend() { color default_txt = ColorTextStrong; //--- Set default text color for (int i = 0; i < num_legend_visible; i++) { //--- Loop visible legends string rect_name = LEGEND_CELL_RECTANGLE + IntegerToString(i); //--- Get rectangle name string text_name = LEGEND_CELL_TEXT + IntegerToString(i); //--- Get text name double corr = visible_corr_vals[i]; //--- Get correlation value int decimals = (MathAbs(corr) == 0.5 || corr == 0.0 || MathAbs(corr) == 1.0) ? 0 : 1; //--- Set decimals string txt_str = DoubleToString(corr * 100, decimals) + "%"; //--- Format text color bg_color = ColorNeutralBg; //--- Initialize background color txt_color = default_txt; //--- Initialize text color if (corr == 1.0) { //--- Handle perfect positive bg_color = ColorDiagonalBg; //--- Set diagonal background txt_color = default_txt; //--- Set text color } else if (corr == 0.0) { //--- Handle zero bg_color = ColorNeutralBg; //--- Set neutral background txt_color = default_txt; //--- Set text color } else { //--- Handle other values if (global_display_mode == MODE_STANDARD) { //--- Handle standard mode double strong_pos = StrongPositiveThresholdPct / 100.0; //--- Set positive threshold double strong_neg = StrongNegativeThresholdPct / 100.0; //--- Set negative threshold if (corr >= strong_pos) { //--- Check strong positive bg_color = ColorStrongPositiveBg; //--- Set positive background txt_color = default_txt; //--- Set text color } else if (corr <= strong_neg) { //--- Check strong negative bg_color = ColorStrongNegativeBg; //--- Set negative background txt_color = default_txt; //--- Set text color } else { //--- Handle mild bg_color = ColorNeutralBg; //--- Set neutral background txt_color = (corr > 0.0) ? ColorTextPositive : ColorTextNegative; //--- Set mild text color } } else { //--- Handle heatmap mode txt_color = default_txt; //--- Set text color bg_color = interpolate_heatmap_color(corr); //--- Interpolate background } } ObjectSetInteger(0, rect_name, OBJPROP_BGCOLOR, bg_color); //--- Update background ObjectSetString(0, text_name, OBJPROP_TEXT, txt_str); //--- Update text ObjectSetInteger(0, text_name, OBJPROP_COLOR, txt_color); //--- Update text color } ChartRedraw(0); //--- Redraw chart } //+------------------------------------------------------------------+ //| Create full dashboard UI | //+------------------------------------------------------------------+ void create_full_dashboard() { color main_bg = C'30,30,30'; //--- Set main background color header_bg = C'60,60,60'; //--- Set header background color text_color = COLOR_WHITE; //--- Set text color color neutral_bg = ColorNeutralBg; //--- Set neutral background color button_text = clrGold; //--- Set button text color color theme_icon_color = clrWhite; //--- Set theme icon color color close_text = clrWhite; //--- Set close text color color header_icon_color = clrAqua; //--- Set header icon color int panel_width = WIDTH_SYMBOL + num_symbols * (WIDTH_CELL - 1) + 4; //--- Compute panel width int panel_height = HEIGHT_HEADER + HEIGHT_TF_CELL + GAP_HEIGHT + HEIGHT_RECTANGLE * (num_symbols + 1) - num_symbols + 2; //--- Compute panel height create_rectangle(MAIN_PANEL, panel_x, panel_y, panel_width, panel_height, main_bg); //--- Create main panel create_rectangle(HEADER_PANEL, panel_x, panel_y, panel_width, HEIGHT_HEADER, header_bg); //--- Create header panel create_label(HEADER_PANEL_ICON, CharToString(181), panel_x + 12, panel_y + 14, 18, header_icon_color, "Wingdings"); //--- Create header icon create_label(HEADER_PANEL_TEXT, "Correlation Matrix", panel_x + 90, panel_y + 12, 13, text_color); //--- Create header text create_label(CLOSE_BUTTON, CharToString('r'), panel_x + (panel_width - 17), panel_y + 14, 18, close_text, "Webdings"); //--- Create close button create_label(TOGGLE_BUTTON, CharToString('r'), panel_x + (panel_width - 47), panel_y + 14, 18, button_text, "Wingdings"); //--- Create toggle button string heatmap_icon = CharToString(global_display_mode == MODE_STANDARD ? (uchar)82 : (uchar)110); //--- Set heatmap icon create_label(HEATMAP_BUTTON, heatmap_icon, panel_x + (panel_width - 77), panel_y + 14, 18, button_text, "Wingdings"); //--- Create heatmap button create_label(PVAL_BUTTON, CharToString('X'), panel_x + (panel_width - 107), panel_y + 14, 18, button_text, "Wingdings"); //--- Create PVAL button string sort_icon = CharToString('N'); //--- Set sort icon create_label(SORT_BUTTON, sort_icon, panel_x + (panel_width - 137), panel_y + 14, 18, button_text, "Wingdings 3"); //--- Create sort button create_label(THEME_BUTTON, CharToString('['), panel_x + (panel_width - 167), panel_y + 14, 18, theme_icon_color, "Wingdings"); //--- Create theme button // Timeframe cells row int tf_y = panel_y + HEIGHT_HEADER; //--- Compute TF y position int tf_x_start = panel_x + 2; //--- Set TF start x for (int i = 0; i < num_tf_visible; i++) { //--- Loop visible TFs int x_offset = tf_x_start + i * WIDTH_TF_CELL; //--- Compute offset string rect_name = TF_CELL_RECT + IntegerToString(i); //--- Get rectangle name string text_name = TF_CELL_TEXT + IntegerToString(i); //--- Get text name color bg = (i == current_tf_index) ? ColorStrongPositiveBg : header_bg; //--- Set background create_rectangle(rect_name, x_offset, tf_y, WIDTH_TF_CELL, HEIGHT_TF_CELL, bg); //--- Create TF rectangle create_label(text_name, tf_strings[i], x_offset + (WIDTH_TF_CELL / 2), tf_y + (HEIGHT_TF_CELL / 2), 10, text_color, "Arial Bold"); //--- Create TF text } // Create row symbols (left column), pushed down int matrix_y = tf_y + HEIGHT_TF_CELL + GAP_HEIGHT; //--- Compute matrix y create_rectangle("SYMBOL_ROW_HEADER", panel_x + 2, matrix_y, WIDTH_SYMBOL, HEIGHT_RECTANGLE, header_bg); //--- Create row header rectangle create_label("SYMBOL_ROW_HEADER_TEXT", "Symbols", panel_x + (WIDTH_SYMBOL / 2 + 2), matrix_y + (HEIGHT_RECTANGLE / 2), 10, text_color, "Arial Bold"); //--- Create row header text for (int i = 0; i < num_symbols; i++) { //--- Loop row symbols int y_offset = matrix_y + HEIGHT_RECTANGLE * (i + 1) - (1 + i); //--- Compute y offset create_rectangle(SYMBOL_ROW_RECTANGLE + IntegerToString(i), panel_x + 2, y_offset, WIDTH_SYMBOL, HEIGHT_RECTANGLE, header_bg); //--- Create row rectangle create_label(SYMBOL_ROW_TEXT + IntegerToString(i), symbols_array[i], panel_x + (WIDTH_SYMBOL / 2 + 2), y_offset + (HEIGHT_RECTANGLE / 2 - 1), 10, text_color, "Arial Bold"); //--- Create row text } // Create column symbols (top row), pushed down for (int j = 0; j < num_symbols; j++) { //--- Loop column symbols int x_offset = panel_x + WIDTH_SYMBOL + j * WIDTH_CELL - j + 1; //--- Compute x offset create_rectangle(SYMBOL_COL_RECTANGLE + IntegerToString(j), x_offset, matrix_y, WIDTH_CELL, HEIGHT_RECTANGLE, header_bg); //--- Create column rectangle create_label(SYMBOL_COL_TEXT + IntegerToString(j), symbols_array[j], x_offset + (WIDTH_CELL / 2), matrix_y + (HEIGHT_RECTANGLE / 2), 10, text_color, "Arial Bold"); //--- Create column text } // Create correlation cells, pushed down for (int i = 0; i < num_symbols; i++) { //--- Loop rows for cells int y_offset = matrix_y + HEIGHT_RECTANGLE * (i + 1) - (1 + i); //--- Compute y offset for (int j = 0; j < num_symbols; j++) { //--- Loop columns for cells string cell_name = CELL_RECTANGLE + IntegerToString(i) + "_" + IntegerToString(j); //--- Get cell name string text_name = CELL_TEXT + IntegerToString(i) + "_" + IntegerToString(j); //--- Get text name int x_offset = panel_x + WIDTH_SYMBOL + j * WIDTH_CELL - j + 1; //--- Compute x offset create_rectangle(cell_name, x_offset, y_offset, WIDTH_CELL, HEIGHT_RECTANGLE, neutral_bg); //--- Create cell rectangle create_label(text_name, "0.00", x_offset + (WIDTH_CELL / 2), y_offset + (HEIGHT_RECTANGLE / 2 - 1), 10, text_color, "Arial"); //--- Create cell text } } // Create separate legend panel int legend_y = panel_y + panel_height + GAP_MAIN_LEGEND; //--- Compute legend y create_rectangle(LEGEND_PANEL, panel_x, legend_y, panel_width, HEIGHT_LEGEND_PANEL, main_bg); //--- Create legend panel recreate_legend(); //--- Recreate legend ChartRedraw(0); //--- Redraw chart } //+------------------------------------------------------------------+ //| Update dashboard cells with correlation values and colors | //+------------------------------------------------------------------+ void update_dashboard() { update_correlations(); //--- Update correlations double strong_pos = StrongPositiveThresholdPct / 100.0; //--- Set positive threshold double strong_neg = StrongNegativeThresholdPct / 100.0; //--- Set negative threshold color text_base = ColorTextStrong; //--- Set base text color for (int i = 0; i < num_symbols; i++) { //--- Loop rows for (int j = 0; j < num_symbols; j++) { //--- Loop columns double corr = correlation_matrix[i][j]; //--- Get correlation double pval = pvalue_matrix[i][j]; //--- Get p-value string text = DoubleToString(corr * 100, 1) + "%" + get_significance_stars(pval); //--- Format text color bg_color = ColorNeutralBg; //--- Initialize background color txt_color = ColorTextZero; //--- Initialize text color if (i == j) { //--- Handle diagonal bg_color = ColorDiagonalBg; //--- Set diagonal background txt_color = text_base; //--- Set text color } else { //--- Handle off-diagonal if (global_display_mode == MODE_STANDARD) { //--- Handle standard mode if (corr >= strong_pos) { //--- Check strong positive bg_color = ColorStrongPositiveBg; //--- Set positive background txt_color = text_base; //--- Set text color } else if (corr <= strong_neg) { //--- Check strong negative bg_color = ColorStrongNegativeBg; //--- Set negative background txt_color = text_base; //--- Set text color } else { //--- Handle mild bg_color = ColorNeutralBg; //--- Set neutral background if (corr > 0.0) { //--- Check positive mild txt_color = ColorTextPositive; //--- Set positive text } else if (corr < 0.0) { //--- Check negative mild txt_color = ColorTextNegative; //--- Set negative text } else { //--- Handle zero txt_color = text_base; //--- Set base text } } } else { //--- Handle heatmap mode txt_color = text_base; //--- Set text color bg_color = interpolate_heatmap_color(corr); //--- Set interpolated background } } string cell_name = CELL_RECTANGLE + IntegerToString(i) + "_" + IntegerToString(j); //--- Get cell name string text_name = CELL_TEXT + IntegerToString(i) + "_" + IntegerToString(j); //--- Get text name ObjectSetInteger(0, cell_name, OBJPROP_BGCOLOR, bg_color); //--- Update background ObjectSetString(0, text_name, OBJPROP_TEXT, text); //--- Update text ObjectSetInteger(0, text_name, OBJPROP_COLOR, txt_color); //--- Update text color } } update_legend(); //--- Update legend ChartRedraw(0); //--- Redraw chart } //+------------------------------------------------------------------+ //| Initialize expert | //+------------------------------------------------------------------+ int OnInit() { global_display_mode = DashboardMode; //--- Set display mode global_correlation_tf = (CorrelationTimeframe == PERIOD_CURRENT ? (ENUM_TIMEFRAMES)_Period : CorrelationTimeframe); //--- Set timeframe for (int i = 0; i < NUM_TF; i++) { //--- Loop to find index if (tf_list[i] == global_correlation_tf) { //--- Check match current_tf_index = i; //--- Set index break; //--- Exit loop } } if (current_tf_index == -1) current_tf_index = 3; //--- Default to H1 global_correlation_tf = tf_list[current_tf_index]; //--- Update timeframe parse_symbols(); //--- Parse symbols int panel_width = WIDTH_SYMBOL + num_symbols * (WIDTH_CELL - 1) + 4; //--- Compute width num_tf_visible = MathMin(NUM_TF, (panel_width - 2) / WIDTH_TF_CELL); //--- Set visible TFs if (current_tf_index >= num_tf_visible) current_tf_index = num_tf_visible - 1; //--- Clamp index global_correlation_tf = tf_list[current_tf_index]; //--- Update timeframe ArrayInitialize(pvalue_matrix, 1.0); //--- Initialize p-values create_full_dashboard(); //--- Create dashboard update_tf_highlights(); //--- Update highlights update_dashboard(); //--- Update initial return(INIT_SUCCEEDED); //--- Return success } //+------------------------------------------------------------------+ //| Handle tick event | //+------------------------------------------------------------------+ void OnTick() { update_dashboard(); //--- Update on tick } //+------------------------------------------------------------------+