
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
Introducción
El análisis de redes de causalidad (Causality Network Analysis, CNA) es un método utilizado para comprender y modelar relaciones causales complejas entre variables en un sistema. Cuando se aplica a los mercados financieros, puede ayudar a identificar cómo los distintos acontecimientos y factores del mercado se influyen mutuamente, lo que puede dar lugar a predicciones más precisas.
Descubrimiento causal: El descubrimiento causal es el proceso de inferir relaciones causales a partir de datos observacionales. En el contexto de los mercados financieros, esto significa identificar qué variables (como indicadores económicos, precios de mercado o eventos externos) tienen efectos causales sobre otros. Existen varios algoritmos para el descubrimiento causal, pero uno de los más populares es el algoritmo PC (Peter-Clark).
Este robot de negociación no implementa explícitamente un sistema denominado «Análisis de redes de causalidad para la predicción de eventos de mercado» como componente nombrado. Sin embargo, el robot incorpora elementos de análisis causal y enfoques basados en redes que son conceptualmente similares. Vamos a desglosarlo:
Análisis causal: el bot utiliza un algoritmo de descubrimiento causal, específicamente el algoritmo de inferencia causal rápida (Fast Causal Inference, FCI) (en lugar del algoritmo PC (Peter-Clark)). Esto se implementa en la función FCIAlgorithm().
Análisis de red: el bot utiliza una estructura de red para representar relaciones entre diferentes instrumentos o indicadores financieros. Esto es evidente en la estructura Node y la función SetupNetwork().
Predicción de eventos: aunque no se denomina explícitamente "predicción de eventos", el bot utiliza un modelo de autorregresión vectorial (Vector autoregression, VAR) para realizar predicciones sobre estados futuros del mercado. Esto se implementa en funciones como TrainVARModel() y PredictVARValue().
Análisis de redes de causalidad: una nueva frontera en la predicción de eventos de mercado
En el mundo del trading algorítmico, un nuevo enfoque está ganando terreno entre los analistas cuantitativos y los traders por igual: el análisis de redes de causalidad para la predicción de eventos de mercado. Este sofisticado método combina el poder de la inferencia causal, la teoría de redes y el análisis predictivo para pronosticar eventos importantes del mercado con una precisión sin precedentes.
Imagine el mercado financiero como una red enorme e interconectada. Cada hilo representa una relación entre diferentes variables del mercado: precios de acciones, indicadores económicos, eventos geopolíticos y más. El análisis tradicional a menudo se centra en las correlaciones, pero como cualquier trader experimentado sabe, la correlación no siempre implica causalidad.
Aquí es donde entra en juego el análisis de redes de causalidad. Su objetivo es descubrir las verdaderas relaciones de causa y efecto dentro de esta compleja red. Al hacerlo, proporciona a los comerciantes una comprensión más profunda de la dinámica del mercado, lo que les permite anticipar eventos que podrían ser invisibles para el análisis convencional.
En esencia, el análisis de redes de causalidad implica tres pasos clave:
1. Construyendo la red: Primero, construimos una red donde cada nodo representa una variable de mercado. Estos podrían ser cualquier cosa, desde precios de activos y volúmenes de negociación hasta indicadores económicos y puntuaciones de sentimiento.
2. Descubriendo vínculos causales: A continuación, utilizamos algoritmos avanzados para determinar las relaciones causales entre estos nodos. Aquí es donde ocurre la magia: no solo observamos qué variables se mueven juntas, sino cuáles realmente impulsan cambios en otras.
3. Predicción de eventos: Finalmente, utilizamos esta red causal para pronosticar eventos significativos del mercado. Al comprender los verdaderos impulsores de los movimientos del mercado, podemos anticipar mejor cambios importantes, caídas o repuntes.
Las ventajas para los comerciantes
Para los traders de MQL5, implementar el análisis de red de causalidad puede ser un cambio radical. He aquí por qué:
- Gestión mejorada de riesgos: al identificar las causas fundamentales de la volatilidad del mercado, puede prepararse mejor para posibles caídas.
- Predicciones más precisas: comprender las relaciones causales conduce a pronósticos más confiables que aquellos basados en meras correlaciones.
- Descubrimiento de oportunidades ocultas: La red causal podría revelar conexiones que no son obvias a primera vista, dando lugar a oportunidades comerciales únicas.
- Estrategias adaptativas: a medida que el mercado evoluciona, también lo hace la red causal, lo que permite que sus estrategias se adapten en tiempo real.
Implementación en MQL5
Si bien implementar un sistema completo de análisis de red de causalidad es complejo, MQL5 proporciona una plataforma sólida para este tipo de análisis avanzado. Podrías empezar por:
- Usando la función "iCustom()" para crear indicadores para cada nodo de su red.
- Implementar algoritmos de descubrimiento causal como el algoritmo PC o las pruebas de causalidad de Granger (en este caso utilizamos algoritmos FCI).
- Aprovechar las capacidades de red neuronal de MQL5 para crear modelos predictivos basados en su red causal.
¿Por qué utilizamos FCI en lugar de PC?
FCI (Fast Causal Inference) y PC (Peter-Clark) son algoritmos de descubrimiento causal utilizados en el campo de la inferencia causal. Están diseñados para inferir relaciones causales a partir de datos observacionales. He aquí por qué se podría elegir FCI en lugar de PC:
- Factores de confusión latentes: la principal ventaja de FCI sobre PC es su capacidad para manejar factores de confusión latentes. La FCI puede inferir la presencia de causas comunes ocultas, mientras que la PC supone suficiencia causal (sin factores de confusión latentes).
- Sesgo de selección: FCI también puede explicar el sesgo de selección en los datos, algo que PC no puede.
- Modelo más general: FCI produce un modelo gráfico más general llamado Gráfico Ancestral Parcial (Partial Ancestral Graph, PAG), que puede representar una clase más amplia de estructuras causales que los Gráficos Acíclicos Dirigidos (Directed Acyclic Graphs, DAG) producidos por PC.
- Solidez y completitud: FCI es sólido y completo para la clase de sistemas causalmente insuficientes, lo que significa que puede identificar correctamente todas las relaciones causales posibles dado un tamaño de muestra infinito.
- Robustez: debido a su capacidad para manejar factores de confusión latentes y sesgos de selección, el FCI es generalmente más robusto cuando se trabaja con datos del mundo real donde las variables ocultas son comunes.
Sin embargo, vale la pena señalar que la FCI tiene algunas desventajas en comparación con la PC:
- Complejidad computacional: FCI generalmente es computacionalmente más costoso que PC, especialmente para conjuntos de datos grandes.
- Resultado menos definitivo: los PAG producidos por FCI a menudo contienen más direcciones de borde indeterminadas que los DAG de PC, lo que refleja la incertidumbre adicional de posibles factores de confusión latentes.
- Interpretación: Los PAG pueden ser más difíciles de interpretar que los DAG para los no expertos.
En la práctica, la elección entre FCI y PC a menudo depende de los requisitos específicos de su tarea de inferencia causal, la naturaleza de sus datos y sus suposiciones sobre el sistema causal. Si está seguro de que no hay factores de confusión ocultos ni sesgos de selección, la PC podría ser suficiente y más eficiente. Si sospecha que hay variables latentes o sesgo de selección, FCI sería la opción más adecuada.
Modelo de autorregresión vectorial (VAR)
VAR es un algoritmo de pronóstico multivariado que se utiliza cuando dos o más series de tiempo se influyen entre sí. En este sistema comercial, es probable que se utilice para modelar las relaciones entre diferentes instrumentos financieros o indicadores económicos.
Características principales de VAR:- Captura interdependencias lineales entre múltiples series de tiempo.
- Cada variable es una función lineal de sus rezagos pasados y de los rezagos pasados de las otras variables.
- Permite una dinámica rica en un sistema de series de tiempo múltiples.
- El modelo VAR se entrena utilizando la función "TrainVARModel".
- La función "PredictVARValue" utiliza el modelo entrenado para hacer predicciones.
- El sistema optimiza el modelo VAR seleccionando el rezago óptimo y las variables significativas utilizando la función "OptimizeVARModel".
Representación matemática:
Para un modelo VAR de dos variables con retardo 1:
y1,t = c1 + φ11y1,t-1 + φ12y2,t-1 + ε1,t
y2,t = c2 + φ21y1,t-1 + φ22y2,t-1 + ε2,t
Donde:
- "y1,t" e "y2,t" son los valores de las dos variables en el tiempo t.
- "c1" y "c2" son constantes.
- "φij" son los coeficientes.
- "ε1,t" y "ε2,t" son términos de error.
El sistema estima estos coeficientes para hacer predicciones.
Imagínese que no sólo está prediciendo el precio futuro de un solo activo, sino que simultáneamente está pronosticando múltiples variables financieras interrelacionadas. Ahí es donde brilla VAR. Es como tener una bola de cristal que no sólo te muestra un futuro, sino múltiples futuros interconectados a la vez.
En esencia, VAR es un algoritmo de pronóstico multivariado que se utiliza cuando dos o más series de tiempo se influyen entre sí. En términos más simples, es una forma de capturar las dependencias lineales entre múltiples series de tiempo.
¿Cómo hace magia VAR?
Vamos a desglosarlo:
- Recopilación de datos: Comienza recopilando datos históricos de todas las variables que deseas incluir en tu modelo. Estos podrían ser datos de precios de múltiples pares de divisas, materias primas o incluso indicadores económicos.
- Especificación del modelo: Usted decide cuántos rezagos (períodos de tiempo pasados) incluir. ¡Aquí es donde tu experiencia en trading resulta útil!
- Estimación: El modelo estima cómo cada variable está influenciada por sus propios valores pasados y los valores pasados de otras variables.
- Pronóstico: Una vez estimado, el modelo VAR puede generar pronósticos para todas las variables incluidas simultáneamente.
Implementación de VAR en MQL5
Si bien MQL5 no tiene una función VAR incorporada, puedes implementarla tú mismo. A continuación se muestra un ejemplo simplificado de cómo podría estructurar su código:
// Define your VAR model struct VARModel { int lag; int variables; double[][] coefficients; }; // Estimate VAR model VARModel EstimateVAR(double[][] data, int lag) { // Implement estimation logic here // You might use matrix operations for efficiency } // Make predictions double[] Forecast(VARModel model, double[][] history) { // Implement forecasting logic here } // In your EA or indicator void OnTick() { // Collect your multivariate data double[][] data = CollectData(); // Estimate model VARModel model = EstimateVAR(data, 5); // Using 5 lags // Make forecast double[] forecast = Forecast(model, data); // Use forecast in your trading logic // ... }
La ventaja de VAR en acción
Imagínate que estás negociando con EURUSD. Un enfoque tradicional podría simplemente mirar los precios pasados del EURUSD. Pero con VAR podrías incluir:
- Precios del EURUSD.
- Precios del USDJPY (para capturar la fortaleza general del USD).
- Precios del petróleo (un factor importante para muchas monedas).
- Índice S&P 500 (para medir el sentimiento general del mercado).
- Diferencial de tipos de interés entre EE. UU. y la UE.
Ahora su modelo captura una imagen mucho más rica del panorama forex, lo que potencialmente conduce a decisiones comerciales más informadas.
Desafíos y consideraciones
Como cualquier herramienta poderosa, VAR tiene sus desafíos:
- Requisitos de datos: Los modelos VAR pueden consumir muchos datos. Asegúrese de tener suficientes datos históricos para realizar estimaciones confiables.
- Intensidad computacional: A medida que aumentan las variables y los rezagos, aumentan los requisitos computacionales. Optimice su código para mejorar la eficiencia.
- Estacionariedad: VAR asume series de tiempo estacionarias. Es posible que necesites procesar previamente tus datos (por ejemplo, diferenciarlos) para cumplir con este supuesto.
- Interpretación: Con múltiples variables y rezagos, interpretar los resultados del VAR puede ser complejo. No olvides combinar los conocimientos estadísticos con tus conocimientos de trading.
Análisis de red en el sistema de negociación CNA
El análisis de red implementado en este Asesor Experto (EA) es un componente fundamental de su estrategia de análisis y predicción de mercado. Está diseñado para representar y analizar las relaciones complejas entre diferentes instrumentos financieros o variables del mercado.
Para resumir los puntos clave sobre el análisis de red utilizado en este EA:
- Estructura: La red está compuesta de nodos, cada uno de los cuales representa un instrumento financiero (normalmente un par de divisas).
- Objetivo: Está diseñado para modelar las relaciones e interdependencias entre diferentes instrumentos financieros en el mercado.
- Descubrimiento causal: El EA utiliza el algoritmo de inferencia causal rápida (FCI) para descubrir posibles relaciones causales entre estos instrumentos.
- Representación: Estas relaciones se representan en una matriz de adyacencia, que muestra qué instrumentos están directamente vinculados en términos de influencia causal.
- Análisis: El EA realiza varios análisis en esta red, incluida la identificación de estructuras v (un patrón específico en gráficos causales) y la aplicación de reglas de orientación para refinar aún más la comprensión de las relaciones causales.
- Integración con Predicción: La estructura de la red y las relaciones descubiertas a través de este análisis sirven como entradas para el modelo de autorregresión vectorial (VAR), que se utiliza para realizar predicciones.
- Naturaleza adaptativa: El análisis de red no es estático. Se puede actualizar con el tiempo, lo que permite que el EA se adapte a las condiciones cambiantes del mercado y a las relaciones entre los instrumentos.
La idea clave detrás de este enfoque es que los instrumentos financieros no se mueven de forma aislada. Al modelar y analizar la red de relaciones entre diferentes instrumentos, el EA pretende obtener una comprensión más completa de la dinámica del mercado. En teoría, esto debería conducir a predicciones más precisas y decisiones comerciales mejor informadas.
Sin embargo, es importante señalar que, si bien este enfoque es sofisticado, los mercados financieros son extremadamente complejos y están influenciados por muchos factores. La eficacia de este análisis de red dependerá de qué tan bien capture la dinámica real del mercado y de cómo se integre con otros componentes de la estrategia comercial.
Estructura de la Red
La red está representada por las siguientes estructuras:
struct Node { string name; double value; }; Node g_network[]; int g_node_count = 0;
Cada nodo de la red representa un instrumento financiero o una variable de mercado específica. El campo de nombre identifica el instrumento (por ejemplo, "EURUSD", "GBPUSD") y el campo de valor puede almacenar datos relevantes para ese nodo.
Configuración de la red
La red se inicializa en la función SetupNetwork():
void SetupNetwork() { string symbols[] = {"EURUSD", "GBPUSD", "USDCAD", "USDCHF", "USDJPY", "AUDUSD"}; for(int i = 0; i < ArraySize(symbols); i++) { AddNode(symbols[i]); } } void AddNode(string name) { ArrayResize(g_network, g_node_count + 1); g_network[g_node_count].name = name; g_network[g_node_count].value = 0; // Initialize with default value g_node_count++; }
Esta configuración crea una red donde cada nodo representa un par de divisas diferente.
Propósito de la red
La red cumple varios propósitos clave en el EA:
- Representación de la estructura del mercado: Modela las interconexiones entre diferentes pares de divisas, lo que permite al EA considerar cómo los movimientos en un par podrían afectar a otros.
- Base para el análisis causal: La estructura de la red se utiliza como base para el algoritmo de inferencia causal rápida (FCI), que intenta descubrir relaciones causales entre los nodos.
- Entrada para modelado predictivo: La estructura de la red y las relaciones descubiertas a través del análisis causal sirven como entradas para el modelo de autorregresión vectorial (VAR) utilizado para las predicciones.
Análisis de red en acción
El EA realiza varios tipos de análisis en esta red:
- Descubrimiento causal: La función FCIAlgorithm() aplica el algoritmo de inferencia causal rápida para descubrir posibles relaciones causales entre los nodos.
- Matriz de adyacencia: Las relaciones causales se representan en una matriz de adyacencia, donde cada entrada indica si existe un vínculo causal directo entre dos nodos.
- Orientación de la estructura en V: La función OrientVStructures() identifica y orienta las estructuras v en la red, que son patrones importantes en los gráficos causales.
- Análisis de gráficos: Se analiza la estructura final del gráfico para fundamentar las decisiones comerciales, con el supuesto de que los instrumentos vinculados causalmente pueden proporcionar información predictiva entre sí.
Implicaciones para el comercio
Este enfoque basado en redes permite al EA:
- Considerar dinámicas de mercado complejas que podrían no ser evidentes si se analizan los instrumentos de forma aislada.
- Identificar potencialmente indicadores adelantados entre los instrumentos analizados.
- Realice predicciones más informadas teniendo en cuenta el contexto más amplio del mercado.
- Adaptarse a las condiciones cambiantes del mercado a medida que se reevalúa periódicamente la estructura causal.
Aprovechando este análisis de red, el EA pretende comprender mejor la dinámica del mercado, lo que podría dar lugar a predicciones más precisas y decisiones de negociación mejor informadas.
Código de ejemplo
Este código sigue estos dos diagramas de flujo:
Explicación detallada de las funciones clave del programa de trading MQL5
Este EA comercial es bastante sofisticado y combina varios enfoques avanzados:
- Utiliza un modelo de autorregresión vectorial (VAR) para las predicciones.
- Implementa un algoritmo de descubrimiento causal (Fast Causal Inference, FCI) para comprender las relaciones entre diferentes variables del mercado.
- Emplea una estructura de red para representar y analizar múltiples instrumentos financieros simultáneamente.
- Incorpora varios filtros técnicos como volatilidad, RSI y fuerza de tendencia.
- Utiliza gestión de riesgos adaptativa y dimensionamiento de posiciones.
- Implementa una estrategia de ventana deslizante para actualizar y volver a entrenar continuamente el modelo.
- Incluye técnicas de validación cruzada y optimización de modelos.
La estructura del EA permite un análisis y una toma de decisiones complejos manteniendo la flexibilidad para futuras mejoras o adaptaciones a diferentes condiciones del mercado.
Explicación detallada de las funciones clave del EA de trading
1. OnInit()
int OnInit() { // Step 1: Set up your network structure SetupNetwork(); // Step 2: Run the causal discovery algorithm (e.g., PC or FCI) FCIAlgorithm(); // Step 3: Train the optimized causal model TrainOptimizedVARModel(); ArrayResize(g_previous_predictions, g_node_count); ArrayInitialize(g_previous_predictions, 0); // Initialize with zeros return(INIT_SUCCEEDED); }
Esta es la función de inicialización que se ejecuta cuando el EA se carga o se vuelve a cargar por primera vez en un gráfico.
Responsabilidades clave:
- Configura la estructura de la red llamando a SetupNetwork().
- Ejecuta el algoritmo de descubrimiento causal (FCI) con FCIAlgorithm().
- Entrena el modelo causal optimizado utilizando TrainOptimizedVARModel().
- Inicializa la matriz de predicciones anteriores.
Esta función sienta las bases para todo el análisis y la predicción que realizará el EA.
2. OnTick()
void OnTick() { ENUM_TIMEFRAMES tf = ConvertTimeframe(InputTimeframe); static datetime lastBarTime = 0; datetime currentBarTime = iTime(Symbol(), tf, 0); if(currentBarTime == lastBarTime) return; lastBarTime = currentBarTime; Print("--- New bar on timeframe ", EnumToString(tf), " ---"); UpdateModelSlidingWindow(); for(int i = 0; i < g_node_count; i++) { string symbol = g_network[i].name; Print("Processing symbol: ", symbol); double prediction = PredictVARValue(i); Print("Prediction for ", symbol, ": ", prediction); int signal = GenerateSignal(symbol, prediction); Print("Signal for ", symbol, ": ", signal); // Imprimir más detalles sobre las condiciones Print("RSI: ", CustomRSI(symbol, ConvertTimeframe(InputTimeframe), 14, PRICE_CLOSE, 0)); Print("Trend: ", DetermineTrend(symbol, ConvertTimeframe(InputTimeframe))); Print("Trend Strong: ", IsTrendStrong(symbol, ConvertTimeframe(InputTimeframe))); Print("Volatility OK: ", VolatilityFilter(symbol, ConvertTimeframe(InputTimeframe))); Print("Fast MA > Slow MA: ", (iMA(symbol, PERIOD_CURRENT, 14, 0, MODE_EMA, PRICE_CLOSE) > iMA(symbol, PERIOD_CURRENT, 24, 0, MODE_EMA, PRICE_CLOSE))); if(signal != 0) { Print("Attempting to execute trade for ", symbol); ExecuteTrade(symbol, signal); } else { g_debug_no_signal_count++; Print("No trade signal generated for ", symbol, ". Total no-signal count: ", g_debug_no_signal_count); } ManageOpenPositions(); ManageExistingOrders(symbol); Print("Current open positions for ", symbol, ": ", PositionsTotal()); Print("Current pending orders for ", symbol, ": ", OrdersTotal()); } Print("--- Bar processing complete ---"); Print("Total no-signal count: ", g_debug_no_signal_count); Print("Total failed trade count: ", g_debug_failed_trade_count); }
Esta función se llama en cada tick del mercado.
Tareas principales:
- Convierte el marco de tiempo de entrada.
- Actualiza el modelo usando una ventana deslizante con UpdateModelSlidingWindow()
- Para cada símbolo de la red:
- Predice valores usando PredictVARValue().
- Genera señales comerciales con GenerateSignal().
- Ejecuta operaciones si se generan señales.
- Gestiona puestos vacantes.
- Gestiona pedidos existentes.
Este es el corazón operativo del EA, donde se toman las decisiones comerciales.
3. OnCalculate()
Aunque no se muestra explícitamente en el código proporcionado, esta función normalmente se usaría para calcular valores de indicadores personalizados. En este EA, algunas de estas funciones parecen estar integradas en OnTick().
4. CheckMarketConditions()
int GenerateSignal(string symbol, double prediction) { int node_index = FindNodeIndex(symbol); if(node_index == -1) return 0; static bool first_prediction = true; if(first_prediction) { first_prediction = false; return 0; // No generar señal en la primera predicción } double current_price = SymbolInfoDouble(symbol, SYMBOL_BID); // Calculate predicted change as a percentage double predicted_change = (prediction - current_price) / current_price * 100; bool volatility_ok = VolatilityFilter(symbol, ConvertTimeframe(InputTimeframe)); double rsi = CustomRSI(symbol, ConvertTimeframe(InputTimeframe), 14, PRICE_CLOSE, 0); bool trend_strong = IsTrendStrong(symbol, ConvertTimeframe(InputTimeframe)); int trend = DetermineTrend(symbol, ConvertTimeframe(InputTimeframe)); double fastMA = iMA(symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, PRICE_CLOSE); double slowMA = iMA(symbol, PERIOD_CURRENT, 24, 0, MODE_EMA, PRICE_CLOSE); Print("Debugging GenerateSignal for ", symbol); Print("Current price: ", current_price); Print("Prediction diff: ", prediction); Print("predicted_change: ", predicted_change); Print("RSI: ", rsi); Print("Trend: ", trend); Print("Trend Strong: ", trend_strong); Print("Volatility OK: ", volatility_ok); Print("Fast MA: ", fastMA, ", Slow MA: ", slowMA); bool buy_condition = prediction > 0.00001 && rsi < 30 && trend_strong && volatility_ok && fastMA > slowMA; bool sell_condition = prediction < -0.00001 && rsi > 70 && trend_strong && volatility_ok && fastMA < slowMA; Print("Buy condition met: ", buy_condition); Print("Sell condition met: ", sell_condition); // Buy conditions if(buy_condition) { Print("Buy signal generated for ", symbol); int signal = 1; return signal; // Buy signal } // Sell conditions else if(sell_condition) { Print("Sell signal generated for ", symbol); int signal = -1; return signal; // Sell signal } else { Print("No signal generated for ", symbol); int signal = 0; return signal; // No signal } }
Esta función no está definida explícitamente en el código, pero su funcionalidad se distribuye en varias partes, principalmente dentro de GenerateSignal():
- Comprueba la volatilidad con VolatilityFilter().
- Comprueba el RSI.
- Verifica la fuerza de la tendencia con IsTrendStrong().
- Determina la dirección de la tendencia con DetermineTrend().
- Compara promedios móviles rápidos y lentos.
Estas comprobaciones determinan si las condiciones del mercado son favorables para el comercio.
5. ExecuteTrade()
void ExecuteTrade(string symbol, int signal) { if(!IsMarketOpen(symbol) || !IsTradingAllowed()) { Print("Market is closed or trading is not allowed for ", symbol); return; } double price = (signal == 1) ? SymbolInfoDouble(symbol, SYMBOL_ASK) : SymbolInfoDouble(symbol, SYMBOL_BID); double stopLoss, takeProfit; CalculateAdaptiveLevels(symbol, signal, stopLoss, takeProfit); double lotSize = CalculateDynamicLotSize(symbol, stopLoss); if(lotSize <= 0) { Print("Invalid lot size for symbol: ", symbol); return; } trade.SetExpertMagicNumber(123456); trade.SetTypeFilling(ORDER_FILLING_FOK); bool result = false; int attempts = 3; for(int i = 0; i < attempts; i++) { if(signal == 1) { result = trade.Buy(lotSize, symbol, price, stopLoss, takeProfit, "CNA Buy"); Print("Attempting Buy order: Symbol=", symbol, ", Lot Size=", lotSize, ", Price=", price, ", SL=", stopLoss, ", TP=", takeProfit); } else if(signal == -1) { result = trade.Sell(lotSize, symbol, price, stopLoss, takeProfit, "CNA Sell"); Print("Attempting Sell order: Symbol=", symbol, ", Lot Size=", lotSize, ", Price=", price, ", SL=", stopLoss, ", TP=", takeProfit); } if(result) { Print("Order executed successfully for ", symbol, ", Type: ", (signal == 1 ? "Buy" : "Sell"), ", Lot size: ", lotSize); break; } else { int lastError = GetLastError(); Print("Attempt ", i+1, " failed for ", symbol, ". Error: ", lastError, " - ", GetErrorDescription(lastError)); if(lastError == TRADE_RETCODE_REQUOTE || lastError == TRADE_RETCODE_PRICE_CHANGED || lastError == TRADE_RETCODE_INVALID_PRICE) { price = (signal == 1) ? SymbolInfoDouble(symbol, SYMBOL_ASK) : SymbolInfoDouble(symbol, SYMBOL_BID); CalculateAdaptiveLevels(symbol, signal, stopLoss, takeProfit); } else break; } } if(!result) { Print("All attempts failed for ", symbol, ". Last error: ", GetLastError(), " - ", GetErrorDescription(GetLastError())); } }
Esta función maneja la ejecución real de las operaciones.
Aspectos clave:
- Verifica si el mercado está abierto y se permite operar.
- Calcula niveles de Stop Loss y Take Profit adaptativos.
- Determina el tamaño del lote en función de la gestión de riesgos.
- Intentos de ejecutar la orden, con reintentos en caso de fallo.
- Maneja errores y proporciona retroalimentación detallada.
6. OnDeinit()
void OnDeinit(const int reason) { if(atr_handle != INVALID_HANDLE) IndicatorRelease(atr_handle); if(rsi_handle != INVALID_HANDLE) IndicatorRelease(rsi_handle); if(momentum_handle != INVALID_HANDLE) IndicatorRelease(momentum_handle); GenerateFinalSummary(); }
Esta función se llama cuando se elimina el EA del gráfico o cuando se cierra la terminal.
Responsabilidades principales:
- Libera los manejadores de indicadores.
- Genera un resumen final del rendimiento del EA llamando a GenerateFinalSummary().
Funciones importantes adicionales
UpdateModelSlidingWindow()
void UpdateModelSlidingWindow() { static int bars_since_update = 0; ENUM_TIMEFRAMES tf = ConvertTimeframe(InputTimeframe); // Check if it's time to update if(bars_since_update >= g_update_frequency) { // Collect new data double training_data[]; CollectTrainingData(training_data, g_window_size, tf); // Retrain model TrainModel(training_data); // Validate model double validation_score = ValidateModel(); Print("Model updated. Validation score: ", validation_score); bars_since_update = 0; } else { bars_since_update++; } }
Actualiza el modelo VAR utilizando una ventana deslizante de datos, lo que permite que el modelo se adapte a las condiciones cambiantes del mercado.
TrainOptimizedVARModel()
void TrainOptimizedVARModel() { OptimizationResult opt_result = OptimizeVARModel(); Print("Lag óptimo encontrado: ", opt_result.optimal_lag); Print("AIC: ", opt_result.aic); Print("Variables seleccionadas: ", ArraySize(opt_result.selected_variables)); // Usar opt_result.optimal_lag y opt_result.selected_variables para entrenar el modelo final TrainVARModel(opt_result.optimal_lag, opt_result.selected_variables); }Optimiza y entrena el modelo VAR, seleccionando el número óptimo de retardos y variables significativas.
PredictVARValue()
double PredictVARValue(int node_index) { if(node_index < 0 || node_index >= g_node_count) { Print("Error: Invalid node index: ", node_index); return 0; } double prediction = 0; int lag = g_var_params[node_index].lag; Print("Predicting for node: ", g_network[node_index].name, ", Lag: ", lag); // Retrieve the previous prediction double previous_prediction = g_previous_predictions[node_index]; // Verify if there are enough coefficients int expected_coefficients = g_node_count * lag + 1; // +1 for the intercept if(ArraySize(g_var_params[node_index].coefficients) < expected_coefficients) { Print("Error: Not enough coefficients for node ", node_index, ". Expected: ", expected_coefficients, ", Actual: ", ArraySize(g_var_params[node_index].coefficients)); return 0; } prediction = g_var_params[node_index].coefficients[0]; // Intercept Print("Intercept: ", prediction); double sum_predictions = 0; double sum_weights = 0; double current_price = iClose(g_network[node_index].name, PERIOD_CURRENT, 0); for(int l = 1; l <= lag; l++) { double time_weight = 1.0 - (double)(l-1) / lag; // Time-based weighting sum_weights += time_weight; double lag_prediction = 0; for(int j = 0; j < g_node_count; j++) { int coeff_index = (l - 1) * g_node_count + j + 1; if(coeff_index >= ArraySize(g_var_params[node_index].coefficients)) { Print("Warning: Coefficient index out of range. Skipping. Index: ", coeff_index, ", Array size: ", ArraySize(g_var_params[node_index].coefficients)); continue; } double coeff = g_var_params[node_index].coefficients[coeff_index]; double raw_value = iClose(g_network[j].name, PERIOD_CURRENT, l); if(raw_value == 0 || !MathIsValidNumber(raw_value)) { Print("Warning: Invalid raw value for ", g_network[j].name, " at lag ", l); continue; } // Normalize the value as a percentage change double normalized_value = (raw_value - current_price) / current_price; double partial_prediction = coeff * normalized_value; lag_prediction += partial_prediction; Print("Lag ", l, ", Node ", j, ": Coeff = ", coeff, ", Raw Value = ", raw_value, ", Normalized Value = ", normalized_value, ", Partial prediction: ", partial_prediction); } sum_predictions += lag_prediction * time_weight; Print("Lag ", l, " prediction: ", lag_prediction, ", Weighted: ", lag_prediction * time_weight); } Print("Sum of weights: ", sum_weights); // Calculate the final prediction if(sum_weights > 1e-10) { prediction = sum_predictions / sum_weights; } else { Print("Warning: sum_weights is too small (", sum_weights, "). Using raw sum of predictions."); prediction = sum_predictions; } // Calculate the difference between the current prediction and the previous prediction double prediction_change = prediction - previous_prediction; Print("Previous prediction: ", previous_prediction); Print("Current prediction: ", prediction); Print("Prediction change: ", prediction_change); // Convert the prediction to a percentage change double predicted_change_percent = (prediction - current_price) / current_price * 100; Print("Final prediction (as percentage change): ", predicted_change_percent, "%"); // Update the current prediction for the next iteration g_previous_predictions[node_index] = prediction; // Return the difference in basis points return prediction_change * 10000; // Multiply by 10000 to convert to basis points }
Realiza predicciones utilizando el modelo VAR entrenado, considerando valores históricos y coeficientes del modelo.
ManageOpenPositions() y ManageExistingOrders()
void ManageOpenPositions() { for(int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(PositionSelectByTicket(ticket)) { string symbol = PositionGetString(POSITION_SYMBOL); double openPrice = PositionGetDouble(POSITION_PRICE_OPEN); double currentPrice = PositionGetDouble(POSITION_PRICE_CURRENT); double stopLoss = PositionGetDouble(POSITION_SL); ENUM_POSITION_TYPE positionType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // Implement trailing stop if(positionType == POSITION_TYPE_BUY && currentPrice - openPrice > 2 * CustomATR(symbol, PERIOD_CURRENT, 14, 0)) { double newStopLoss = NormalizeDouble(currentPrice - CustomATR(symbol, PERIOD_CURRENT, 14, 0), SymbolInfoInteger(symbol, SYMBOL_DIGITS)); if(newStopLoss > stopLoss) { trade.PositionModify(ticket, newStopLoss, 0); } } else if(positionType == POSITION_TYPE_SELL && openPrice - currentPrice > 2 * CustomATR(symbol, PERIOD_CURRENT, 14, 0)) { double newStopLoss = NormalizeDouble(currentPrice + CustomATR(symbol, PERIOD_CURRENT, 14, 0), SymbolInfoInteger(symbol, SYMBOL_DIGITS)); if(newStopLoss < stopLoss || stopLoss == 0) { trade.PositionModify(ticket, newStopLoss, 0); } } } } }
void ManageExistingOrders(string symbol) { for(int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(PositionSelectByTicket(ticket) && PositionGetString(POSITION_SYMBOL) == symbol) { double stopLoss = PositionGetDouble(POSITION_SL); double takeProfit = PositionGetDouble(POSITION_TP); double openPrice = PositionGetDouble(POSITION_PRICE_OPEN); double currentPrice = PositionGetDouble(POSITION_PRICE_CURRENT); ENUM_POSITION_TYPE positionType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); double atr = CustomATR(symbol, PERIOD_CURRENT, 14, 0); double newStopLoss, newTakeProfit; if(positionType == POSITION_TYPE_BUY) { newStopLoss = NormalizeDouble(currentPrice - 2 * atr, SymbolInfoInteger(symbol, SYMBOL_DIGITS)); newTakeProfit = NormalizeDouble(currentPrice + 3 * atr, SymbolInfoInteger(symbol, SYMBOL_DIGITS)); if(newStopLoss > stopLoss && currentPrice - openPrice > atr) { trade.PositionModify(ticket, newStopLoss, newTakeProfit); } } else if(positionType == POSITION_TYPE_SELL) { newStopLoss = NormalizeDouble(currentPrice + 2 * atr, SymbolInfoInteger(symbol, SYMBOL_DIGITS)); newTakeProfit = NormalizeDouble(currentPrice - 3 * atr, SymbolInfoInteger(symbol, SYMBOL_DIGITS)); if(newStopLoss < stopLoss && openPrice - currentPrice > atr) { trade.PositionModify(ticket, newStopLoss, newTakeProfit); } } // Implementar cierre parcial double profit = PositionGetDouble(POSITION_PROFIT); double volume = PositionGetDouble(POSITION_VOLUME); if(profit > 0 && MathAbs(currentPrice - openPrice) > 2 * atr) { double closeVolume = volume * 0.5; if(IsValidVolume(symbol, closeVolume)) { ClosePosition(ticket, closeVolume); } } } } }
Gestionar posiciones abiertas y órdenes existentes, implementando estrategias como Trailing Stops y cierres parciales.
Este EA combina el análisis técnico tradicional con modelos estadísticos avanzados (VAR) y técnicas de aprendizaje automático (descubrimiento causal) para tomar decisiones comerciales. La estructura modular permite una fácil modificación y mejora de componentes individuales.
Resultados
Estos son los resultados para algunos símbolos, las configuraciones y entradas seguirán siendo las mismas para todos los símbolos estudiados:
¿Cómo obtener mejores resultados?
Se pueden lograr mejores resultados si en el nodo de símbolos se agregan más y también se utilizan símbolos cointegrados y correlacionados. Para saber cuáles son esos símbolos, puedes utilizar mi script de Python de este artículo: Aplicación de la teoría de juegos de Nash con filtrado HMM en el trading.
Además, se pueden lograr mejores resultados si se añade a la estrategia un aprendizaje profundo. Hay algunos ejemplos de ello en artículos como éste:Análisis de sentimientos y aprendizaje profundo para operar con EA y backtesting con Python
Además, no se han realizado optimizaciones para los filtros, y también podría intentar agregar más filtros.
Ejemplo de cómo cambia el gráfico al agregar más símbolos a la red:
void SetupNetwork() { string symbols[] = {"EURUSD", "GBPUSD", "USDCAD", "USDCHF", "USDJPY", "AUDUSD", "XAUUSD", "SP500m", "ND100m"}; for(int i = 0; i < ArraySize(symbols); i++) { AddNode(symbols[i]); } }
Sólo añadiendo más símbolos a la red, conseguimos mejorar en:
- Actividad comercial (más operaciones totales).
- Tasa de éxito en operaciones cortas.
- Porcentaje de operaciones rentables.
- Tamaño de la operación comercial más rentable.
- Beneficio promedio por operación ganadora.
- Menor porcentaje de operaciones perdedoras.
- Pérdida promedio menor por operación perdedora.
Estas mejoras sugieren una mejor gestión general del comercio y del control del riesgo, a pesar de que algunas métricas de rendimiento clave (como el factor de beneficio y el factor de recuperación) son más bajas.
Conclusión
Este artículo analiza un sistema de trading avanzado que integra el análisis de redes de causalidad (Causality Network Analysis, CNA) y la regresión automática vectorial (Vector Autoregression, VAR) para predecir eventos del mercado y tomar decisiones comerciales. El sistema utiliza sofisticadas técnicas estadísticas y de aprendizaje automático para modelar las relaciones entre instrumentos financieros. Si bien es prometedor, enfatiza la importancia de combinar este enfoque con una sólida gestión de riesgos y un profundo conocimiento de los mercados.
Para los traders que buscan mejores resultados, el artículo sugiere ampliar la red con más símbolos correlacionados, incorporar aprendizaje profundo y optimizar los métodos de filtrado. El aprendizaje continuo y la adaptación son cruciales para el éxito a largo plazo en el trading.
¡Felices operaciones y que sus algoritmos siempre estén un paso por delante del mercado!
Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/15665
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.





- 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
Si ese EA te da problemas, puedes probar con este (es una versión más antigua y los gráficos no se igualan, pero lo acabo de probar y funciona).
Por favor, avisadme cuando un EA no funcione correctamente, porque de vez en cuando formateo el ordenador y pierdo todas las demás versiones.
Éste también funciona
Lo siento, este debería funcionar