De novato a experto: Noticias animadas utilizando MQL5 (XI): Correlación en el trading con noticias
Contenido:
- Introducción
- Comprender la correlación financiera
- Estrategia de implementación
- Pruebas y resultados
- Conclusión
- Lecciones clave
- Archivos adjuntos
Introducción
La posibilidad de operar con varios pares a la vez puede parecer atractiva, pero también conlleva riesgos importantes, sobre todo cuando se opera con pares que presentan una alta correlación. Cuando los pares se mueven en la misma dirección, abrir posiciones en todos ellos aumenta la exposición. Una sola decisión errónea podría traducirse en varias operaciones con pérdidas a la vez.
Otro reto habitual surge en los momentos previos a los anuncios económicos importantes, cuando los operadores suelen enfrentarse a la incertidumbre y la indecisión a la hora de decidir qué decisión tomar. En nuestras últimas publicaciones, hemos presentado la posibilidad de seleccionar y operar con varios pares con un solo clic mediante los botones de negociación. Si bien esta característica permitió una ejecución más rápida, también puso de manifiesto un nuevo problema: una mayor exposición al riesgo.
Es aquí donde el concepto de correlación cobra una importancia fundamental. Al analizar las relaciones entre pares, los operadores pueden perfeccionar sus estrategias, evitar exposiciones redundantes e incluso aplicar técnicas como la estrategia «líder-seguidor» (catch-up), en la que el movimiento de un instrumento ayuda a predecir el de otro.
Una vez sentadas unas bases sólidas con la gestión de múltiples símbolos, el siguiente paso es integrar el análisis de correlación en el EA «News Headline». Esto nos permitirá descartar los pares que no estén en consonancia con la dirección de la operación prevista, identificar los instrumentos líderes y mejorar la eficiencia general a la hora de operar ante noticias de gran impacto, sin dejar de permitir la intervención manual.
Comprender la correlación financiera
La correlación, en los mercados financieros, es una medida estadística que cuantifica el grado en que dos valores se mueven en relación entre sí. Es la piedra angular de la gestión moderna del riesgo y una potente herramienta para la negociación estratégica, especialmente en un entorno con múltiples símbolos.
Para el sistema News Headline EA, comprender la correlación lo convierte de un simple ejecutor de operaciones en un sofisticado gestor de estrategias.
El coeficiente de correlación: el indicador clave
Esta relación se expresa mediante el coeficiente de correlación, que oscila entre -1 y +1.
- +1 (Correlación positiva perfecta): Los dos pares se mueven al unísono. Si el par A sube un 1 %, el par B sube un 1 %. Si el par A baja, el par B baja en la misma proporción. (por ejemplo, dos ETF casi idénticos que replican el mismo índice).
- 0 (Sin correlación): No existe una relación apreciable entre los movimientos de los dos pares. Son totalmente independientes.
- -1 (Correlación negativa perfecta): Los dos pares se mueven en sentido totalmente opuesto. Si el par A sube un 1 %, el par B baja un 1 %. (por ejemplo, una cobertura clásica como una acción y una opción de venta sobre esa acción).
En realidad, la mayoría de las correlaciones se sitúan en algún punto entre estos dos extremos (por ejemplo, +0,85, -0,30).
Por qué la correlación no es estática y depende del contexto
Este es el concepto más importante en el trading basado en noticias: la correlación no es una ley inmutable. Se trata de una relación dinámica que evoluciona con el tiempo y que, en determinadas circunstancias, puede romperse por completo.
Dependencia del marco temporal: La correlación entre el EUR/USD y el GBP/USD en un gráfico de 1 minuto durante la publicación de noticias puede ser muy diferente de la que se observa en un gráfico diario. Tu EA debe calcular la correlación en un periodo de referencia breve y relevante (por ejemplo, de 15 a 30 minutos) para el trading basado en noticias.
- Cambio de régimen: Los grandes cambios económicos (por ejemplo, un cambio en la política del banco central) pueden alterar correlaciones que se han mantenido durante mucho tiempo.
- Tensión en los mercados: Durante una «huida hacia activos seguros» o un momento de pánico en los mercados (por ejemplo, la crisis de 2008), las correlaciones pueden converger inesperadamente hacia +1 o -1. La diversificación no funciona porque todo se mueve al unísono: o todo sube o todo baja. Esta es la prueba definitiva para la gestión de riesgos de tu EA.
Cálculo de la correlación para el EA «News Headline»
El método más habitual es el coeficiente de correlación de Pearson. Nuestro EA calcularía esto automáticamente a partir de los porcentajes de rentabilidad o las variaciones de precio de dos activos (A y B) a lo largo de un número determinado de períodos (N).
La fórmula es:

Donde:
- 𝑟_A = rentabilidad del activo A
- 𝑟_B = rentabilidad del activo B
- Cov(𝑟_A.r_B) = covarianza entre las dos series de rendimientos
- 𝜎_A = desviación típica de la rentabilidad del activo A
- 𝜎_B = desviación típica de la rentabilidad del activo B
Aplicación práctica:
- Datos: Nuestro EA ya dispone de datos de precios para todos los pares seleccionados.
- Función: Vamos a programar una función que devuelva el coeficiente.
- Periodo histórico de referencia: En el trading basado en noticias, los periodos serán cortos (por ejemplo, entre 50 y 100 barras en un gráfico de 1 minuto o de 5 minutos).
Estrategia de implementación
Para aplicar la correlación, abordé la tarea en dos pasos estructurados. El primer paso consistió en ampliar la clase CTradingButtons para incluir tanto la lógica de cálculo de la correlación como la interfaz visual necesaria para mostrar los resultados en el gráfico. De este modo se garantiza que todas las funciones relacionadas con la correlación sigan siendo modulares y reutilizables, y que se incluyan íntegramente en el archivo de cabecera, sin dejar de ser lo suficientemente flexibles como para poder invocarlas desde cualquier EA.
El segundo paso se centró en la integración: incorporar esta nueva función de correlación en el EA principal para que funcione a la perfección junto con los componentes existentes, como los botones de negociación, las franjas de noticias y los mosaicos de minigráficos. Al mantener separadas estas dos fases, el desarrollo y la depuración resultaron más eficientes: pudimos validar los cálculos y los elementos de la interfaz de usuario de forma aislada antes de integrarlos en el sistema general.
En las siguientes secciones, explicaremos paso a paso cómo incorporar la correlación en el encabezado, abordando las fórmulas de cálculo, la colocación de marcadores en el gráfico, la alineación con las etiquetas de símbolos existentes y las rutinas de limpieza para garantizar que no quede ningún objeto tras la desinicialización.
Paso 1: Ampliar CTradingButtons para la correlación
1.1. Las constantes de diseño y su finalidad
Empezamos con un pequeño conjunto de valores predeterminados en tiempo de compilación que controlan los cálculos de correlación: la longitud de la ventana (cuántas muestras de retorno utilizamos), el desfase máximo (cuántas barras desplazamos una serie respecto a la otra para encontrar relaciones de adelanto/retraso) y un umbral que decide si una correlación se considera lo suficientemente fuerte como para marcarla como «correlacionada». Estas sencillas constantes facilitan el ajuste del código para equilibrar la capacidad de respuesta y la sensibilidad al ruido (las ventanas cortas reaccionan más rápido, pero presentan más ruido; las ventanas más largas ofrecen un resultado más suave).
// ---------------- Correlation defaults & utilities (merged) ------- #define CORR_WINDOW 40 // samples used for correlation window (returns) #define CORR_MAX_LAG 3 // maximum lag (in bars) to test for cross-correlation #define CORR_THRESHOLD 0.60 // threshold for "correlated" marker
1.2. Obtención de series de rentabilidad (cómo convertimos los precios en datos comparables)
La correlación se calcula a partir de las «rentabilidades» (variaciones relativas de los precios), en lugar de los precios brutos, para evitar los efectos de nivel y para que la fórmula de Pearson sea válida para instrumentos con diferentes escalas de precios. La función FetchReturns copia los precios de cierre recientes del símbolo y el intervalo de tiempo solicitados, y los convierte en rendimientos porcentuales simples.

Donde:
- R_t es la rentabilidad en el momento t
- 𝑃_t es el precio de cierre actual
- 𝑃_t−1 es el precio de cierre anterior
- Δ𝑃_𝑡 = 𝑃_𝑡 − 𝑃_𝑡−1, y devuelve la matriz de rendimientos más recientes (ordenados de más reciente a más antiguo). Además, reserva barras adicionales para permitir la realización de pruebas de desfase. Si no hay datos suficientes, la función finaliza de forma segura.
// Fetch recent returns for `symbol` on timeframe `tf`. // Returns number of return samples placed into `ret[]` (most recent first). int FetchReturns(const string symbol, const ENUM_TIMEFRAMES tf, const int samples, const int maxLag, double &ret[]) { if(StringLen(symbol) == 0 || samples <= 0) return 0; int need = samples + MathMax(0, maxLag) + 5; if(need <= 1) return 0; double closes[]; ArrayResize(closes, need); int copied = CopyClose(symbol, tf, 0, need, closes); if(copied <= 1) return 0; int available = copied - 1; // returns available int use = MathMin(samples, available - MathMax(0, maxLag)); if(use <= 0) return 0; ArrayResize(ret, use); for(int i = 0; i < use; i++) { double older = closes[i+1]; double newer = closes[i]; if(older == 0.0) ret[i] = 0.0; else ret[i] = (newer - older) / older; } return use; }
1.3. Cálculo de la correlación de Pearson a partir de dos vectores de rendimientos (explicación matemática)
Una vez que disponemos de dos vectores alineados de rendimientos de longitud n, calculamos el coeficiente de correlación de Pearson r. La fórmula habitual es:

Donde:
- r es el coeficiente de correlación de Pearson (un número único comprendido entre −1 y +1 que mide la asociación lineal)
- x_i es la i-ésima observación de la serie x (en nuestro EA, se trata de la i-ésima rentabilidad del símbolo X, p. ej., a[i])
- y_i es la i-ésima observación de la serie y (el i-ésimo retorno del símbolo Y, p. ej., b[i])
- x̄ (barra de x) es la media (valor medio) de la serie x: x̄ = (1/n) Σ x_i
- ȳ (y barra) es la media de la serie y: ȳ = (1/n) Σ y_i
// Compute Pearson correlation from two return arrays of length n double ComputePearsonFromReturns(const double &a[], const double &b[], const int n) { if(n <= 1) return 0.0; double meanA = 0.0, meanB = 0.0; for(int i = 0; i < n; i++) { meanA += a[i]; meanB += b[i]; } meanA /= n; meanB /= n; double cov = 0.0, varA = 0.0, varB = 0.0; for(int i = 0; i < n; i++) { double da = a[i] - meanA; double db = b[i] - meanB; cov += da * db; varA += da * da; varB += db * db; } if(varA <= 0.0 || varB <= 0.0) return 0.0; double r = cov / MathSqrt(varA * varB); if(r > 1.0) r = 1.0; if(r < -1.0) r = -1.0; return r; }
1.4. Búsqueda de la correlación cruzada máxima entre los distintos retrasos (detección de líder/seguidor)
Una mejora fundamental consiste en buscar la correlación más fuerte entre el símbolo actual del gráfico y cada uno de los símbolos candidatos, permitiendo pequeños desfases. Para cada candidato, desplazamos una serie de rendimientos con respecto a la otra en intervalos que van desde −maxLag hasta +maxLag y calculamos el coeficiente de Pearson r para cada desplazamiento. Conservamos la r con el valor absoluto máximo (peakCorr) y el retraso correspondiente. Un desfase positivo indica que el candidato va por detrás del símbolo actual; un desfase negativo indica que el candidato va por delante del símbolo actual. Así, el EA puede recomendar el instrumento líder. La función devuelve peakCorr y lagAtPeak, o «false» si los datos son insuficientes.// Compute cross-correlation peak and lag between currSym and otherSym. // Outputs peakCorr and lagAtPeak (int). bool ComputeCrossCorrPeak(const string currSym, const string otherSym, const ENUM_TIMEFRAMES tf, const int window, const int maxLag, double &peakCorr, int &lagAtPeak) { if(StringLen(currSym) == 0 || StringLen(otherSym) == 0 || window <= 1) return(false); double rCurr[], rOther[]; int nCurr = FetchReturns(currSym, tf, window, maxLag, rCurr); int nOther = FetchReturns(otherSym, tf, window, maxLag, rOther); if(nCurr == 0 || nOther == 0) return(false); int available = MathMin(nCurr, nOther); if(available < window) return(false); bool found = false; peakCorr = 0.0; lagAtPeak = 0; for(int lag = -maxLag; lag <= maxLag; lag++) { int startCurr = 0; int startOther = lag; if(startOther < 0) { startCurr = -startOther; startOther = 0; } int maxSamples = available - MathMax(startCurr, startOther); if(maxSamples < window) continue; double a[], b[]; ArrayResize(a, window); ArrayResize(b, window); for(int i = 0; i < window; i++) { a[i] = rCurr[startCurr + i]; b[i] = rOther[startOther + i]; } double r = ComputePearsonFromReturns(a, b, window); if(!found || MathAbs(r) > MathAbs(peakCorr)) { peakCorr = r; lagAtPeak = lag; found = true; } } return(found); }
1.5. Representación de marcadores: funciones de dibujo (retroalimentación visual)
Para mostrar los resultados de la correlación sin saturar las etiquetas de los símbolos existentes, se añadieron marcadores mínimos: una etiqueta compacta que muestra un punto de color y el valor numérico de la correlación. DrawCorrelationMarker crea un elemento OBJ_LABEL en el gráfico en las coordenadas indicadas, establece el color en verde (correlacionado) o rojo (no correlacionado) y escribe un texto breve como «● 0,72». Esto permite que la interfaz de usuario sea compacta y fácil de leer. Una pequeña función similar, DrawRecommendation, escribe la sugerencia «Líder recomendado»; DrawCorrelationTitle coloca un encabezado estático «Correlación» encima del área del marcador. Estas tres funciones son simples envoltorios de gestión de objetos que garantizan la coherencia en el dibujo y centralizan el orden Z y la selección de fuentes.// Draw a small correlation marker near (x,y) — dot + numeric value only (no symbol text). void DrawCorrelationMarker(const string objName, const int x, const int y, const double corr, const bool correlated) { if(StringLen(objName) == 0) return; long chart = ChartID(); if(ObjectFind(chart, objName) == -1) ObjectCreate(chart, objName, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(chart, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(chart, objName, OBJPROP_XDISTANCE, x); ObjectSetInteger(chart, objName, OBJPROP_YDISTANCE, y); ObjectSetInteger(chart, objName, OBJPROP_FONTSIZE, 10); int col = correlated ? clrLime : clrRed; ObjectSetInteger(chart, objName, OBJPROP_COLOR, col); ObjectSetInteger(chart, objName, OBJPROP_SELECTABLE, 0); ObjectSetInteger(chart, objName, OBJPROP_ZORDER, 20); // Show a small dot and the numeric correlation (2 decimals). Example: "● 0.72" string text = StringFormat("● %.2f", corr); ObjectSetString(chart, objName, OBJPROP_TEXT, text); } // Draw recommendation label (top-left of panel area) void DrawRecommendation(const string objName, const int x, const int y, const string text) { if(StringLen(objName) == 0) return; long chart = ChartID(); if(ObjectFind(chart, objName) == -1) ObjectCreate(chart, objName, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(chart, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(chart, objName, OBJPROP_XDISTANCE, x); ObjectSetInteger(chart, objName, OBJPROP_YDISTANCE, y); ObjectSetInteger(chart, objName, OBJPROP_FONTSIZE, 10); ObjectSetInteger(chart, objName, OBJPROP_COLOR, clrWhite); ObjectSetInteger(chart, objName, OBJPROP_SELECTABLE, 0); ObjectSetInteger(chart, objName, OBJPROP_ZORDER, 21); ObjectSetString(chart, objName, OBJPROP_TEXT, text); } // Draw static "Correlation" title above correlation area void DrawCorrelationTitle(const string objName, const int x, const int y) { if(StringLen(objName) == 0) return; long chart = ChartID(); if(ObjectFind(chart, objName) == -1) ObjectCreate(chart, objName, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(chart, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(chart, objName, OBJPROP_XDISTANCE, x); ObjectSetInteger(chart, objName, OBJPROP_YDISTANCE, y); ObjectSetInteger(chart, objName, OBJPROP_FONTSIZE, 11); ObjectSetInteger(chart, objName, OBJPROP_COLOR, clrWhite); ObjectSetInteger(chart, objName, OBJPROP_SELECTABLE, 0); ObjectSetInteger(chart, objName, OBJPROP_ZORDER, 22); ObjectSetString(chart, objName, OBJPROP_TEXT, "Correlation"); }
1.6. Dónde se encuentran los ajustes de correlación y el estado de la interfaz de usuario dentro de la clase «trading-button»
Para facilitar la integración, los parámetros de correlación y las coordenadas de cada casilla de selección se almacenan como miembros de la clase CTradingButtons. El constructor establece unos valores por defecto razonables, de modo que el EA pueda crear fácilmente el panel de operaciones y tener la correlación lista. Los elementos clave son m_corr_window, m_corr_maxlag, m_corr_threshold, los desplazamientos verticales y horizontales (para poder mover ligeramente los puntos) y las matrices m_check_x/m_check_y, que memorizan las posiciones de los píxeles de las casillas de selección. Este estado localizado simplifica la función UpdateCorrelationMarkersInternal y evita que el estado de correlación se disperse por todo el EA.// initialize correlation defaults here (cannot initialize at declaration) m_corr_marker_prefix = "CorrMarker_"; m_corr_rec_name = "Corr_Recommendation"; m_corr_title_name = "Corr_Title"; m_corr_tf = PERIOD_M1; m_corr_window = CORR_WINDOW; m_corr_maxlag = CORR_MAX_LAG; m_corr_threshold = CORR_THRESHOLD; // vertical offsets (push correlation UI down a bit) m_corr_rec_y_offset = 24; // recommendation label y-distance in pixels (tweak) m_corr_marker_v_offset = 8; // marker offset relative to checkbox top (tweak) // horizontal offset default (shift markers slightly right) m_corr_marker_h_offset = 6; // default shift to the right by 6 pixels (tweak as needed) ArrayResize(m_check_x, 0); ArrayResize(m_check_y, 0);
1.7. Controles públicos: exponer el ajuste en tiempo de ejecución al EA
Hay dos pequeños métodos que permiten al EA ajustar la correlación en tiempo de ejecución: SetCorrelationParams, para modificar el marco temporal, la ventana, el retraso máximo y el umbral, y SetCorrelationMarkerHorizontalOffset, para que el usuario del EA pueda ajustar ligeramente la posición de los marcadores en función de los diferentes tamaños de pantalla o anchos de las casillas de selección. Ambas llaman (o llamarán) a la rutina interna de actualización para volver a dibujar los marcadores de forma inmediata. Esta separación permite que los ajustes en la interfaz de usuario sean sencillos.// Configure correlation evaluation (optional runtime tuning) void SetCorrelationParams(const int timeframe, const int window, const int maxlag, const double threshold) { m_corr_tf = timeframe; m_corr_window = MathMax(1, window); m_corr_maxlag = MathMax(0, maxlag); m_corr_threshold = MathMax(0.0, MathMin(1.0, threshold)); PrintFormat("SetCorrelationParams: tf=%d window=%d maxlag=%d thresh=%.2f", m_corr_tf, m_corr_window, m_corr_maxlag, m_corr_threshold); } // Exposed update so EA can refresh markers (public wrapper) void UpdateCorrelationMarkers() { UpdateCorrelationMarkersInternal(); } // Public setter for horizontal offset of correlation markers void SetCorrelationMarkerHorizontalOffset(const int px) { m_corr_marker_h_offset = px; UpdateCorrelationMarkersInternal(); }
1.8. Dibujo por casilla de selección: DrawCorrelationForIndex (donde se calcula y se dibuja cada marcador)
Para cada par identificado, calculamos el pico de correlación con respecto al símbolo actual del gráfico y determinamos si cumple el umbral. Las coordenadas se leen a partir de los valores almacenados en m_check_x y m_check_y (recogidos al crear las casillas de selección o al consultar el objeto de la casilla de selección); a continuación, colocamos el punto y el texto numérico en esa posición de píxel (con desplazamientos horizontales y verticales configurables). La función llama a «ComputeCrossCorrPeak» y «DrawCorrelationMarker», manteniendo así las responsabilidades separadas.void DrawCorrelationForIndex(const int idx) { if(idx < 0 || idx >= ArraySize(availablePairs)) return; string sym = availablePairs[idx]; if(StringLen(sym) == 0) return; if(idx >= ArraySize(m_check_x) || idx >= ArraySize(m_check_y)) return; int x = m_check_x[idx]; int y = m_check_y[idx]; if(x < 0 || y < 0) return; // move marker slightly to the right with configurable horizontal offset int markerX = MathMax(2, x - 18 + m_corr_marker_h_offset); int markerY = y + m_corr_marker_v_offset; // configurable vertical offset double peakCorr = 0.0; int lag = 0; bool ok = ComputeCrossCorrPeak(Symbol(), sym, (ENUM_TIMEFRAMES)m_corr_tf, m_corr_window, m_corr_maxlag, peakCorr, lag); if(!ok) peakCorr = 0.0; bool correlated = (MathAbs(peakCorr) >= m_corr_threshold); string objName = m_corr_marker_prefix + sym; DrawCorrelationMarker(objName, markerX, markerY, peakCorr, correlated); }
1.9. Coordinación de todo: UpdateCorrelationMarkersInternal (selección del líder + redibujado)
Esta es la función principal que recorre los pares identificados, se asegura de que tengamos las coordenadas de píxeles de las casillas de selección, dibuja cada marcador y, a continuación, calcula el mejor candidato a líder eligiendo el símbolo con la correlación máxima absoluta que también indique liderazgo mediante un desfase negativo (puedes ajustar tu regla de liderazgo). La función escribe una breve cadena de texto fácil de entender para el usuario, del tipo «Líder recomendado: … r=… lag=…», mediante DrawRecommendation, y dibuja el título «Correlación» encima del área. Esta es la función que se debe llamar cada vez que cambien las casillas de selección o la disposición de la pantalla.
void UpdateCorrelationMarkersInternal() { int n = ArraySize(availablePairs); if(n == 0) return; for(int i = 0; i < n; i++) { if(StringLen(availablePairs[i]) == 0) continue; if(i >= ArraySize(m_check_x) || i >= ArraySize(m_check_y) || m_check_x[i] < 0 || m_check_y[i] < 0) { string chkName = "Chk_" + availablePairs[i]; if(ObjectFind(ChartID(), chkName) >= 0) { int y = (int)ObjectGetInteger(ChartID(), chkName, OBJPROP_YDISTANCE); int x = (int)ObjectGetInteger(ChartID(), chkName, OBJPROP_XDISTANCE); if(ArraySize(m_check_x) < n) ArrayResize(m_check_x, n); if(ArraySize(m_check_y) < n) ArrayResize(m_check_y, n); m_check_x[i] = x; m_check_y[i] = y; } else continue; } DrawCorrelationForIndex(i); } double bestCorr = 0.0; string bestSym = ""; int bestLag = 0; for(int j = 0; j < n; j++) { if(StringLen(availablePairs[j]) == 0) continue; double p = 0.0; int l = 0; bool ok = ComputeCrossCorrPeak(Symbol(), availablePairs[j], (ENUM_TIMEFRAMES)m_corr_tf, m_corr_window, m_corr_maxlag, p, l); if(!ok) continue; if(l < 0 && MathAbs(p) > MathAbs(bestCorr)) { bestCorr = p; bestSym = availablePairs[j]; bestLag = l; } } int recX = checkStartX; int recY = m_corr_rec_y_offset; // configurable vertical offset for recommendation string recText; if(bestSym != "") recText = StringFormat("Recommended leader: %s r=%.2f lag=%d", bestSym, bestCorr, bestLag); else recText = "No clear leader detected"; // Draw title above the recommendation/markers area DrawCorrelationTitle(m_corr_title_name, recX, MathMax(2, recY - 18)); DrawRecommendation(m_corr_rec_name, recX, recY, recText); }
1.10. Limpieza: DeleteCorrelationMarkers (eliminación de objetos innecesarios)
Cuando se desmonta el encabezado o la interfaz de usuario (Deinit), eliminamos todos los objetos de etiquetas de correlación, junto con el título y la etiqueta de recomendación, para que el gráfico vuelva a su estado anterior a la aplicación del EA. Esto evita que queden etiquetas huérfanas cuando se elimina el panel de EA o de botones.void DeleteCorrelationMarkers() { for(int i = 0; i < ArraySize(availablePairs); i++) { if(StringLen(availablePairs[i]) == 0) continue; string obj = m_corr_marker_prefix + availablePairs[i]; if(ObjectFind(ChartID(), obj) >= 0) ObjectDelete(ChartID(), obj); } if(ObjectFind(ChartID(), m_corr_rec_name) >= 0) ObjectDelete(ChartID(), m_corr_rec_name); if(ObjectFind(ChartID(), m_corr_title_name) >= 0) ObjectDelete(ChartID(), m_corr_title_name); }
Dónde y cuándo se activa la interfaz de usuario de correlación (puntos de integración)
Para mantener la sincronización con la disposición de las casillas de selección y las interacciones del usuario, llamamos a UpdateCorrelationMarkersInternal tras crear las casillas de selección (para que se coloquen los marcadores iniciales) y de nuevo cada vez que se activa o desactiva una casilla de selección mediante HandleChartEvent. Estos son los dos puntos de llamada (la función `CreatePairCheckboxes` termina llamando a `UpdateCorrelationMarkersInternal`; la función `HandleChartEvent` llama a `UpdateCorrelationMarkersInternal` cuando cambia el estado de una casilla de selección).// end of CreatePairCheckboxes() // inside HandleChartEvent() when checkbox clicked: UpdateCorrelationMarkersInternal();
Paso 2: Integración de la correlación en el EA
2.1. Incluir encabezados: habilitar la API de correlación.
Incluye el encabezado de los botones de negociación (que ahora contiene utilidades de correlación) para que el EA pueda llamar a sus API públicas (crear casillas de selección, establecer parámetros de correlación, actualizar marcadores, desinicializar). Esto debe aparecer en la parte superior del EA antes de utilizar cualquier función de buttonsEA.
#include <TradingButtons.mqh> #include <Trade\Trade.mqh> #include <Canvas\Canvas.mqh> #include <ChartMiniTiles.mqh> // <-- CTM class include (make sure this file is in MQL5/Include/)
2.2. Los datos introducidos por el usuario para la correlación permiten al operador realizar ajustes.
Permite exponer el intervalo de tiempo, la ventana, el retardo máximo y el umbral para que los usuarios puedan ajustar la sensibilidad y la estabilidad de la detección de correlación. Estos se leen en OnInit() y se pasan al encabezado.
// Correlation tuning exposed to EA input group "Correlation (TradingButtons)" input int CorrTimeframe = PERIOD_M1; input int CorrWindow = 40; input int CorrMaxLag = 3; input double CorrThreshold = 0.60;
2.3. Crear interfaz de usuario de pares (casillas de selección): puntos de anclaje para los marcadores de correlación
Crea las casillas de selección por pares (esto también proporciona al encabezado las coordenadas de la interfaz de usuario que necesita para colocar los puntos y los valores junto a cada símbolo). Hazlo al principio, durante la inicialización, para que el encabezado pueda consultar las posiciones de las casillas de selección.
// Create pair checkboxes aligned below the canvas lanes: int checkboxY = InpTopOffset + (InpSeparateLanes ? 8 : 28) * lineH + 6; // same as before buttonsEA.CreatePairCheckboxes(majorPairs, pairSelected, checkboxY);
2.4. Pasar los parámetros de correlación y forzar el renderizado inicial
Una vez creadas las casillas de selección, pasa los datos de entrada del EA al encabezado y fuerza una actualización inicial de los marcadores para que la interfaz de usuario de correlación aparezca inmediatamente al iniciar.
// Set correlation params in TradingButtons buttonsEA.SetCorrelationParams(CorrTimeframe, CorrWindow, CorrMaxLag, CorrThreshold); // Force initial correlation markers buttonsEA.UpdateCorrelationMarkers();
2.5. Reenvío de eventos y gestión de cambios de diseño
Reenvía los eventos del gráfico al encabezado para que los clics en las casillas de selección y las interacciones con la interfaz de usuario se gestionen allí. Además, responde a los cambios en el diseño del gráfico (CHARTEVENT_CHART_CHANGE) reajustando tanto los minicuadros como los marcadores de correlación para mantener las posiciones correctas.
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { // Let the tiles class handle object clicks (toggle button). If handled, stop processing. if(tiles.HandleEvent(id, sparam)) return; // Forward to the TradingButtons header afterward buttonsEA.HandleChartEvent(id, sparam, majorPairs, pairSelected); // Also respond to chart change events for CTM layout if(id == CHARTEVENT_CHART_CHANGE) { tiles.UpdateLayout(); buttonsEA.UpdateCorrelationMarkers(); } }
2.6. Actualización programada: mantén actualizados los marcadores de correlación
En cada ciclo del temporizador, el EA realiza numerosas tareas periódicas y, a continuación, solicita al encabezado que vuelva a calcular y a trazar los marcadores de correlación, de modo que los puntos y los valores reflejen los cambios recientes en los precios.
// Keep CTM updated every tick (timer-driven) tiles.UpdateLayout(); // Keep correlation markers fresh — call the header's public updater buttonsEA.UpdateCorrelationMarkers();
2.7. Limpieza: la desinicialización de la cabecera elimina los objetos de correlación
Cuando se detenga el EA, llama a la función «Deinit/cleanup» del encabezado para que este pueda eliminar todos los objetos de marcadores de correlación, la etiqueta de recomendación y el título. En el nivel EA, se llama a buttonsEA.Deinit(). Internamente, el encabezado debería eliminar cada marcador; ejemplo de función de limpieza del encabezado:
void OnDeinit(const int reason) { EventKillTimer(); buttonsEA.Deinit(); // ... other UI destruction ... // delete CTM tiles and toggle button tiles.Delete(); }
Pruebas y resultados
Implementar el EA «News Headline» actualizado en un gráfico real de MetaTrader 5 es la forma más eficaz de comprobar su funcionamiento, ya que muchas de sus funciones se basan en datos en tiempo real y no pueden validarse por completo en el Probador de estrategias.
Los resultados de las pruebas se muestran en las imágenes siguientes. Ahora, cada etiqueta de símbolo principal muestra un valor de correlación junto con un punto de color: rojo para correlación negativa y verde lima para correlación positiva. Los valores numéricos, que oscilan entre -1 y +1, representan la intensidad y la dirección de la correlación con respecto al par actual del gráfico, tomado aquí como referencia. Una correlación positiva indica que el par tiende a moverse en la misma dirección que el líder, mientras que una correlación negativa sugiere un movimiento en la dirección opuesta.

Figura 1: Prueba de correlación en GBPAUD utilizando el EA «News Headline» actualizado
Como se muestra en las imágenes, los valores de correlación fluctúan lentamente, ya que dependen no solo de la volatilidad del mercado, sino también del tamaño de la ventana de correlación. Este comportamiento refleja el desfase natural de las relaciones estadísticas, lo que convierte al análisis de correlación en un complemento estable para las decisiones de negociación en tiempo real.
Conclusión
La correlación financiera puede ser una herramienta muy eficaz para descartar pares y reducir la exposición al riesgo al operar con múltiples instrumentos durante acontecimientos de gran impacto. Hemos aplicado con éxito este concepto en el EA «News Headline» para mejorar la eficiencia en la negociación con múltiples símbolos en condiciones de volatilidad.
El objetivo no es simplemente permitir operar con todos los pares a la vez, sino utilizar la correlación como guía estadística para tomar decisiones más claras y fundamentadas. Al analizar cómo se mueven los pares entre sí, el EA permite a los operadores centrarse en las oportunidades que se ajustan a su estrategia, evitando al mismo tiempo posiciones redundantes o excesivamente arriesgadas.
Aunque aún se puede sacar mucho más partido a este concepto, nuestra implementación actual ya supone un importante paso adelante. Como se muestra en la imagen siguiente, ahora puedo seleccionar qué pares operar simultáneamente, guiándome por los valores de correlación que se muestran.

Figura 2: Uso de la correlación para decidir qué pares operar simultáneamente.
Este concepto abre la puerta a muchas más estrategias, y su implementación en MQL5 es totalmente posible. Todo el código fuente y los componentes clave se adjuntan y se documentan parcialmente en la tabla de archivos adjuntos que figura a continuación. Te invitamos a participar en el debate: comparte tus opiniones, ideas y sugerencias mientras seguimos ampliando nuestras herramientas de MQL5 para convertirlas en estrategias prácticas y ganadoras.
Lecciones clave
| Lección | Descripción: |
|---|---|
| Integración con un objetivo concreto | La correlación debe considerarse un factor que influye en las decisiones de negociación, no una señal en sí misma. La integración de la correlación en la interfaz de usuario y el flujo de trabajo (casillas de selección, marcadores, recomendaciones) permite aprovechar la información estadística durante las operaciones con múltiples símbolos impulsadas por las noticias. |
| Trabaja con la rentabilidad, no con los precios brutos | Calcular la correlación entre las rentabilidades de un periodo a otro (variaciones relativas de los precios) para que las comparaciones entre valores sean independientes de la escala. El uso de los rendimientos evita los efectos de nivel y hace que la correlación de Pearson sea significativa para instrumentos con diferentes rangos de precios. |
| Implementación de la correlación de Pearson | Aplica el coeficiente de Pearson con cuidado: calcula las medias, la covarianza (suma de las desviaciones por pares) y normaliza el resultado por el producto de las desviaciones estándar. Evita la varianza cero para evitar errores de división por cero. |
| Compensación entre la longitud de la ventana y otros factores | Elige con cuidado la longitud de la ventana de correlación: las ventanas cortas reaccionan rápidamente, pero presentan más ruido; las ventanas largas ofrecen un resultado más suave, pero son más lentas. Incluye la ventana como parámetro de ejecución para que los usuarios puedan ajustar el equilibrio entre la capacidad de respuesta y la estabilidad. |
| Retraso y detección de líder-seguidor | Prueba pequeños retrasos positivos y negativos al calcular la correlación cruzada para identificar los instrumentos adelantados. El desfase respecto al pico de correlación absoluta indica si otro par va por delante o por detrás del gráfico actual, lo que permite ofrecer recomendaciones sobre el par líder. |
| Umbrales para la toma de decisiones | Aplica un umbral ajustable para determinar cuándo marcar un par como «correlacionado». Esto evita el exceso de marcas y permite a los operadores controlar la sensibilidad (los umbrales habituales oscilan entre 0,5 y 0,8, dependiendo de la tolerancia a los falsos positivos). |
| Visualización compacta y discreta | Muestra la correlación como un pequeño punto de color junto con un valor numérico junto a las etiquetas de los símbolos existentes, y añade un título conciso como «Correlación». Los marcadores compactos transmiten información sin saturar el gráfico ni obstaculizar los controles de negociación. |
| Anclar los marcadores a elementos de la interfaz | Coloca los marcadores de correlación en relación con los puntos de referencia existentes de la interfaz de usuario (por ejemplo, las casillas de selección de símbolos) para que los marcadores permanezcan alineados al cambiar el tamaño del gráfico y al modificar los paneles. Actualiza las posiciones cada vez que se produzca un cambio en el diseño. |
| Utiliza la correlación para reducir la exposición | Aprovecha la correlación para descartar los pares redundantes al abrir posiciones con varios pares. Evita realizar operaciones en la misma dirección con pares de divisas muy correlacionados para reducir el riesgo agregado durante acontecimientos de gran impacto. |
| Exponer parámetros ajustables en tiempo de ejecución | Permitir que el intervalo de tiempo, la ventana, el retraso máximo y el umbral se introduzcan como parámetros. Permitir a los operadores ajustar estos parámetros en tiempo de ejecución aumenta la flexibilidad y ayuda a adaptar el algoritmo a diferentes condiciones de mercado y preferencias de los usuarios. |
| Actualización controlada por temporizador y rendimiento | Vuelve a calcular y a trazar los marcadores de correlación con un temporizador controlado para mantener los valores actualizados, al tiempo que se limita el uso de la CPU y la API. Equilibrar la frecuencia de actualización con el coste de cálculo, de modo que la interfaz de usuario sea oportuna pero no consuma demasiados recursos. |
| Gestionar correctamente los datos faltantes o degenerados | Detecta las series con historial insuficiente o de varianza nula y omite o marca dichos pares de forma conservadora. Devolver valores predeterminados seguros en lugar de provocar un error garantiza la solidez del EA en todos los brókers y listas de símbolos. |
| Limpiar objetos al desinicializarse | Elimina todos los marcadores de correlación, el título y las etiquetas de recomendación durante la desinicialización para evitar que queden objetos huérfanos en el gráfico. Una limpieza adecuada garantiza que el gráfico quede ordenado tras eliminar o volver a cargar el EA. |
| Diseño modular basado en encabezados | Incorporar la lógica de correlación y el dibujo en un encabezado o clase reutilizable (por ejemplo, ampliando la utilidad del botón de negociación). Esto permite que el código de la EA se centre en lo esencial, simplifica las pruebas y facilita su reutilización en distintos proyectos. |
| Es preferible realizar pruebas en un gráfico en tiempo real | Comprueba la correlación y las interacciones de la interfaz de usuario en un gráfico en tiempo real, en lugar de utilizar el Strategy Tester, ya que la correlación depende de la dinámica de los ticks en tiempo real y de la disposición interactiva de la interfaz de usuario, aspectos que el Strategy Tester no reproduce por completo. |
Archivos adjuntos
En la tabla siguiente se enumeran los archivos fuente que se han actualizado para incorporar la función de correlación. Cada fila muestra el nombre del archivo, la versión actual del mismo (cuando proceda) y una breve descripción de los cambios introducidos, centrándose en los cálculos de correlación, las actualizaciones de marcadores y de la interfaz de usuario, los enlaces a la API pública y los puntos de integración con el EA principal. | Nombre del archivo | Versión | Descripción |
|---|---|---|
| TradingButtons.mqh | 1.01 | Se ha ampliado el encabezado de la interfaz de usuario de operaciones para incluir herramientas de correlación. Incorpora cálculos de Pearson y de correlación cruzada con desfase, parámetros configurables (intervalo de tiempo, ventana, desfase máximo, umbral) y actualizaciones eficientes controladas por un temporizador. Los cambios visuales incluyen marcadores de correlación compactos (punto de color + valor numérico), un título «Correlación» encima del bloque, ajustes en la ubicación (se ha bajado ligeramente y se ha desplazado hacia la derecha) y la eliminación del texto duplicado de los símbolos, de modo que solo aparezcan puntos y valores junto a las etiquetas existentes. Expone las funciones de la API pública para el EA: SetCorrelationParams, UpdateCorrelationMarkers, CreatePairCheckboxes, HandleChartEvent y Deinit (limpieza). Gestiona datos corruptos y elimina todos los objetos creados al desinicializarse. |
| NewsHeadlineEA.mq5 | 1.15 | EA principal que integra el calendario, las noticias, los análisis de IA, la interfaz de usuario de TradingButtons y los mosaicos de minigráficos. Se ha actualizado para pasar los datos de correlación al encabezado de TradingButtons, llamar a la función UpdateCorrelationMarkers en los eventos de inicialización, temporizador y cambio de gráfico, y colocar la interfaz de usuario de correlación de forma que no se solape con los controles de negociación ni con el CTM. Además, integra ChartMiniTiles para crear minigráficos de varios símbolos y reserva la zona superior para la interfaz de usuario de negociación. Garantiza una limpieza ordenada de los marcadores de correlación y los mosaicos CTM al desinicializarse. |
| ChartMiniTiles.mqh | 1.0 | Clase de mosaicos de minigráficos reutilizables para incrustar varios gráficos de símbolos dentro del gráfico principal. |
Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/19343
Advertencia: todos los derechos de estos materiales pertenecen a MetaQuotes Ltd. Queda totalmente prohibido el copiado total o parcial.
Este artículo ha sido escrito por un usuario del sitio web y refleja su punto de vista personal. MetaQuotes Ltd. no se responsabiliza de la exactitud de la información ofrecida, ni de las posibles consecuencias del uso de las soluciones, estrategias o recomendaciones descritas.
Utilizando redes neuronales en MetaTrader
Motor de decisión Multi-IA para MQL5 (Parte 2): Voto ponderado que aprende en cuál IA confiar, más gestión de riesgo
Particularidades del trabajo con números del tipo double en MQL4
Introducción a MQL5 (Parte 21): Automatización de la detección de patrones armónicos
- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso