English Русский 中文 Deutsch 日本語
preview
Formulación de un Asesor Experto Multipar Dinámico (Parte 1): Correlación de divisas y correlación inversa

Formulación de un Asesor Experto Multipar Dinámico (Parte 1): Correlación de divisas y correlación inversa

MetaTrader 5Ejemplos | 20 marzo 2025, 09:27
517 0
Hlomohang John Borotho
Hlomohang John Borotho

Introducción

Cuando se cuenta con una estrategia o un sistema comercial sólido con una tasa de ganancias o un factor de ganancias favorable, diversificar las operaciones entre pares de divisas correlacionados e inversamente correlacionados puede mejorar el rendimiento general. Demostraré cómo desarrollar un sistema que identifique correlaciones y correlaciones inversas entre múltiples pares de divisas, permitiendo a los operadores capitalizar estas relaciones para mejorar las oportunidades comerciales.

Durante eventos comerciales importantes, como los anuncios de nóminas no agrícolas (NFP), el mercado a menudo se mueve rápidamente en una dirección predeterminada. En tales escenarios, la ejecución en múltiples pares de divisas se puede simplificar designando un par de divisas principal. Las transacciones iniciadas en este par principal determinarían las transacciones correspondientes en otros pares, aprovechando las relaciones de correlación y correlación inversa entre ellas. Este enfoque puede mejorar significativamente la eficiencia y la consistencia durante eventos de mercado de alto impacto.

Qué se cubrirá:

  • La capacidad de cambiar y modificar pares de divisas.
  • La indexación del par de divisas que servirá como proveedor de señales para otros pares de divisas.
  • Determinar las monedas base y cotizadas para operar.

En el trading, la correlación se refiere a la relación entre los movimientos de precios de diferentes pares de divisas. Cuando dos pares de divisas están correlacionados positivamente, tienden a moverse en la misma dirección. Por ejemplo, el GBPUSD y el EURUSD suelen estar correlacionados positivamente, lo que significa que cuando el GBPUSD sube, el EURUSD también tiende a subir. Esto se debe a que ambos pares comparten el USD como moneda de cotización, y cualquier debilidad o fortaleza general del USD probablemente afectará a ambos pares de la misma manera.

Por otro lado, la correlación inversa existe cuando dos pares de divisas se mueven en direcciones opuestas. Un ejemplo clásico es la relación entre GBPUSD y USDCAD. Cuando el GBPUSD sube (alcista), el USDCAD a menudo baja (bajista). Esto sucede porque en el primer par (GBPUSD), el USD es la moneda de cotización, mientras que en el segundo par (USDCAD), el USD es la moneda base. A medida que el USD se debilita, el GBPUSD sube, mientras que el USDCAD tiende a caer.

Formularemos un EA multipar dinámico para manejar múltiples pares de divisas simultáneamente. El sistema le brindará flexibilidad al permitirle ingresar, cambiar y modificar pares de divisas según su estrategia comercial. Una característica clave de este sistema es su capacidad para definir un par de divisas primario o "principal", que actúa como proveedor de señales para otros pares de divisas.

En el núcleo del sistema se encuentra la capacidad de ajustar dinámicamente la lista de pares de divisas que se negocian. Los traders pueden personalizar fácilmente qué pares se incluyen en la estrategia comercial, haciéndola adaptable a diversas condiciones del mercado o planes comerciales. El EA acepta entradas para diferentes pares de divisas, lo que permite a los usuarios agregar, eliminar o cambiar entre pares según sea necesario.

Uno de los aspectos más innovadores es la designación de un par de divisas primario o principal. Este par no solo se negocia activamente, sino que también sirve como punto de referencia para generar señales para otros pares. Al monitorear este par principal, el EA identifica señales comerciales (ya sea de compra o de venta) y las aplica a los pares correlacionados o inversamente correlacionados seleccionados.

El sistema también admite ajustes dinámicos basados en la fuerza de las correlaciones entre pares de divisas. Por ejemplo, si se detecta una fuerte señal alcista en el par de divisas principal, el EA puede abrir automáticamente operaciones correspondientes en pares que históricamente se mueven en la misma dirección. Por el contrario, para los pares que normalmente se mueven en sentido inverso al par principal, el EA puede abrir posiciones opuestas, protegiendo eficazmente contra posibles fluctuaciones del mercado.

Matriz de Forex

Formulación

#include <Trade\Trade.mqh>
CTrade trade;

Esto importa la biblioteca de operaciones de MetaTrader 5 y crea una instancia de la clase "CTrade", lo que le permite administrar operaciones de operaciones como abrir, cerrar y modificar órdenes.

int handles[];

Esta matriz se utiliza para almacenar los controladores de varios indicadores u objetos, que son necesarios para el seguimiento de indicadores de análisis técnico en múltiples pares de divisas. Esta matriz se utiliza para almacenar los controladores de varios indicadores u objetos, que son necesarios para el seguimiento de indicadores de análisis técnico en múltiples pares de divisas.

MqlTick previousTick, currentTick;

Estas variables almacenan datos de ticks para los precios de los símbolos. "previousTick" contiene los datos del último tick, mientras que "currentTick" almacena los datos del tick actual.

inputstring Symbols = "XAUUSD, GBPUSD, USDCAD, USDJPY";
inputstring Base_Quote = "USD";
inputint Currecy_Main = 0;

Estas entradas permiten al usuario personalizar el EA:

  • Symbols: Una lista separada por comas de pares de divisas que el EA monitoreará y negociará.
  • Base_Quote: La moneda para determinar correlaciones.
  • Currency_Main: Un índice que especifica el par de divisas principal que se utilizará para generar señales.
string symb_List[];
string Formatted_Symbs[];
int Num_symbs = 0;
  • symb_List: Una matriz que contiene la lista sin procesar de símbolos que se procesarán.
  • Formatted_Symbs: Una matriz que almacena los símbolos procesados.
  • Num_symb: Contiene el número total de símbolos que se utilizarán después de analizar la entrada `Símbolos`.
intOnInit(){
    string sprtr = ",";
    ushort usprtr;
    usprtr = StringGetCharacter(sprtr, 0);
    StringSplit(Symbols, usprtr, symb_List);
    Num_symbs = ArraySize(symb_List);
    ArrayResize(Formatted_Symbs, Num_symbs);

La función "OnInit" se llama una vez cuando se carga el EA, estableciendo valores y configuraciones iniciales. Luego definimos la coma como separador (sprtr), que se utilizará para dividir la cadena "string" de entrada. La función "StringGetCharacter()" convierte el separador en un "ushort" (corto sin signo) que es necesario para la función "StringSplit()". La función "StringSplit()" divide la entrada "Symbols" (una cadena separada por comas) en una matriz de símbolos individuales. La matriz "symb_List[]" contiene los símbolos analizados. La matriz "Formatted_Symbs[]" se redimensiona para que coincida con la cantidad de símbolos analizados. Utilizaremos esta matriz para un mayor procesamiento, como agregar cualquier formato o ajustes necesarios para la lógica comercial.

for(int i = 0; i < Num_symbs; i++){
       Formatted_Symbs[i] = symb_List[i];
    }

Recorremos la cantidad de símbolos y transferimos los símbolos de la matriz "symb_List[]" a la matriz "Formatted_Symbs[]". En esta etapa no se realiza ningún formato adicional.

ArrayResize(handles, ArraySize(Formatted_Symbs));

Aquí, redimensionamos la matriz "handles[]" para que coincida con el tamaño de la matriz "Formatted_Symbs[]". Cada elemento en "handles[]" contendrá el identificador RSI para el símbolo correspondiente.

for(int i = 0; i < ArraySize(Formatted_Symbs); i++){
      handles[i] = iRSI(Formatted_Symbs[i], PERIOD_CURRENT, 14, PRICE_CLOSE);
    }

Este bucle inicializa el controlador del indicador RSI para cada símbolo.



void OnTick(){
   
   if(isNewBar()){
      for(int i = 0; i < ArraySize(Formatted_Symbs); i++){
         Sig_trade(Formatted_Symbs[Currecy_Main], handles[Currecy_Main]);
      }
   }
}

Aquí primero verificamos si tenemos una nueva barra, y luego tenemos un bucle for para detectar el índice de la moneda principal que generará señales. Luego, simplemente llamamos a la función "Sig_trade()" que lleva la lógica comercial, la función toma un parámetro de cadena para el símbolo y un parámetro entero para el controlador RSI.

void Sig_trade(string symb, int handler){   
   double rsi[];
   CopyBuffer(handler, MAIN_LINE, 1, 1, rsi);
   
   bool RSIBuy = rsi[0] < 30;
   bool RSISell = rsi[0] > 70;
   
   // Check if the current symbol is a base USD pair
   bool isBaseUSD = StringSubstr(symb, 0, 3) == Base_Quote;
   bool isQuoteUSD = StringSubstr(symb, 3, 3) == Base_Quote;
   string Bcurr = SymbolInfoString(symb, SYMBOL_CURRENCY_BASE);
   string Qcurr = SymbolInfoString(symb, SYMBOL_CURRENCY_PROFIT);

Utilizaremos una estrategia bastante simple, que consiste en utilizar la estrategia RSI para comprar cuando el RSI cae por debajo del nivel 30 y vender cuando supera el nivel 70.

  • StringSubstr(symb, 0, 3) == Base_Quote: Extrae los tres primeros caracteres del símbolo del par de divisas (symb) y comprueba si son iguales a USD. Esto determina si el símbolo es un par USD base.
  • StringSubstr(symb, 3, 3) == Base_Quote: Extrae los tres caracteres comenzando desde la cuarta posición del símbolo del par de divisas (symb) y verifica si son iguales a USD. Esto determina si el símbolo es un par de cotización USD.
  • Bcurr = SymbolInfoString(symb, SYMBOL_CURRENCY_BASE): Recupera la moneda base del símbolo (la primera moneda del par) y la almacena en la variable "Bcurr".
  • Qcurr = SymbolInfoString(symb, SYMBOL_CURRENCY_PROFIT): Recupera la moneda de cotización del símbolo (la segunda moneda del par) y la almacena en la variable "Qcurr".
for(int i = PositionsTotal() - 1; i >= 0; i--){
      ulong posTicket = PositionGetTicket(i);
      if(PositionGetString(POSITION_SYMBOL) == symb){
         if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY){
            if(RSISell){
               trade.PositionClose(posTicket);
            }
            RSIBuy = false;
         }elseif(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL){
            if(RSIBuy){
               trade.PositionClose(posTicket);
            }
            RSISell = false;
         }
      }
   }

Para gestionar todas las posiciones, repasamos todas las posiciones abiertas. La función "PositionsTotal()" devuelve el número total de posiciones abiertas actualmente. El bucle comienza desde la última posición (PositionsTotal() - 1) e itera hacia atrás. Usamos la iteración hacia atrás para evitar problemas al modificar la lista de posiciones abiertas durante el bucle. Usamos la función "PositionGetTicket()" para recuperar el número de ticket de la posición en el índice "i". El ticket es un identificador único para cerrar o modificar una posición específica.

Luego usamos la función "PositionGetString()" para recuperar el símbolo de la posición actual. A partir de ahí comparamos este símbolo con "symb" (el símbolo que se está analizando). Si coinciden la posición es relevante. Luego verificamos si la posición actual es una orden de compra, con la función "PositionGetInteger()". Si la posición es de compra y el RSI sugiere una venta ("RSISell" es verdadero), la posición se cierra utilizando "trade.PositionClose(posTicket)". Después de eso asignamos "RSIBuy = false" para garantizar que no se abrirán más operaciones de compra ya que la señal actual indica una venta.

Lo mismo se aplica a las posiciones de venta, verificamos si la posición actual es una orden de venta. Si la posición es de venta y el RSI sugiere una señal de compra ("RSIBuy" es verdadero), la posición se cierra utilizando "trade.PositionClose(posTicket)". También asignamos "RSISell = false" para evitar que se abran nuevas operaciones de venta ya que la señal es para una posición de compra. Utilizamos el código anterior para gestionar todas las posiciones abiertas ya que no utilizamos stop loss ni take profit. Por lo tanto, el código abrirá y cerrará posiciones dependiendo únicamente del RSI.

for(int i = 0; i < ArraySize(Formatted_Symbs); i++){
      string currSymb = Formatted_Symbs[i];
      
      // Get base and quote currencies for the looped symbol
      string currBaseCurr = SymbolInfoString(currSymb, SYMBOL_CURRENCY_BASE);
      string currQuoteCurr = SymbolInfoString(currSymb, SYMBOL_CURRENCY_PROFIT);

Para abrir operaciones en todos los pares de divisas, recorrimos el tamaño (número de elementos) en la matriz "Formatted_Symbs[]". El bucle itera sobre cada elemento (par de divisas) en la matriz "Formatted_Symbs". Almacenamos el símbolo actual en el gráfico en la variable "currSymb" de la matriz "Formatted_Symbs". Este símbolo se utilizará para obtener información relevante sobre el par de divisas.

if(RSIBuy){
         
         if(currQuoteCurr == Base_Quote){
            trade.PositionOpen(currSymb, ORDER_TYPE_BUY, volume, currentTick.ask, NULL, NULL, "Correlation");
         }
         
         if(currBaseCurr == Base_Quote){
            trade.PositionOpen(currSymb, ORDER_TYPE_SELL, volume, currentTick.bid, NULL, NULL, "Correlation");
         }
      }

Aquí verificamos y ejecutamos solo si el indicador RSI genera una señal de compra (generalmente cuando el valor RSI está por debajo de un cierto umbral, lo que indica una condición de sobreventa). Luego verificamos si la moneda de cotización del símbolo actual coincide con la moneda de "Base_Quote" especificada. Si coincide, se abre una orden de compra para ese par de divisas. La lógica detrás de esto es que cuando compras un par de divisas, estás comprando la divisa base y vendiendo la divisa cotizada. Por lo tanto, si su estrategia comercial es alcista en pares donde la cotización es su "Base_Quote", usted compra ese par.

Procedemos a verificar si la moneda base del símbolo actual coincide con la moneda "Base_Quote" especificada. Si coincide, se abre una orden de venta para ese par de divisas. El razonamiento aquí es que si su estrategia es alcista en pares donde la moneda base es la "Base_Quote" especificada, usted vendería ese par. Vender el par significaría efectivamente vender la moneda base y comprar la moneda cotizada.

      if(RSISell){
         
         if(currBaseCurr == Base_Quote){
            trade.PositionOpen(currSymb, ORDER_TYPE_SELL, volume, currentTick.bid, NULL, NULL, "Correlation");
         }
         if(currQuoteCurr == Base_Quote){
            trade.PositionOpen(currSymb, ORDER_TYPE_BUY, volume, currentTick.ask, NULL, NULL, "Correlation");
         }
      }

Aquí manejamos la lógica cuando se detecta una señal de venta RSI. Este bloque se ejecuta si el indicador RSI genera una señal de venta (normalmente cuando el RSI está por encima de un determinado umbral, lo que indica una condición de sobrecompra). Comprobamos si la moneda base del símbolo actual coincide con la "Base_Quote" especificada con "currBaseCurr == Base_Quote". Si coincide, se ejecuta una orden de venta para ese par de divisas. La lógica sigue siendo la misma si eres bajista en pares donde la moneda base es la "Base_Quote" especificada. Entonces quieres vender ese par. Vender ese par significa que estás vendiendo la moneda base y comprando la moneda cotizada.

Luego procedemos a verificar la moneda de cotización del símbolo actual si coincide con la moneda "Base_Quote" especificada. Si coincide, se abre una orden de compra para ese par de divisas. El razonamiento detrás es que si su estrategia es bajista en pares donde la moneda cotizada es la "Base_Quote" especificada, usted abriría una operación de compra en ese par. Esto se debe a que comprar ese par implicaría comprar la moneda base y vender la moneda cotizada.

bool isNewBar()
  {
//--- memorize the time of opening of the last bar in the static variable
   staticdatetime last_time=0;
//--- current time
   datetime lastbar_time= (datetime) SeriesInfoInteger(Symbol(),Period(),SERIES_LASTBAR_DATE); 

//--- if it is the first call of the function
   if(last_time==0)
     {
      //--- set the time and exit
      last_time=lastbar_time;
      return(false);
     }

//--- if the time differs
   if(last_time!=lastbar_time)
     {
      //--- memorize the time and return true
      last_time=lastbar_time;
      return(true);
     }
//--- if we passed to this line, then the bar is not new; return false
   return(false);
  }

Arriba está la función "isNewBar" para que el EA no ejecute múltiples órdenes.

Resultados del Probador de estrategias

Probador de estrategias

Con base en los resultados de las pruebas anteriores, podemos confirmar que el sistema abre operaciones con éxito de acuerdo con las correlaciones monetarias y las correlaciones inversas especificadas. Como se discutió anteriormente, cuando se genera una señal de compra y la moneda principal es un par de USD cotizado, todos los pares de USD cotizados en la matriz "Formatted_Symbs" ejecutan órdenes de compra, mientras que los pares de USD base ejecutan órdenes de venta. Este comportamiento es consistente con la funcionalidad esperada, lo que demuestra que el sistema implementa eficazmente la lógica de correlación que pretendíamos lograr.

Para utilizar el sistema de forma eficaz y correcta, es fundamental considerar el uso de agrupación basada en pares iguales. Por ejemplo, al operar con pares basados en EUR como EURUSD, EURGBP y EURJPY, configurar "EUR" como la entrada "Base_Quote" permitiría que la moneda base guíe la lógica comercial cuando se detecte una señal. Este enfoque se puede aplicar a otros grupos de divisas, como USDEUR, o cualquier otro par personalizado que permita su corredor, lo que garantiza que la lógica del sistema esté correctamente alineada con su estrategia comercial.

El sistema es dinámico, lo que le permite elegir fácilmente el principal par de divisas que proporcionará o generará señales simplemente indexando el par deseado. Esta flexibilidad es particularmente útil ya que el indicador RSI se utiliza para generar señales, y el buffer y el manejador del RSI se aplican a todos los pares de divisas. Esto garantiza que el par principal seleccionado impulse eficazmente las decisiones comerciales de los demás pares correlacionados en el sistema.

Conclusión

En resumen, hemos explorado y desarrollado un EA multipar dinámico que procesa señales comerciales basadas en el indicador RSI y las aplica en varios pares de divisas correlacionados e inversamente correlacionados. El EA permite la entrada de pares de divisas personalizables y designa un par de divisas principal para impulsar las decisiones comerciales para los demás pares de divisas. A través del análisis de las monedas base y cotizadas, el EA abre operaciones que se alinean con la tendencia general del mercado, utilizando la lógica de correlación.

En conclusión, el asesor experto dinámico de múltiples pares puede lograr resultados comerciales más consistentes al aplicar sistemáticamente estrategias de correlación y correlación inversa. Este enfoque no solo optimiza la eficiencia comercial al automatizar la propagación de señales. Al integrar la correlación y la correlación inversa en el sistema comercial, los operadores pueden aprovechar la relación entre los pares de divisas correlacionados.


Curva de capital

Prueba retrospectiva

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

Archivos adjuntos |
Algoritmo de optimización basado en la migración animal (Animal Migration Optimization, AMO) Algoritmo de optimización basado en la migración animal (Animal Migration Optimization, AMO)
El artículo está dedicado al algoritmo AMO, que modela la migración estacional de los animales en busca de condiciones óptimas para la vida y la reproducción. Las principales características de AMO incluyen el uso de vecindad topológica y un mecanismo de actualización probabilística, lo que lo hace fácil de implementar y flexible para diversas tareas de optimización.
Creación de un modelo de restricción de tendencia de velas (Parte 8): Desarrollo de un asesor experto (II) Creación de un modelo de restricción de tendencia de velas (Parte 8): Desarrollo de un asesor experto (II)
Piense en un asesor experto independiente. Anteriormente, analizamos un Asesor Experto basado en indicadores que también se asoció con un script independiente para dibujar la geometría de riesgo y recompensa. Hoy discutiremos la arquitectura de un Asesor Experto MQL5, que integra todas las características en un solo programa.
Redes neuronales en el trading: Modelo Universal de Generación de Trayectorias (UniTraj) Redes neuronales en el trading: Modelo Universal de Generación de Trayectorias (UniTraj)
La comprensión del comportamiento de los agentes es importante en distintos ámbitos, pero la mayoría de los métodos se centran en una única tarea (comprensión, eliminación del ruido, predicción), lo cual reduce su eficacia en escenarios del mundo real. En este artículo, propongo al lector introducir un modelo capaz de adaptarse a diferentes tareas.
Ejemplo de análisis de redes de causalidad (Causality Network Analysis, CNA) y modelo de autoregresión vectorial para la predicción de eventos de mercado Ejemplo de análisis de redes de causalidad (Causality Network Analysis, CNA) y modelo de autoregresión vectorial para la predicción de eventos de mercado
Este artículo presenta una guía completa para implementar un sistema comercial sofisticado utilizando análisis de red de causalidad (CNA) y autorregresión vectorial (Vector autoregression, VAR) en MQL5. Abarca los fundamentos teóricos de estos métodos, ofrece explicaciones detalladas de las funciones clave del algoritmo de negociación e incluye código de ejemplo para su aplicación.