English Русский 中文 Deutsch 日本語
preview
Arbitraje estadístico mediante reversión a la media en el trading de pares: Cómo superar al mercado con matemáticas

Arbitraje estadístico mediante reversión a la media en el trading de pares: Cómo superar al mercado con matemáticas

MetaTrader 5Sistemas comerciales |
73 16
Jocimar Lopes
Jocimar Lopes

Introducción

“Puedo calcular el movimiento de los cuerpos celestes, pero no la locura de las personas.” (Sir Isaac Newton, a los noventa años, tras perder casi todos sus ahorros de jubilación invirtiéndolos en la bolsa).

El 10 de mayo del año pasado, el mundo perdió a Jim Simons, el gestor de fondos de cobertura más exitoso de todos los tiempos.

Jim Simons fue un matemático reconocido, con varios reconocimientos y logros académicos en geometría diferencial y criptografía. Sin embargo, su papel en el análisis financiero cuantitativo hizo que su nombre fuera famoso incluso entre personas no interesadas en las matemáticas o las finanzas.

Fue objeto de varias biografías, docenas de libros sobre su vida y carrera, cientos de programas de televisión y miles de artículos y publicaciones de blogs en todo el mundo. The Man Who Solved the Market: How Jim Simons Launched the Quant Revolution es su biografía más famosa.

A principios de los años ochenta, Simons fundó Renaissance Technologies (RenTech) y comenzó a reunir un equipo de «matemáticos, físicos, expertos en procesamiento de señales y estadísticos» altamente cualificados. Tras décadas de trabajo conjunto, demostraron que, con suficientes datos y potencia computacional para encontrar patrones estadísticos y anomalías en dichos patrones, el mercado podía «ser vencido por las matemáticas».

«En 1988, la empresa creó su cartera más rentable, el fondo Medallion, que utilizaba una versión mejorada y ampliada de los modelos matemáticos de Leonard Baum, perfeccionados por el algebraista James Ax, para explorar correlaciones de las que pudiera obtener beneficios». (Wikipedia)

El fondo Medallion obtuvo una rentabilidad media anual del 66 % entre 1988 y 2018, lo que supuso más de 104 000 millones de dólares en beneficios comerciales en estas tres décadas. El fondo Medallion de RenTech sigue activo hoy en día y generando grandes ganancias. Como es de esperar, a muchas personas les gustaría saber cómo funcionan, los detalles, el algoritmo secreto, el código de trucos... lo que sea. Pero, hasta donde sabe cualquier ser humano mortal, su salsa secreta se conserva como un acuerdo corporativo de alto secreto. Cuando el autor de su biografía le preguntó sobre la estrategia operativa de Medallion, Simons respondió con la misma respuesta lacónica que daría a varios entrevistadores en los años siguientes: arbitraje estadístico a nivel de cartera. También reveló que han estado utilizando “una especie de aprendizaje automático” desde el principio para encontrar las anomalías del mercado.

El arbitraje estadístico es, en sí mismo, un amplio campo de investigación. Cuando le añadimos aprendizaje automático, el comerciante minorista promedio sin una sólida formación en matemáticas y estadística queda excluido. Y ni hablar del trader novato. Pero, si bien es cierto que es realmente difícil y se requieren muchos recursos para implementar un arbitraje estadístico a nivel de cartera con todas las funciones y potenciado por el aprendizaje automático sin todo ese conocimiento, también es cierto que es perfectamente posible entender qué es el arbitraje estadístico a nivel de cartera, cómo funciona y, lo que es más importante: es posible empezar de a poco con paciencia, trabajo duro y tiempo para crecer.

Este artículo no es de ninguna manera un intento de reproducir, o peor aún, “revelar el código secreto” de RenTech/Jim Simons. Como se dijo anteriormente, eso sería imposible para cualquiera que no estuviera directamente involucrado en sus operaciones. Es un esfuerzo por compartir con ustedes mi comprensión de los principios generales que impulsan sus modelos. Estos principios pueden informar el sistema comercial incluso del comerciante minorista más humilde. La diferencia estará en la escala de los resultados, que será proporcional a la cantidad de recursos invertidos en el sistema y sus operaciones.

Así pues, lo que leeréis a continuación es el resultado de una investigación en libros, documentales en vídeo y comunidades especializadas de internet, fusionada con mi experiencia personal de algunos años en el segmento financiero (más en el lado empresarial que en el lado desarrollador). Lo que hace RenTech es enorme, pero lo que veremos aquí es una miniatura, digamos, una figura de acción de un superhéroe, una maqueta de un rascacielos. 

El objetivo es contribuir con un método de análisis de bajo costo, liviano y fácil de desarrollar que pueda ser probado y mejorado por el trader minorista promedio usando solo las herramientas ya disponibles en la plataforma MetaTrader 5 que se ejecuta en un portátil de consumo de materias primas, posiblemente un portátil de gama baja. El método debería ser útil tanto para el trader algorítmico como para el trader discrecional. Comenzaremos con la configuración más sencilla, lo justo para describir el proceso.

Después de comprender los conceptos generales detrás del modelo, construiremos una cartera mínima para la forma más simple de arbitraje estadístico, lo negociaremos en modo automático con un Asesor Experto, tomaremos algunas notas sobre los resultados y, finalmente, pensaremos en los próximos pasos necesarios. Espero que esta experiencia pueda ayudarte a iniciarte en esta potente técnica de trading y poder ampliar posteriormente estos conocimientos, incorporando otros símbolos al portfolio y probando otros algoritmos más allá del aquí descrito, para ir construyendo progresivamente tu propia estrategia StatArb completa y adecuada a tus recursos y objetivos.


Conceptos generales detrás del modelo

Antes de crear RenTech, Jim Simons trabajó como descifrador de códigos para la inteligencia estadounidense durante la Guerra Fría. Cuando comenzó a operar en los mercados financieros, intentó predecir los precios de las acciones y las materias primas y fracasó. Luego cambió su enfoque. Supuso que nunca sería capaz de anticipar el futuro del mercado. Comprendió que tenía que aceptar que el mercado era un enigma. Éste es el primer concepto relevante detrás del modelo.

El otro concepto es que el mercado está en un estado continuo de cambio. Es decir, no existen mercados alcistas o bajistas, patrones de velas/barras o “acciones correlacionadas que funcionan bien juntas”. Todo está cambiando ahora y para siempre.

Si piensas por un segundo verás que ambos conceptos se pasan por alto.

El mercado es un enigma

El mercado es un enigma, pero a diferencia de aquella máquina Enigma de la Segunda Guerra Mundial cuyo código fue descifrado por Alan Turing y su equipo, el enigma del mercado no tiene un algoritmo determinista que pueda ser diseñado a la inversa y descifrado. Entre la entrada y la salida pueden ocurrir eventos inesperados. Si bien el aumento de las tasas de interés por parte de un banco central tiene el efecto esperado de fortalecer la moneda de ese país, el estallido de un conflicto político en otro país distante puede tener el efecto contrario, contrarrestando el aumento de las tasas de interés al disminuir su impacto, anularlo o incluso debilitar esa moneda.

El mercado es un enigma porque, entre la entrada y la salida, está la irracionalidad de los agentes económicos, el carácter imprevisible de la política y el aspecto caótico de la interacción entre las fuerzas que lo impulsan. Entre el mercado del oro que se mantiene alcista durante un año y su caída en picada de un mes la semana siguiente, existe un comportamiento humano. No fue por otra razón que un psicólogo, Daniel Kahneman, recibió el Premio Nobel de Ciencias Económicas. Porque aborda precisamente esta cuestión.
Aunque el mercado es un enigma gobernado por agentes económicos irracionales dentro de un entorno caótico, los bancos de inversión compran y venden acciones basándose en modelos financieros, los fondos de cobertura utilizan Black-Scholes para evaluar opciones y casi todos los grandes actores del mercado gastan millones de dólares en el desarrollo de estrategias de trading cuantitativo. ¿Por qué? Porque funciona, por supuesto. ¿Por qué funciona si el mercado es imprevisible, impredecible, irracional y caótico?
Jim Simons, junto con miles de otros exitosos traders cuantitativos, algorítmicos y discrecionales, tiene la respuesta más sincera a esta pregunta. Una lección que cualquier aspirante a trader debería recitar como mantra cada mañana antes de entrar al mercado:
“El éxito en el trading no consiste en tener razón todo el tiempo. “Se trata de maximizar las ganancias y minimizar las pérdidas”.
Éste es el objetivo de los modelos financieros, la ecuación de Black-Scholes y las estrategias de trading cuantitativo: maximizar las ganancias y minimizar las pérdidas. No hay novedades aquí. La respuesta de los traders exitosos al enigma del mercado es una verdad muy conocida incluso antes de que el comerciante de arroz japonés Munehisa Homma inventara los gráficos de velas: la gestión de riesgos.

Pero con o sin el uso de modelos financieros, cualquier estrategia comercial puede funcionar bastante bien durante un tiempo, un período de tiempo desconocido. Puede ser rentable para un día, para un mes, para un año…, no lo sabemos. La única garantía es que funcionó en el pasado y fue rentable en esos símbolos, período y marco temporal, con esos valores de parámetros utilizados en la prueba retrospectiva. Puede dejar de ser rentable en el siguiente minuto, en la primera ejecución, o puede funcionar para siempre. Una vez más, no lo sabemos. No podemos saberlo, porque el mercado es un enigma. No podemos resolver este enigma. No existe ningún código que descifrar. Sólo existe un estado continuo de cambio.

El mercado está en un estado continuo de cambio.

El mercado está cambiando todo el tiempo. La única constante en el mercado es el cambio. Los valores de nuestros parámetros se eligen no porque sean los más adecuados para un estado específico del mercado, sino porque fueron los más adecuados para un cambio específico del mercado. Entre el momento en el que colocamos una orden ganadora y el momento en el que la orden se cerró, el mercado cambió de la manera que esperábamos. Por el contrario, entre el momento en el que colocamos una orden perdedora y el momento en el que la orden se cerró, el mercado cambió de una manera que no esperábamos. Esto es cierto incluso si no podemos decir qué cambio contribuyó más al resultado final.

Para ser claros: nunca podremos identificar el cambio preciso que convirtió una estrategia rentable en una fuente de dinero o viceversa. Para mejorar una estrategia comercial, lo que haremos es buscar un patrón para aumentar las probabilidades de repetir las decisiones correctas cuando enfrentemos cambios similares en el estado del mercado en el futuro. Encontrar, aprender y comprender estos patrones es lo que hace un trader experimentado en meses o años de operar con el mismo activo o grupo de activos. No es por ninguna otra razón que tenemos diarios comerciales. Se trata de registrar cuáles eran nuestras suposiciones sobre los cambios esperados del mercado y poder revisarlas posteriormente para mejorar nuestras suposiciones.

Gracias al gran volumen de datos disponibles hoy en día y a los potentes ordenadores para procesarlos, podemos acortar estos años de aprendizaje de búsqueda de patrones a horas o incluso minutos. Podemos automatizar la recopilación de datos, el análisis y la ejecución comercial. Podemos automatizar las pruebas y los informes. Incluso podemos automatizar la elección del símbolo/activo a comercializar y la estrategia a utilizar entrenando un modelo integral de aprendizaje automático para aprender esos patrones. Con una cantidad adecuada de recursos en dinero, gente calificada y tiempo, sí podemos.

Pero, como se mencionó anteriormente, estas notas se centran en el trader minorista promedio. Con estos dos principios simples, aunque poco conocidos, en mente, veamos cómo podemos empezar a comprender qué es StatArb y cómo funciona.


Construyendo la cartera

Debido a que el mercado es un enigma en continuo estado de cambio, construiremos nuestra cartera sin preconcepciones, no haremos suposiciones sobre lo que suponemos que es cierto y la actualizaremos periódicamente. El intervalo de actualización estará determinado por la estrategia comercial y limitado por la potencia computacional.

Debemos tener en cuenta que la construcción de carteras, o la gestión de carteras, es un campo de investigación amplio en sí mismo. Según una revisión exhaustiva de la literatura académica, hace diez años existían al menos cuatro enfoques principales para construir una cartera de arbitraje estadístico de negociación por pares: distancia, cointegración, series de tiempo y control estocástico. Además de estos cuatro enfoques principales, el autor también identificó otros enfoques que incluyen aprendizaje automático, pronósticos combinados, cópula y análisis de componentes principales.

Para mantener nuestro enfoque en ser simples y fundamentales, comencemos con una cartera simple de operaciones de pares. Para algunos autores, el trading de pares es un subconjunto del arbitraje estadístico; para otros, “se asume ampliamente que el trading de pares es el “antepasado” del arbitraje estadístico”, siendo la diferencia el tamaño de la cartera y la complejidad de los algoritmos estadísticos. Como su nombre lo indica, el trading de pares está limitado a dos valores, mientras que el arbitraje estadístico puede involucrar docenas, incluso cientos de símbolos para ser rastreados y eventualmente comercializados. 

El trading de pares, como probablemente ya sabes, no es nada más que dar dos valores con precios históricos correlacionados o cointegrados, vender simultáneamente el valor con tendencia alcista y comprar el valor con tendencia bajista cuando el diferencial histórico entre sus precios se amplía más allá de un umbral elegido. El supuesto subyacente es que los precios “volverán a la media”, convergiendo alrededor del diferencial de precios histórico.

En un arbitraje estadístico completo, no estamos limitados a la correlación o cointegración entre precios. Dado que nuestro objetivo principal en este artículo es simplificar las complejidades del arbitraje estadístico para el trader minorista promedio, comenzaremos a recopilar datos históricos para construir una cartera mínima de trading de pares para el mercado de divisas. Más adelante se podrá ampliar a otros mercados y otras relaciones estadísticas más allá de la correlación de precios.

Elija un grupo de valores para comenzar

Al momento de escribir esto, mi cuenta de terminal MetaTrader 5 informa que hay más de diez mil símbolos disponibles. En nuestro análisis utilizaremos la integración de Python para Metatrader 5.

print("Total symbols =",mt5.symbols_total()) # display all symbols
Total symbols = 10563
Entonces, por razones prácticas, primero necesitamos elegir un subconjunto de todos los símbolos disponibles. Comencemos con los pares XAU.
# get symbols containing XAU in their names
xau_symbols=mt5.symbols_get("*XAU*")
print('len(*XAU*): ', len(xau_symbols))
for s in xau_symbols:
    print(s.name)

len(*XAU*):  6
XAUUSD
XAUEUR
XAUAUD
* XAUG
XAUCHF
XAUGBP

* XAUG es un ETF, por lo que podemos excluirlo por ahora y centrarnos en los otros cinco pares. Veamos cómo se correlaciona cada uno con el XAUUSD.

Ahora necesitamos calcular su correlación histórica de precios. En un escenario real, podríamos querer explorar todas las permutaciones posibles entre los símbolos elegidos, posiblemente cientos de símbolos bursátiles, porque asumimos que no tenemos conocimiento sobre ellos. Pero aquí los filtraremos para ver solo la correlación de precios entre la cotización del oro en dólares estadounidenses (XAUUSD) y la cotización del oro en euros, dólares australianos, francos suizos y libras esterlinas británicas.
Queremos datos de los precios de cierre diarios de un año desde el día actual, lo que supone aproximadamente 250 días de negociación para los mercados de divisas.
# get 250 D1 bars from the current day
xauusd_rates = mt5.copy_rates_from_pos("XAUUSD", mt5.TIMEFRAME_D1, 0, 250)
xaueur_rates = mt5.copy_rates_from_pos("XAUEUR", mt5.TIMEFRAME_D1, 0, 250)
xauaud_rates = mt5.copy_rates_from_pos("XAUAUD", mt5.TIMEFRAME_D1, 0, 250)
xauchf_rates = mt5.copy_rates_from_pos("XAUCHF", mt5.TIMEFRAME_D1, 0, 250)
xaugbp_rates = mt5.copy_rates_from_pos("XAUGBP", mt5.TIMEFRAME_D1, 0, 250)

(...)

# calculate correlation coefficients
import numpy as np
usd_eur_corr = np.corrcoef(xauusd_close['close'], xaueur_close['close'])
usd_aud_corr = np.corrcoef(xauusd_close['close'], xauaud_close['close'])
usd_chf_corr = np.corrcoef(xauusd_close['close'], xauchf_close['close'])
usd_gbp_corr = np.corrcoef(xauusd_close['close'], xaugbp_close['close'])

Esto nos dará los siguientes resultados:


Correlación XAUUSD (Pearson)
XAUEUR
0.9692368
XAUAUD
0.96677962
XAUCHF
0.8418827
XAUGBP
0.90490282

Tabla 1: correlación entre el precio de cierre diario del oro en dólares estadounidenses (XAUUSD) y el oro en euros, dólares australianos, francos suizos y libras esterlinas entre el 9 de abril de 2024 y el 26 de marzo de 2025.

Podemos comprobar visualmente cómo se ve una correlación de precios cercana a 0,97 en el gráfico siguiente.

Un año de precios de cierre diarios del oro cotizado en dólares estadounidenses y euros

Figura 1: Precios de cierre diarios de un año del oro cotizado en dólares estadounidenses y euros.

Tenga en cuenta que el gráfico anterior puede ser engañoso. Podemos sentirnos tentados a “negociar el spread” entre los pares, pero no es el spread real, si es que existe alguno. Convirtamos los XAUEUR a dólares estadounidenses según el tipo de cambio del día.
adjusted_for_dollars = pd.concat([xauusd_close, xaueur_close['close'], eurusd_close['close']], join='inner', axis=1)
adjusted_for_dollars.columns = ['time', 'xauusd', 'xaueur', 'eurusd']
adjusted_for_dollars['xaueur_dollars'] = adjusted_for_dollars['xaueur'] * adjusted_for_dollars['eurusd']
adjusted_for_dollars['diff'] = abs(adjusted_for_dollars['xauusd'] - adjusted_for_dollars['xaueur_dollars'])

print(adjusted_for_dollars)

         time   xauusd   xaueur   eurusd  xaueur_dollars       diff
0   2024-04-12  2344.22  2202.92  1.06237     2340.316120   3.903880
1   2024-04-15  2383.10  2242.90  1.06181     2381.533649   1.566351
2   2024-04-16  2382.85  2243.81  1.06720     2394.594032  11.744032
3   2024-04-17  2361.16  2212.14  1.06425     2354.269995   6.890005
4   2024-04-18  2378.86  2234.79  1.06557     2381.325180   2.465180
..         ...      ...      ...      ...             ...        ...
245 2025-03-25  3019.81  2797.81  1.07918     3019.340596   0.469404
246 2025-03-26  3018.85  2807.50  1.07370     3014.412750   4.437250
247 2025-03-27  3056.42  2829.26  1.07975     3054.893485   1.526515
248 2025-03-28  3084.20  2847.12  1.08276     3082.747651   1.452349
249 2025-03-31  3118.19  2882.78  1.08152     3117.784226   0.405774

[250 rows x 6 columns]
adjusted_for_dollars.plot(title = 'One Year of XAUUSD and XAUEUR in US Dollars (D1)', x='time', y=['xauusd', 'xaueur_dollars'])
plt.show()

Un año de precios de cierre diarios del oro cotizados en dólares estadounidenses y euros ajustados a dólares estadounidenses
Figura 2: Precios de cierre diarios de un año de oro cotizados en dólares estadounidenses y euros ajustados a dólares estadounidenses.

Observando la diferencia entre la cotización del oro en USD y la cotización del oro en euros… 

print("median: ", adjusted_for_dollars['diff'].median())
adjusted_for_dollars['diff'].describe()

median:  4.052404150000029
count    250.000000
mean       5.894673
std        6.238511
min        0.050646
25%        1.279615
50%        4.052404
75%        8.587763
max       51.483719
median:  4.052404150000029

... observaremos que la diferencia media real en este periodo de un año fue de ~5,9 dólares, con una desviación estándar de ~6,2 dólares. Si simplificamos demasiado y suponemos que la diferencia (spread) entre ambas cotizaciones después de la conversión al tipo de cambio actual debería ser cercana a cero, podemos considerar cualquier spread por encima de la media como una anomalía negociable en el mercado. 

Elija la relación estadística que desea buscar

Luego decidimos comenzar a construir nuestra cartera de arbitraje estadístico en función de la alta correlación que encontramos entre XAUUSD y XAUEUR en el último año comercial (~250 días). Pero, ¿es la correlación de precios la relación estadística correcta o incluso la mejor que debemos buscar al construir una cartera de arbitraje estadístico?

Cuando hablamos de correlación en precios históricos estamos sujetos a ser engañados por algunas diferencias entre el uso popular del término y su significado estadístico apropiado. Este hecho es aún más evidente en la comunidad Forex. Una simple búsqueda de “pares de Forex correlacionados” nos llevará a muchos recursos que enumeran los pares más/menos correlacionados junto con consejos sobre cómo operar con ellos. No es nuestro objetivo aquí decir si este o aquel recurso, listado o consejo comercial es correcto o incorrecto. Lo que debemos tener en cuenta es que estamos sentando las bases para un arbitraje estadístico a nivel de cartera que no debe limitarse a los pares de divisas. En cambio, nuestro sistema debe generalizarse a cualquier clase de activo, en cualquier mercado y en cualquier período de tiempo, sujeto únicamente a los requisitos de ser neutral respecto del mercado y comprobable.

Según los estadísticos, se espera que la función de coeficiente de correlación de Pearson se utilice en series estacionarias y una serie temporal de precios no es estacionaria. Calculando la correlación en una serie temporal no estacionaria podemos obtener lo que se denomina “correlaciones espurias”. 

“Los datos no estacionarios, por regla general, son impredecibles y no se pueden modelar ni pronosticar. Los resultados obtenidos al utilizar series de tiempo no estacionarias pueden ser espurios, ya que pueden indicar una relación entre dos variables cuando no existe ninguna. Para obtener resultados consistentes y confiables, los datos no estacionarios deben transformarse en datos estacionarios”. (Nason, GP (2006). Series temporales estacionarias y no estacionarias. Investopedia)

Entonces, como comerciantes que buscan construir una cartera de arbitraje estadístico, tenemos que tomar una decisión: ¿es suficiente esa “correlación espuria” o necesitamos una correlación adecuada en el sentido estadístico? Por ahora, aceptamos la primera medida, no perfecta, como suficiente para nuestro modelo simplificado. Pero no debemos olvidar que los pares correlacionados pueden seguir ampliando el spread durante largos períodos mientras suben o bajan juntos, es decir, pueden no volver a la media durante largos períodos y, aun así, la correlación estadística todavía se aplica. Esta condición es excepcional cuando se trata de divisas, pero muy común cuando se trata de materias primas, futuros o series temporales de precios de acciones. Por lo tanto, los niveles de stop loss y el timing de las posiciones son obligatorios cuando se trabaja con estrategias de “retorno esperado a la media”.

Elija la medida estadística que será el disparador comercial

¿Por qué elegir la media o la mediana como medida de nuestra dispersión histórica? Según los estadísticos, deberíamos utilizar la media cuando nuestros datos tienen pocos valores atípicos y la mediana cuando el conjunto de datos tiene picos extremos porque la mediana se ve menos afectada por estos picos. Por ejemplo, si desea filtrar la gran dispersión causada por noticias de alto impacto, puede elegir la mediana. Por el contrario, si desea tener en cuenta los efectos de estas noticias de alto impacto en el spread, es posible que prefiera elegir la media.

Así que no existe ninguna “receta”. Debes decidir por ti mismo basándose en tus datos y tu buen juicio. Incluso podría optar por no utilizar ni la media ni la mediana. En lugar de ello, puede investigar y decidir que otra relación es mejor para su caso de uso.
Iré con la media y estableceré un parámetro para nuestra estrategia comercial en función de la ampliación del diferencial medio. Digamos que cuando el spread entre XAUUSD y XAUEUR se amplía en más del 50% de la media, activamos la operación, comprando el símbolo que está perdiendo la carrera y vendiendo simultáneamente el símbolo que está subiendo más rápido.

¿Cómo podemos determinar qué símbolo está subiendo y cuál está bajando? Para nuestro caso específico, dado que asumimos que ambas cotizaciones del oro deberían ser las mismas después de la conversión, podemos simplemente obtener el símbolo con el precio más grande como el par ascendente y el otro como el par descendente. Si estuviéramos tratando con el spread de precios de acciones que vuelven a la media, podríamos utilizar un promedio móvil exponencial con un período muy corto y asumir que el símbolo que se negocia por encima de la EMA está subiendo y viceversa.

bool IsRising(const int symbol)
  {
   switch(symbol)
     {
      case BASE_PAIR:
         //Print("Base pair is rising? ", quotes_base[0] > ema_base[0]);
         return quotes_base[0] > ema_base[0];
      case CORR_PAIR:
         //Print("Corr pair is rising? ", quotes_corr[0] > ema_corr[0]);
         return quotes_corr[0] > ema_corr[0];
      default:
         return false;
     }
  }

bool IsFalling(const int symbol)
  {
   switch(symbol)
     {
      case BASE_PAIR:
         //Print("Base pair is falling? ", quotes_base[0] < ema_base[0]);
         return quotes_base[0] < ema_base[0];
      case CORR_PAIR:
         //Print("Corr pair is falling? ", quotes_corr[0] < ema_corr[0]);
         return quotes_corr[0] < ema_corr[0];
      default:
         return false;
     }
  }
O podemos utilizar la pendiente.

void CalculateSlopes(double & slope_b[], double & slope_c[])
  {
   slope_b[0] = MathAbs((quotes_base[0] - quotes_base[SlopePeriod]) / SlopePeriod);
   slope_c[0] = MathAbs((quotes_corr[0] - quotes_corr[SlopePeriod]) / SlopePeriod);
  }
En nuestro caso, simplemente utilizamos el símbolo con el precio más alto.

if(quotes_base[0] > quotes_corr[0])



Operar con la cartera

Hemos creado un EA sencillo para probar nuestra hipótesis en una prueba retrospectiva.Hemos creado un EA simple para probar nuestra hipótesis en un backtest. 

Obtenemos las cotizaciones iniciales en OnInit() y las actualizamos en OnTimer(). Esto se debe a que no podemos confiar en el controlador de eventos OnTick para actualizar las cotizaciones del par que no es el del gráfico de trabajo actual, ya que OnTick() solo se llama para el símbolo/gráfico actual. Véase «Expert Advisors multidivisa» o «Expert Advisors multisímbolo».

int OnInit()
  {
   ArrayResize(quotes_base, CountQuotes);
   ArrayResize(quotes_corr, CountQuotes);
   ArrayResize(quotes_conv, CountQuotes);
//--- Get start quotes for both pairs
   GetQuotes();
//--- EMA indicators
   EMA_Handle_Base = iMA(BasePair, _Period, EMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
   EMA_Handle_Corr = iMA(CorrPair, _Period, EMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
   if(EMA_Handle_Base == INVALID_HANDLE ||
      EMA_Handle_Corr == INVALID_HANDLE)
     {
      printf(__FUNCTION__ + ": EMA initialization failed");
      return(INIT_FAILED);
     }
//--- create timer
   EventSetTimer(5); // seconds
//---
   return(INIT_SUCCEEDED);
  }

bool GetQuotes()
  {
   if(CopyClose(BasePair, _Period, 0, CountQuotes, quotes_base) != CountQuotes)
     {
      Print(__FUNCTION__ + ": CopyClose failed. No data");
      //printf("Size quotes base pair %i ", ArraySize(quotes_base));
      return false;
     }
   if(CopyClose(CorrPair, _Period, 0, CountQuotes, quotes_corr) != CountQuotes)
     {
      Print(__FUNCTION__ + ": CopyClose failed. No data");
      //printf("Size quotes corr pair %i ", ArraySize(quotes_corr));
      return false;
     }
   if(CheckMode == PRICE)
     {
      if(CopyClose(ConvPair, _Period, 0, CountQuotes, quotes_conv) != CountQuotes)
        {
         Print(__FUNCTION__ + ": CopyClose failed. No data");
         //printf("Size quotes conv pair %i ", ArraySize(quotes_conv));
         return false;
        }
      //---
      for(int i = 0; i < CountQuotes; i++)
        {
         quotes_corr[i] *= quotes_conv[i];
        }
     }
   return true;
  }

void OnTimer()
  {
   UpdateQuotes();
   CalculateMeanSpread();
   if(CheckMode == EMA)
     {
      GetEMAs();
     }
  }

void UpdateQuotes()
  {
   ArrayRemove(quotes_base, ArraySize(quotes_base) - 1);
   double new_quote_base[1];
   CopyClose(BasePair, _Period, 0, 1, new_quote_base);
   ArrayInsert(quotes_base, new_quote_base, 0, 0);
//---
   ArrayRemove(quotes_corr, ArraySize(quotes_corr) - 1);
   double new_quote_corr[1];
   CopyClose(CorrPair, _Period, 0, 1, new_quote_corr);
   ArrayInsert(quotes_corr, new_quote_corr, 0, 0);
//---
   if(CheckMode == PRICE)
     {
      ArrayRemove(quotes_conv, ArraySize(quotes_conv) - 1);
      double new_quote_conv[1];
      CopyClose(ConvPair, _Period, 0, 1, new_quote_conv);
      ArrayInsert(quotes_conv, new_quote_conv, 0, 0);
      quotes_corr[0] *= quotes_conv[0];
     }
  }

Calcular la dispersión media.

bool CalculateMeanSpread()
  {
   int sz_base_p = ArraySize(quotes_base);
   int sz_corr_p = ArraySize(quotes_corr);
   int sz_conv_p = ArraySize(quotes_conv);
   if(sz_base_p != sz_corr_p ||
      sz_corr_p != sz_conv_p)
     {
      Print(__FUNCTION__ + " Failed: Arrays must be of same size");
      return false;
     }
//---
   ArrayResize(pairs_spread, CountQuotes);
   for(int i = 0; i < sz_base_p; i++)
     {
      pairs_spread[i] = MathAbs(quotes_base[i] - quotes_corr[i]);
     }
   double max_spread = pairs_spread[ArrayMaximum(pairs_spread)];
   double min_spread = pairs_spread[ArrayMinimum(pairs_spread)];
   mean_spread = MathMean(pairs_spread);
//---
//printf("Last quote XAUUSD %f ", quotes_base[0]);
//printf("Last quote XAUEUR %f ", quotes_corr[0]);
//printf("Last spread %f ", pairs_spread[0]);
//printf("Max  spread %f ", max_spread);
//printf("Min  spread %f ", min_spread);
//printf("Mean spread %f ", mean_spread);
   return true;
  }

Comprobamos señales comerciales en OnTick.

void OnTick()
  {
//---
   CheckForClose();
   CheckForOpen();
  }

Cuando el spread es mayor que la media en al menos el porcentaje que hemos establecido.

bool HasSpreadTrigger()
  {
   double trigger_spread = mean_spread + (mean_spread * (PercentTrigger / 100.0));
//printf(" trigger spread %f ", trigger_spread);
   double current_spread = pairs_spread[0];
//printf(" current spread %f ", current_spread);
   return current_spread >= trigger_spread;
  }

Compramos el símbolo que tiene un precio bajo y vendemos el símbolo que tiene un precio alto. En nuestro ejemplo, este cambio se realiza en la enumeración CheckMode (enum). 

void CheckForOpen()
  {
   if(PositionsTotal() == 0 && HasSpreadTrigger())
     {
      switch(CheckMode)
        {
         case EMA:
            if(IsRising(BASE_PAIR) && IsFalling(CORR_PAIR))
              {
               OpenShort(BasePair);
               OpenLong(CorrPair);
              }
            if(IsFalling(BASE_PAIR) && IsRising(CORR_PAIR))
              {
               OpenLong(BasePair);
               OpenShort(CorrPair);
              }
            break;
         case SLOPE:
            CalculateSlopes(slope_base, slope_corr);
            if(slope_base[0] > slope_corr[0])
              {
               OpenShort(BasePair);
               OpenLong(CorrPair);
              }
            else
              {
               OpenLong(BasePair);
               OpenShort(CorrPair);
              }
            break;
         case PRICE:
            if(quotes_base[0] > quotes_corr[0])
              {
               OpenShort(BasePair);
               OpenLong(CorrPair);
              }
            else
              {
               OpenLong(BasePair);
               OpenShort(CorrPair);
              }
        }
     }
  }

Las posiciones se cerrarán mediante stop-loss/take-profit o reversión a la media en CheckForClose().

void CheckForClose()
  {
   int total = PositionsTotal();
   ulong ticket = 0;
   if(total > 0)
     {
      if(PositionSelect(BasePair) || PositionSelect(CorrPair))
        {
         for(int i = 0; i < total; i++)
           {
            ticket = PositionGetTicket(i);
            if(ticket == 0)
               continue;
            if(pairs_spread[0] <= mean_spread)
              {
               ExtTrade.PositionClose(ticket);
              }
           }
        }
     }
  }

La prueba retrospectiva confirma que la estrategia de reversión a la media es viable para el trading de pares.

Figura 3: Gráfico de la prueba retrospectiva del capital.

Figura 3. Prueba retrospectiva del gráfico de capital.

Aunque el backtest valida nuestra hipótesis, se puede ver que este algoritmo específico requiere mejoras para suavizar la curva de capital. Tal vez un tamaño de orden dinámico (el volumen comercial aquí está fijado en el mínimo de 0,01 - micro lote) y optimizaciones para la relación stop-loss/take-profit. Pero la rentabilidad no es nuestra principal preocupación aquí en este artículo. Dicho esto, echemos un vistazo a algunos resultados interesantes que, según algunos autores, parecen ser comunes en las operaciones de arbitraje estadístico.

Fig. 4 - Resultados de la prueba retrospectiva.

Figura 4. Resultados de la prueba retrospectiva.

Hay una gran cantidad de operaciones, la relación entre ganancias y pérdidas es pequeña (~55/~45) y la reducción máxima del saldo es relativamente baja.

Figura 5: Tiempos de trading en la prueba retrospectiva.

Figura 5. Tiempos de trading en la prueba retrospectiva.

La concentración en torno a periodos específicos (horas, días de la semana, etc.). En nuestro caso, la concentración está alrededor de la apertura de la sesión de EE.UU., con un pico en abril de 2024.

Figura 6. Relación entre tiempo de mantenimiento de la posición y beneficio obtenido.

Figura 6. Relación entre tiempo de mantenimiento de la posición y beneficio obtenido.

La gran cantidad de operaciones muy cortas indica que nuestro sistema ha estado explorando momentos de inestabilidad del mercado reingresando después de operaciones ganadoras.

¿Qué podría ser mejor?

Ahora, me gustaría llamar su atención sobre el punto de que el vendedor de una estrategia o configuración comercial intentará mostrarle los mejores resultados pasados posibles para fomentar su interés en su producto. Al final, seleccionarán los parámetros de mayor rendimiento después de una optimización cuidadosa para enfatizar las ganancias potenciales y disminuir el riesgo de pérdidas.

Pero, excepto la idea de que puedes entender los principios y comenzar de a poco con el arbitraje estadístico, no te estoy “vendiendo” nada aquí. Por el contrario, diría que estoy contento de que el backtest muestre que estamos ante un algoritmo que requiere mejoras. Porque ésta es la piedra angular de todo sistema de arbitraje estadístico.

Es decir, hasta ahora para esta automatización simplista, nos hemos limitado a parámetros elegidos arbitrariamente para gestionar el riesgo. En cambio, lo que necesitamos es:

  1. Controlar el número de posiciones a abrir según el riesgo evaluado en cada punto
  2. Tener un porcentaje de spread de activación flotante que tenga en cuenta la volatilidad
  3. Desarrollar una estrategia dinámica de stop-loss/take-profit que derive la probabilidad de ganancia del valor del diferencial de activación y posiblemente de otras variables

Estas son algunas posibles formas de mejorar en el futuro este EA.

Resumen del modelo a escala

1. Empecemos con una hipótesis

La dispersión entre pares correlacionados tiende a volver a la media. Ésta es nuestra hipótesis aquí.

Desde la perspectiva del comerciante, el concepto de reversión a la media es simple e intuitivo: cuando el precio actual está por debajo del precio promedio, se puede esperar que el precio suba y cuando el precio actual está por encima del precio promedio, se puede esperar que el precio baje. Como dice el refrán, el precio siempre “busca el punto medio”.

Los valores sobrecomprados o sobrevendidos tienden a volver al precio medio.

Figura 7. Los valores sobrecomprados o sobrevendidos tienden a volver al precio medio (Fuente: ResearchGate CC BY 4.0).

En los mercados con tendencia, la media se convierte en un soporte dinámico para las tendencias alcistas y en una resistencia dinámica para las tendencias bajistas. En los mercados en consolidación, la media tiende a moverse en el canal, el punto medio entre los máximos más altos y los mínimos más bajos.

Esta característica es más observable en plazos cortos para los tipos de cambio de divisas porque, mientras que el precio de cualquier otro activo puede, al menos en teoría, subir o bajar indefinidamente, los tipos de cambio de divisas están «limitados» por las normas comerciales entre naciones. 

Por ejemplo: "Apple salió a bolsa el 12 de diciembre de 1980 a 22,00 dólares por acción. Las acciones se han dividido cinco veces desde la oferta pública inicial, por lo que, ajustadas por la división, el precio de las acciones en la oferta pública inicial fue de 0,10 dólares."

En el momento de redactar este artículo, Apple cotiza a 192,00 dólares estadounidenses (~ 875 %). Y sigue subiendo. No existe límite teórico.

Por otra parte, no se puede esperar ni siquiera una apreciación o depreciación del 50% en los tipos de cambio entre dos monedas sin pensar al mismo tiempo en factores extremos como la hiperinflación o incluso una guerra a gran escala. En condiciones normales, el tipo de cambio que define el “precio” del par en el trading de Forex debería volver a la media mucho antes.

2. Buscar patrones en los datos para probar la hipótesis

La correlación de Pearson de 0,97 entre XAUUSD y XAUEUR denota nuestro patrón: los precios de estos dos valores tienden a subir o bajar simultáneamente.

3. Monitorizar anomalías en los patrones

El diferencial medio entre XAUUSD y XAUEUR que se aleja mucho de la media es nuestra anomalía. Encontrar anomalías en los patrones del mercado es el pan de cada día del arbitraje estadístico a nivel de cartera tal como lo utilizaban las operaciones del equipo de Simons.

4. Desarrollar una automatización para negociar las anomalías

El EA simplista representa nuestra automatización, pero como se dijo anteriormente, el algoritmo requiere muchas mejoras, es solo una herramienta para ayudarnos a comprender mejor los principios. Además de eso, el propio EA requiere todas las comprobaciones de errores habituales.


Conclusión

El arbitraje estadístico a nivel de cartera, tal como lo realizan los grandes participantes, es prácticamente imposible para el trader minorista promedio. Porque necesitaríamos operar en el mercado de alta frecuencia (HFT), con un equipo altamente cualificado, big data de alta calidad y mucho dinero. Para convertir nuestro modelo a escala en algo similar o incluso cercano a una operación de fondos de cobertura de Jim Simons, diría, con sarcasmo, que todo lo que necesitamos es poder...

  • Realice análisis de mercado con granularidad de subsegundos para cientos de símbolos de activos en cada cartera en tiempo real. (En algún momento, el equipo de Simmons estaba lidiando con más de ocho mil acciones diferentes, en una docena de mercados y territorios).
  • Envíe pedidos de un millón de dólares y recíbalos en una millonésima de segundo.
  • Actualice el modelo periódicamente 

Bueno, supongo que podemos empezar a actualizar el modelo periódicamente. 🙂

Pero en serio, lo que la cita de Isaac Newton nos enseña es que las matemáticas por sí solas no son suficientes para prosperar en los mercados financieros. Muchos matemáticos fracasaron donde Simons tuvo éxito. Pero Simons no fue al campo de batalla sólo con matemáticas. Comenzó su carrera en finanzas realizando operaciones como cualquier otro trader, buscando tendencias, confiando en el análisis técnico y la intuición, y ganando y perdiendo dinero. Probó varios métodos, aprendió las reglas del juego, habló, se asoció y trabajó con traders profesionales mientras intentaba encontrar una forma sostenible de operar.

Sin embargo, su marco conceptual es accesible para cualquiera que esté dispuesto a hacer el esfuerzo necesario para seleccionar la cartera adecuada, elegir las características correctas para estudiar, buscar patrones y anomalías, crear prototipos con datos gratuitos y comprar datos de alta calidad cuando el prototipo sea lo suficientemente prometedor para alcanzar el modelo más equilibrado para una cartera específica. Probablemente muchos comerciantes minoristas de todo el mundo están pagando este esfuerzo con un trabajo serio día a día. La mayoría de ellos no se están convirtiendo en multimillonarios, pero ciertamente, muchos de ellos han convertido su actividad comercial en un negocio sostenible.

Incluso podemos seguir la ruta del aprendizaje automático para descubrir estos patrones y anomalías. Es accesible a los mortales y parece ser el futuro ya presente, aquí y ahora. Hay, literalmente, cientos de artículos de alta calidad sobre el uso del aprendizaje automático en el entorno MetaTrader 5. Hoy en día NO es necesario que conozcamos matemáticas de bajo nivel para utilizar el aprendizaje automático en nuestro sistema de trading. Podemos utilizar MQL5 o Python, ambos con baterías incluidas, es decir, con librerías de machine learning de alto nivel. 

En resumen, este artículo propone a los traders minoristas con recursos limitados una forma esquemática de comprender los fundamentos detrás del arbitraje estadístico a nivel de cartera.

Como dice el refrán, los resultados pasados no son garantía de resultados futuros. Pero podemos tomar decisiones más informadas si analizamos esos resultados pasados con las herramientas adecuadas y datos objetivos.


Archivo adjunto Descripción
 pairs-trading.mq5 Este archivo contiene el código de muestra del Asesor Experto para reproducir el experimento. Requiere (#<include>) el archivo PairsTradingFunctions.mqh.
 PairsTradingFunctions.mqh Este archivo es el archivo de inclusión requerido por el archivo anterior de esta lista y, por el momento, solo contiene una enumeración (enum) del modo de verificación utilizado por el EA para identificar el símbolo ascendente/descendente en los pares.
 pairs-trading.ipynb Este archivo es un archivo Jupyter Notebook que contiene código Python para ejecutar el análisis estadístico.
 stat_arb_pairs_trading_GOLD_XAUEUR.ini  Este archivo contiene la configuración del probador de estrategias de MetaTrader 5 para reproducir el experimento.


Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/17735

Janis Ozols
Janis Ozols | 16 sept 2025 en 15:20

Fuera del tema del artículo, pero muy interesante....

¿Cómo es posible que el artículo se publique hoy (16 de septiembre), pero los primeros comentarios al mismo estén fechados el 11 de abril?

Roman Shiredchenko
Roman Shiredchenko | 16 sept 2025 en 15:28
Janis Ozols #:

Fuera del tema de la pregunta del artículo, pero muy interesante....

¿Cómo es que el artículo se publica hoy (16 de septiembre), pero los primeros comentarios al mismo son del 11 de abril?

Es una traducción, como me he dado cuenta, de otro idioma del foro..... en el idioma nativo se publicó antes aparentemente..... publicado

Aleksey Nikolayev
Aleksey Nikolayev | 16 sept 2025 en 16:23

> Sir Isaac Newton a la edad de noventa...

Newton vivió 84 años (¿traducción rusa torcida?).

Roman Shiredchenko
Roman Shiredchenko | 28 nov 2025 en 12:33

gracias por el articulo. Spin enfoque tanto para 3 y 4 y 6 caracteres!!! código de su análisis. ¡Gracias de nuevo el contenido es super!

Thomas Gardling
Thomas Gardling | 15 ene 2026 en 13:56

Obtención de un array fuera de rango en el pairs_spread[0];

bool HasSpreadTrigger()
  {
   double trigger_spread = mean_spread + (mean_spread * (PercentTrigger / 100.0));
//printf(" margen_disparo %f ", margen_disparo);
   double current_spread = pairs_spread[0];
//printf(" dispersión actual %f ", dispersión_actual);
   return current_spread >= trigger_spread;
  }
Utilizando redes neuronales en MetaTrader Utilizando redes neuronales en MetaTrader
En el artículo se muestra la aplicación de las redes neuronales en los programas de MQL, usando la biblioteca de libre difusión FANN. Usando como ejemplo una estrategia que utiliza el indicador MACD se ha construido un experto que usa el filtrado con red neuronal de las operaciones. Dicho filtrado ha mejorado las características del sistema comercial.
Optimización de Battle Royale — Battle Royale Optimizer (BRO) Optimización de Battle Royale — Battle Royale Optimizer (BRO)
El artículo describe un innovador enfoque de optimización que combina la competición espacial de soluciones con el estrechamiento adaptativo del espacio de búsqueda, lo cual convierte al Battle Royale Optimizer en una prometedora herramienta para el análisis financiero.
Particularidades del trabajo con números del tipo double en MQL4 Particularidades del trabajo con números del tipo double en MQL4
En estos apuntes hemos reunido consejos para resolver los errores más frecuentes al trabajar con números del tipo double en los programas en MQL4.
Aprendizaje automático en la negociación de tendencias unidireccionales tomando el oro como ejemplo Aprendizaje automático en la negociación de tendencias unidireccionales tomando el oro como ejemplo
En este artículo analizaremos un enfoque interesante: la negociación solo en la dirección seleccionada (compra o venta). Para ello, utilizaremos técnicas de inferencia causal y aprendizaje automático.