
Creación de un modelo de restricción de tendencia de velas (Parte 9): Asesor Experto de múltiples estrategias (III)
Introducción
En el trading algorítmico, identificar puntos de entrada óptimos dentro de una tendencia predominante sigue siendo un desafío importante, ya que muchas estrategias tienen dificultades para capturar el momento adecuado o generan señales falsas frecuentes, lo que resulta en un rendimiento subóptimo. Este problema es particularmente pronunciado en las tendencias diarias, donde pequeñas fluctuaciones pueden alterar la precisión de la ejecución.
La divergencia ofrece una solución sólida al actuar como un filtro para identificar posibles reversiones o continuaciones a través de discrepancias entre los movimientos de precios y los indicadores de impulso. Al integrar la detección de divergencias en el asesor experto Trend Constraint, los operadores pueden mejorar significativamente su precisión a la hora de localizar niveles de entrada.
Este enfoque mejora la precisión comercial y también garantiza un comercio consistente y eficiente cuando se combina con las capacidades avanzadas de MQL5. En este artículo, exploraremos los fundamentos de la divergencia, los pasos para integrarla en los Asesores Expertos MQL5, las mejoras del asesor experto Trend Constraint con nuevas condiciones de ejecución comercial y conocimientos adquiridos a partir de pruebas retrospectivas para demostrar su aplicación práctica.
Contenido principal:
- Los fundamentos de la divergencia
- Pasos para integrar la detección de divergencias
- Mejoras en el asesor experto Trend Constraint: Implementación de nuevas condiciones de ejecución de operaciones para aprovechar la divergencia.
- Resultados de las pruebas retrospectivas y aplicación práctica
- Conclusión
Los fundamentos de la divergencia
La divergencia es un concepto clave en el análisis técnico, que proporciona a los operadores información sobre posibles reversiones o continuaciones de precios al comparar los movimientos de precios con la dirección de un indicador.
Importancia de la divergencia:
La divergencia ocurre cuando el precio de un activo se mueve en oposición a un indicador técnico, lo que a menudo señala un debilitamiento de la tendencia o una reversión inminente. Este concepto es particularmente útil para identificar cuándo una tendencia podría estar a punto de sufrir una corrección o un cambio total.
Tipos de divergencia:
- La divergencia alcista se observa cuando el precio del activo alcanza mínimos más bajos, pero el indicador, como el RSI, comienza a mostrar mínimos más altos, lo que sugiere que el impulso bajista está disminuyendo. Esto podría significar que la presión de venta está disminuyendo, lo que podría generar un movimiento de precios al alza.
- La divergencia bajista se observa cuando el precio alcanza máximos más altos, pero el indicador muestra máximos más bajos, lo que indica que el impulso ascendente está disminuyendo. Esto podría presagiar una caída en los precios.
Verificación de antecedentes:
La divergencia es un concepto fundamental en el análisis técnico que influye en el comportamiento del mercado y en las estrategias de los operadores. Bart y Masse (1981), en «Divergence of Opinion and Risk», hacen hincapié en cómo las discrepancias en la opinión del mercado pueden aumentar el riesgo y la volatilidad de los precios, lo que refleja el papel de la divergencia en el análisis técnico.
Las pruebas empíricas de Tilehnouei y Shivaraj (2013) sugieren que herramientas como el MACD pueden superar al RSI en determinados contextos, ya que ofrecen información valiosa sobre el impulso del mercado a través de señales de divergencia. A partir de esta investigación, podemos decir que la integración de la divergencia con otros indicadores, como la interacción entre RSI, MACD y la acción del precio, refuerza su utilidad en un enfoque comercial integral, como lo respaldan varias fuentes de la industria.
En la siguiente sección, daremos un paso práctico para implementar la idea de divergencia en el desarrollo de nuestro EA.
Pasos para integrar la detección de divergencias
Para incorporar la detección de divergencias en un Asesor Experto (EA) de MQL5, comenzamos calculando los valores del Índice de Fuerza Relativa (Relative Strength Index, RSI) utilizando funciones como iRSI() y comparándolos con la acción del precio. Los precios extremos significativos se identifican utilizando iHigh() e iLow() durante un período determinado. Para este proyecto, clasificaré la divergencia en dos tipos: regular (reversión) y oculta.
Divergencia regular:
Las señales de divergencia regulares indican posibles cambios de tendencia: una configuración alcista ocurre cuando el precio alcanza un mínimo más bajo mientras que el indicador forma un mínimo más alto, y una configuración bajista surge cuando el precio alcanza un máximo más alto, pero el indicador muestra un máximo más bajo.
// Regular divergence conditions in code bool CheckRegularBearishDivergence(int period = 14, ENUM_TIMEFRAMES timeframe = PERIOD_H1) { double priceHigh1 = iHigh(_Symbol, timeframe, 2); double priceHigh2 = iHigh(_Symbol, timeframe, 8); double rsiHigh1 = iRSI(_Symbol, timeframe, period, PRICE_CLOSE, 2); double rsiHigh2 = iRSI(_Symbol, timeframe, period, PRICE_CLOSE, 8); if(priceHigh1 > priceHigh2 && rsiHigh1 < rsiHigh2) return true; return false; }
Para ilustrar estas divergencias regulares, aquí hay dos imágenes que representan la divergencia alcista y la divergencia bajista, respectivamente:
Índice Boom 300 H4-Divergencia alcista: (un precio mínimo más bajo B frente a un valor RSI mínimo más alto en D)
Índice Boom 300 H4: Divergencia bajista (un precio máximo más alto B frente a un valor RSI máximo más bajo en D).
Divergencia oculta:
La divergencia oculta, por otro lado, sugiere una continuación de la tendencia. Una divergencia alcista oculta ocurre en una tendencia alcista cuando el precio forma un mínimo más alto mientras el indicador forma un mínimo más bajo, mientras que una divergencia bajista oculta aparece en una tendencia bajista cuando el precio forma un máximo más bajo y el indicador forma un máximo más alto.
//RSI and Price Levels declaration and hidden divergence condition bool CheckHiddenBullishDivergence(int period = 14, ENUM_TIMEFRAMES timeframe = PERIOD_H1) { double priceLow1 = iLow(_Symbol, timeframe, 2); double priceLow2 = iLow(_Symbol, timeframe, 8); double rsiLow1 = iRSI(_Symbol, timeframe, period, PRICE_CLOSE, 2); double rsiLow2 = iRSI(_Symbol, timeframe, period, PRICE_CLOSE, 8); if(priceLow1 > priceLow2 && rsiLow1 < rsiLow2) return true; return false; }
A continuación se muestran imágenes que ilustran la divergencia oculta alcista y la divergencia oculta bajista. Asegúrese de compararlos con las descripciones proporcionadas anteriormente y practique la identificación de patrones similares en sus propios gráficos.
Índice Boom 300 H4: Divergencia oculta alcista
Índice Boom 300 H4: Divergencia bajista oculta
La integración de estos tipos de divergencias en el EA requiere condiciones de codificación para detectarlas en cada tick o cierre de barra, utilizando herramientas como iRSI() o iMACD() para los cálculos de los indicadores. Una vez detectadas, las señales de divergencia se alinean con las restricciones de tendencia, identificadas utilizando el sentimiento diario del mercado.
Mejoras en el asesor experto Trend Constraint: Implementación de nuevas condiciones de ejecución de operaciones para aprovechar la divergencia.
Sobre la sección anterior, cuando finalmente se detecta la divergencia, necesitaremos un indicador adicional para confirmar y señalar el proceso de ejecución de la orden. Hay muchas opciones para esto, pero consideraremos implementar MACD y RSI para eso. A continuación se muestra una lista de otros indicadores de confirmación opcionales:
- Bandas de Bollinger
- Oscilador estocástico
- Volumen de equilibrio (On Balance Volume, OBV) y precio promedio ponderado por volumen (Volume Weighted Average Price , VWAP)
- Índice dinámico promedio (Average Dynamic Index, ADX)
Media móvil de convergencia/divergencia (Moving Average Convergence Divergence, MACD):
Por qué usarlo: MACD puede confirmar cambios de impulso. Si se detecta una divergencia con el RSI, el MACD puede proporcionar una confirmación secundaria de la fortaleza o debilitamiento de la tendencia.
Cómo funciona:
El EA buscará cruces de líneas MACD o cambios en el histograma que se alineen con los hallazgos de divergencia. Por ejemplo, una divergencia bajista podría confirmarse si la línea MACD cruza por debajo de la línea de señal o el histograma comienza a disminuir.
Aspectos destacados del indicador MACD:
Para tener una vista previa del indicador incorporado como el MACD, podemos acceder dentro de la carpeta de "Examples" dentro de la carpeta de Indicadores en el software MetaEditor 5, consulte la imagen explicativa a continuación.
MetaEditor 5: Cómo acceder al archivo fuente del MACD
El motivo por el que accedemos al código es para que podamos entender fácilmente cómo están diseñados los buffers para que podamos adaptarlos fácilmente en nuestro Asesor Experto. A continuación se muestra un fragmento de código para las declaraciones almacenadas en búfer dentro del indicador que nos interesa.
//--- indicator buffers double ExtMacdBuffer[]; double ExtSignalBuffer[]; double ExtFastMaBuffer[]; double ExtSlowMaBuffer[]; int ExtFastMaHandle; int ExtSlowMaHandle;
Ahora, con nuestros buffers en mente, revisemos el proceso de desarrollo paso a paso que se describe a continuación.
Desarrollo de la estrategia de divergencia:
Paso 1: Declaraciones y parámetros de entrada
Comenzamos declarando los parámetros de entrada para la estrategia de divergencia, los buffers MACD e inicializando la clase CTrade.
#include <Trade\Trade.mqh> CTrade trade; input bool UseDivergenceStrategy = true; // Enable/Disable Divergence Strategy input int DivergenceMACDPeriod = 12; // MACD Fast EMA period input int DivergenceSignalPeriod = 9; // MACD Signal period input double DivergenceLots = 1.0; // Lot size for Divergence trades input double DivergenceStopLoss = 300; // Stop Loss in points for Divergence input double DivergenceTakeProfit = 500; // Take Profit in points for Divergence input int DivergenceMagicNumber = 87654321; // Magic number for Divergence Strategy input int DivergenceLookBack = 8; // Number of periods to look back for divergence double ExtMacdBuffer[]; // MACD values double ExtSignalBuffer[]; // Signal line values int macd_handle; // MACD indicator handle
Paso 2: Inicializar el indicador MACD
Inicializa el controlador MACD y asigna memoria intermedia durante OnInit().
int OnInit() { macd_handle = iMACD(_Symbol, PERIOD_CURRENT, DivergenceMACDPeriod, 26, DivergenceSignalPeriod, PRICE_CLOSE); if (macd_handle == INVALID_HANDLE) { Print("Failed to initialize MACD. Error: ", GetLastError()); return INIT_FAILED; } ArrayResize(ExtMacdBuffer, DivergenceLookBack); ArrayResize(ExtSignalBuffer, DivergenceLookBack); return INIT_SUCCEEDED; }
Paso 3: Detección de divergencias
La divergencia ocurre cuando la acción del precio de un activo no coincide con un indicador, en este caso, el MACD. Esta estrategia detecta cuatro tipos de divergencias: alcista regular, alcista oculta, bajista regular y bajista oculta. Cada tipo tiene condiciones específicas, comparando los máximos o mínimos de precios con los máximos o mínimos del MACD correspondientes para determinar la presencia de divergencia.
bool CheckBullishRegularDivergence() { double priceLow1 = iLow(_Symbol, PERIOD_CURRENT, 2); double priceLow2 = iLow(_Symbol, PERIOD_CURRENT, DivergenceLookBack); double macdLow1 = ExtMacdBuffer[2]; double macdLow2 = ExtMacdBuffer[DivergenceLookBack - 1]; return (priceLow1 < priceLow2 && macdLow1 > macdLow2); } bool CheckBearishHiddenDivergence() { double priceHigh1 = iHigh(_Symbol, PERIOD_CURRENT, 2); double priceHigh2 = iHigh(_Symbol, PERIOD_CURRENT, DivergenceLookBack); double macdHigh1 = ExtMacdBuffer[2]; double macdHigh2 = ExtMacdBuffer[DivergenceLookBack - 1]; return (priceHigh1 < priceHigh2 && macdHigh1 > macdHigh2); }
Paso 4: Lógica de negociación
En primer lugar, la estrategia garantiza que el trading de divergencia esté habilitado y que no haya más de 3 posiciones abiertas basadas en divergencia. Recupera datos del buffer MACD, vuelve a intentarlo en caso de error y solo ejecuta operaciones en barras completas. Además, alinea las operaciones con las tendencias de velas diarias, lo que garantiza que solo se compren en días alcistas y se vendan en días bajistas.
void CheckDivergenceTrading() { if (!UseDivergenceStrategy) return; int openDivergencePositions = CountOrdersByMagic(DivergenceMagicNumber); if (openDivergencePositions == 0 || openDivergencePositions < 3) { if (CopyBuffer(macd_handle, 0, 0, DivergenceLookBack, ExtMacdBuffer) > 0 && CopyBuffer(macd_handle, 1, 0, DivergenceLookBack, ExtSignalBuffer) > 0) { double dailyClose = iClose(_Symbol, PERIOD_D1, 0); double dailyOpen = iOpen(_Symbol, PERIOD_D1, 0); bool isDailyBullish = dailyClose > dailyOpen; bool isDailyBearish = dailyClose < dailyOpen; if (isDailyBullish && (CheckBullishRegularDivergence() && ExtMacdBuffer[0] > ExtSignalBuffer[0]) || CheckBullishHiddenDivergence()) { ExecuteDivergenceOrder(true); } if (isDailyBearish && (CheckBearishRegularDivergence() && ExtMacdBuffer[0] < ExtSignalBuffer[0]) || CheckBearishHiddenDivergence()) { ExecuteDivergenceOrder(false); } } } }
Paso 5: Ejecución de la orden
Una vez que se detecta una divergencia, la estrategia ejecuta operaciones con parámetros predefinidos como tamaño de lote, stop loss y take profit. La función ExecuteDivergenceOrder calcula los niveles apropiados según la dirección del comercio y utiliza el objeto comercial para colocar órdenes de compra o venta.
void ExecuteDivergenceOrder(bool isBuy) { trade.SetExpertMagicNumber(DivergenceMagicNumber); double currentPrice = isBuy ? SymbolInfoDouble(_Symbol, SYMBOL_ASK) : SymbolInfoDouble(_Symbol, SYMBOL_BID); double stopLossPrice = isBuy ? currentPrice - DivergenceStopLoss * _Point : currentPrice + DivergenceStopLoss * _Point; double takeProfitPrice = isBuy ? currentPrice + DivergenceTakeProfit * _Point : currentPrice - DivergenceTakeProfit * _Point; if (isBuy) { if (trade.Buy(DivergenceLots, _Symbol, 0, stopLossPrice, takeProfitPrice, "Divergence Buy")) Print("Divergence Buy order placed."); } else { if (trade.Sell(DivergenceLots, _Symbol, 0, stopLossPrice, takeProfitPrice, "Divergence Sell")) Print("Divergence Sell order placed."); } }
Paso 6: Gestión de pedidos
Para evitar el exceso de operaciones, la estrategia utiliza la función de utilidad CountOrdersByMagic para contar todas las posiciones abiertas con el número mágico especificado. Esto garantiza el cumplimiento del límite de posición máxima establecido para operaciones basadas en divergencia.
int CountOrdersByMagic(int magic) { int count = 0; for (int i = 0; i < PositionsTotal(); i++) { ulong ticket = PositionGetTicket(i); if (PositionSelectByTicket(ticket)) { if (PositionGetInteger(POSITION_MAGIC) == magic) { count++; } } } return count; }
Número mágico:
Otro aspecto importante es darle identidad a nuestras posiciones. En este caso, asignamos un número mágico único a las operaciones regidas por la estrategia de divergencia.
// Ensure the magic number is set for the trade trade.SetExpertMagicNumber(DivergenceMagicNumber);
Paso 7: Protección de beneficios
Introdujimos una función de protección de ganancias que incorpora una lógica de bloqueo de ganancias para nuestro asesor experto en restricciones de tendencias para asegurar dinámicamente las ganancias de las operaciones abiertas. La función LockProfits analiza todas las posiciones activas e identifica aquellas con ganancias superiores a un umbral de 100 puntos. Para cada posición que cumple los requisitos, calcula un nuevo nivel de stop-loss basado en el parámetro profitLockerPoints (por ejemplo, 20 puntos desde el precio de entrada).
Este ajuste garantiza que el stop-loss se acerque al precio actual, fijando efectivamente las ganancias. Para las posiciones de compra, el stop-loss se desplaza por encima del precio de entrada, mientras que en las posiciones de venta, se desplaza por debajo. La función actualiza el stop-loss solo si el nuevo nivel ofrece mejor protección, lo que garantiza una gestión óptima del riesgo. Las modificaciones exitosas se registran con un mensaje para su seguimiento. Esta característica ayuda a asegurar las ganancias y al mismo tiempo permite que las operaciones tengan potencial para un mayor crecimiento.
Aquí está la función de bloqueo de ganancias:
//+------------------------------------------------------------------+ //| Profit Locking Logic | //+------------------------------------------------------------------+ void LockProfits() { for (int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if (PositionSelectByTicket(ticket)) { double entryPrice = PositionGetDouble(POSITION_PRICE_OPEN); double currentProfit = PositionGetDouble(POSITION_PROFIT); double currentPrice = PositionGetDouble(POSITION_PRICE_CURRENT); // Convert profit to points double profitPoints = MathAbs(currentProfit / _Point); // Check if profit has exceeded 100 points if (profitPoints >= 100) { double newStopLoss; if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { newStopLoss = entryPrice + profitLockerPoints * _Point; // 20 points above entry for buys } else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) { newStopLoss = entryPrice - profitLockerPoints * _Point; // 20 points below entry for sells } else { continue; // Skip if not a buy or sell position } // Modify stop loss only if the new stop loss is more protective double currentStopLoss = PositionGetDouble(POSITION_SL); if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { if (currentStopLoss < newStopLoss || currentStopLoss == 0) { if (trade.PositionModify(ticket, newStopLoss, PositionGetDouble(POSITION_TP))) { Print("Profit locking for buy position: Stop Loss moved to ", newStopLoss); } } } else // POSITION_TYPE_SELL { if (currentStopLoss > newStopLoss || currentStopLoss == 0) { if (trade.PositionModify(ticket, newStopLoss, PositionGetDouble(POSITION_TP))) { Print("Profit locking for sell position: Stop Loss moved to ", newStopLoss); } } } } } } }
Paso 8: Integrar en OnTick()
Llame a la lógica comercial de divergencia dentro del bucle principal del EA.
void OnTick() { CheckDivergenceTrading(); }
Paso 9: Apagar
void OnDeinit(const int reason) { IndicatorRelease(macd_handle); }
Integración de la estrategia en el asesor experto principal Trend Constrant.
En el artículo anterior de esta serie desarrollamos un asesor experto basado en el canal de Donchian, marcando dos estrategias en un solo experto. Hoy incorporamos la tercera estrategia y utilizamos datos de tipo booleano para activar y desactivar las estrategias.
// Input parameters for controlling strategies input bool UseTrendFollowingStrategy = false; // Enable/Disable Trend Constraint Strategy input bool UseBreakoutStrategy = false; // Enable/Disable Breakout Strategy input bool UseDivergenceStrategy = true; // Enable/Disable Divergence Strategy
Establecemos la estrategia "Divergence" como verdadera para no confundirnos durante el Probador de estrategias.
Finalmente, integramos cuidadosamente nuestra estrategia en el código principal:
//+------------------------------------------------------------------+ //| Trend Constraint Expert.mq5 | //| Copyright 2024, Clemence Benjamin | //| https://www.mql5.com/en/users/billionaire2024/seller | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, Clemence Benjamin" #property link "https://www.mql5.com/en/users/billionaire2024/seller" #property version "1.02" #include <Trade\Trade.mqh> CTrade trade; // Input parameters for controlling strategies input bool UseTrendFollowingStrategy = false; // Enable/Disable Trend Following Strategy input bool UseBreakoutStrategy = false; // Enable/Disable Breakout Strategy input bool UseDivergenceStrategy = true; // Enable/Disable Divergence Strategy // Input parameters for Trend Constraint Strategy input int RSI_Period = 14; // RSI period input double RSI_Overbought = 70.0; // RSI overbought level input double RSI_Oversold = 30.0; // RSI oversold level input double Lots = 0.1; // Lot size input double StopLoss = 100; // Stop Loss in points input double TakeProfit = 200; // Take Profit in points input double TrailingStop = 50; // Trailing Stop in points input int MagicNumber = 12345678; // Magic number for the Trend Constraint EA input int OrderLifetime = 43200; // Order lifetime in seconds (12 hours) // Input parameters for Breakout Strategy input int InpDonchianPeriod = 20; // Period for Donchian Channel input double RiskRewardRatio = 1.5; // Risk-to-reward ratio input double LotSize = 0.1; // Default lot size for trading input double pipsToStopLoss = 15; // Stop loss in pips for Breakout input double pipsToTakeProfit = 30; // Take profit in pips for Breakout // Input parameters for Divergence Strategy input int DivergenceMACDPeriod = 12; // MACD Fast EMA period input int DivergenceSignalPeriod = 9; // MACD Signal period input double DivergenceLots = 1.0; // Lot size for Divergence trades input double DivergenceStopLoss = 300; // Stop Loss in points for Divergence input double DivergenceTakeProfit = 500; // Take Profit in points for Divergence input int DivergenceMagicNumber = 87654321; // Magic number for Divergence Strategy input int DivergenceLookBack = 8; // Number of periods to look back for divergence input double profitLockerPoints = 20; // Number of profit points to lock // Indicator handle storage int rsi_handle; int handle; // Handle for Donchian Channel int macd_handle; double ExtUpBuffer[]; // Upper Donchian buffer double ExtDnBuffer[]; // Lower Donchian buffer double ExtMacdBuffer[]; // MACD buffer double ExtSignalBuffer[]; // Signal buffer int globalMagicNumber; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { // Initialize RSI handle rsi_handle = iRSI(_Symbol, PERIOD_CURRENT, RSI_Period, PRICE_CLOSE); if (rsi_handle == INVALID_HANDLE) { Print("Failed to create RSI indicator handle. Error: ", GetLastError()); return INIT_FAILED; } // Create a handle for the Donchian Channel handle = iCustom(_Symbol, PERIOD_CURRENT, "Free Indicators\\Donchian Channel", InpDonchianPeriod); if (handle == INVALID_HANDLE) { Print("Failed to load the Donchian Channel indicator. Error: ", GetLastError()); return INIT_FAILED; } // Initialize MACD handle for divergence globalMagicNumber = DivergenceMagicNumber; macd_handle = iMACD(_Symbol, PERIOD_CURRENT, DivergenceMACDPeriod, 26, DivergenceSignalPeriod, PRICE_CLOSE); if (macd_handle == INVALID_HANDLE) { Print("Failed to create MACD indicator handle for divergence strategy. Error: ", GetLastError()); return INIT_FAILED; } // Resize arrays for MACD buffers ArrayResize(ExtMacdBuffer, DivergenceLookBack); ArrayResize(ExtSignalBuffer, DivergenceLookBack); return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { IndicatorRelease(rsi_handle); IndicatorRelease(handle); IndicatorRelease(macd_handle); } //+------------------------------------------------------------------+ //| Check and execute Trend Following EA trading logic | //+------------------------------------------------------------------+ void CheckTrendFollowing() { if (PositionsTotal() >= 2) return; // Ensure no more than 2 orders from this strategy double rsi_value; double rsi_values[]; if (CopyBuffer(rsi_handle, 0, 0, 1, rsi_values) <= 0) { Print("Failed to get RSI value. Error: ", GetLastError()); return; } rsi_value = rsi_values[0]; double ma_short = iMA(_Symbol, PERIOD_CURRENT, 50, 0, MODE_EMA, PRICE_CLOSE); double ma_long = iMA(_Symbol, PERIOD_CURRENT, 200, 0, MODE_EMA, PRICE_CLOSE); bool is_uptrend = ma_short > ma_long; bool is_downtrend = ma_short < ma_long; if (is_uptrend && rsi_value < RSI_Oversold) { double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID); double stopLossPrice = currentPrice - StopLoss * _Point; double takeProfitPrice = currentPrice + TakeProfit * _Point; // Corrected Buy method call with 6 parameters if (trade.Buy(Lots, _Symbol, 0, stopLossPrice, takeProfitPrice, "Trend Following Buy")) { Print("Trend Following Buy order placed."); } } else if (is_downtrend && rsi_value > RSI_Overbought) { double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK); double stopLossPrice = currentPrice + StopLoss * _Point; double takeProfitPrice = currentPrice - TakeProfit * _Point; // Corrected Sell method call with 6 parameters if (trade.Sell(Lots, _Symbol, 0, stopLossPrice, takeProfitPrice, "Trend Following Sell")) { Print("Trend Following Sell order placed."); } } } //+------------------------------------------------------------------+ //| Check and execute Breakout EA trading logic | //+------------------------------------------------------------------+ void CheckBreakoutTrading() { if (PositionsTotal() >= 2) return; // Ensure no more than 2 orders from this strategy ArrayResize(ExtUpBuffer, 2); ArrayResize(ExtDnBuffer, 2); if (CopyBuffer(handle, 0, 0, 2, ExtUpBuffer) <= 0 || CopyBuffer(handle, 2, 0, 2, ExtDnBuffer) <= 0) { Print("Error reading Donchian Channel buffer. Error: ", GetLastError()); return; } double closePrice = iClose(_Symbol, PERIOD_CURRENT, 0); double lastOpen = iOpen(_Symbol, PERIOD_D1, 1); double lastClose = iClose(_Symbol, PERIOD_D1, 1); bool isBullishDay = lastClose > lastOpen; bool isBearishDay = lastClose < lastOpen; if (isBullishDay && closePrice > ExtUpBuffer[1]) { double stopLoss = closePrice - pipsToStopLoss * _Point; double takeProfit = closePrice + pipsToTakeProfit * _Point; if (trade.Buy(LotSize, _Symbol, 0, stopLoss, takeProfit, "Breakout Buy") > 0) { Print("Breakout Buy order placed."); } } else if (isBearishDay && closePrice < ExtDnBuffer[1]) { double stopLoss = closePrice + pipsToStopLoss * _Point; double takeProfit = closePrice - pipsToTakeProfit * _Point; if (trade.Sell(LotSize, _Symbol, 0, stopLoss, takeProfit, "Breakout Sell") > 0) { Print("Breakout Sell order placed."); } } } //+------------------------------------------------------------------+ //| DIVERGENCE TRADING STRATEGY | //+------------------------------------------------------------------+ bool CheckBullishRegularDivergence() { double priceLow1 = iLow(_Symbol, PERIOD_CURRENT, 2); double priceLow2 = iLow(_Symbol, PERIOD_CURRENT, DivergenceLookBack); double macdLow1 = ExtMacdBuffer[2]; double macdLow2 = ExtMacdBuffer[DivergenceLookBack - 1]; return (priceLow1 < priceLow2 && macdLow1 > macdLow2); } bool CheckBullishHiddenDivergence() { double priceLow1 = iLow(_Symbol, PERIOD_CURRENT, 2); double priceLow2 = iLow(_Symbol, PERIOD_CURRENT, DivergenceLookBack); double macdLow1 = ExtMacdBuffer[2]; double macdLow2 = ExtMacdBuffer[DivergenceLookBack - 1]; return (priceLow1 > priceLow2 && macdLow1 < macdLow2); } bool CheckBearishRegularDivergence() { double priceHigh1 = iHigh(_Symbol, PERIOD_CURRENT, 2); double priceHigh2 = iHigh(_Symbol, PERIOD_CURRENT, DivergenceLookBack); double macdHigh1 = ExtMacdBuffer[2]; double macdHigh2 = ExtMacdBuffer[DivergenceLookBack - 1]; return (priceHigh1 > priceHigh2 && macdHigh1 < macdHigh2); } bool CheckBearishHiddenDivergence() { double priceHigh1 = iHigh(_Symbol, PERIOD_CURRENT, 2); double priceHigh2 = iHigh(_Symbol, PERIOD_CURRENT, DivergenceLookBack); double macdHigh1 = ExtMacdBuffer[2]; double macdHigh2 = ExtMacdBuffer[DivergenceLookBack - 1]; return (priceHigh1 < priceHigh2 && macdHigh1 > macdHigh2); } void CheckDivergenceTrading() { if (!UseDivergenceStrategy) return; // Check if no position is open or if less than 3 positions are open int openDivergencePositions = CountOrdersByMagic(DivergenceMagicNumber); if (openDivergencePositions == 0 || openDivergencePositions < 3) { int barsAvailable = Bars(_Symbol, PERIOD_CURRENT); if (barsAvailable < DivergenceLookBack * 2) { Print("Not enough data bars for MACD calculation."); return; } int attempt = 0; while(attempt < 6) { if (CopyBuffer(macd_handle, 0, 0, DivergenceLookBack, ExtMacdBuffer) > 0 && CopyBuffer(macd_handle, 1, 0, DivergenceLookBack, ExtSignalBuffer) > 0) break; Print("Failed to copy MACD buffer, retrying..."); Sleep(1000); attempt++; } if(attempt == 6) { Print("Failed to copy MACD buffers after ", attempt, " attempts."); return; } if(TimeCurrent() == iTime(_Symbol, PERIOD_CURRENT, 0)) { Print("Skipping trade due to incomplete bar data."); return; } double currentClose = iClose(_Symbol, PERIOD_CURRENT, 0); double dailyClose = iClose(_Symbol, PERIOD_D1, 0); double dailyOpen = iOpen(_Symbol, PERIOD_D1, 0); bool isDailyBullish = dailyClose > dailyOpen; bool isDailyBearish = dailyClose < dailyOpen; // Only proceed with buy orders if D1 is bullish if (isDailyBullish) { if ((CheckBullishRegularDivergence() && ExtMacdBuffer[0] > ExtSignalBuffer[0]) || CheckBullishHiddenDivergence()) { ExecuteDivergenceOrder(true); } } // Only proceed with sell orders if D1 is bearish if (isDailyBearish) { if ((CheckBearishRegularDivergence() && ExtMacdBuffer[0] < ExtSignalBuffer[0]) || CheckBearishHiddenDivergence()) { ExecuteDivergenceOrder(false); } } } else { Print("Divergence strategy: Maximum number of positions reached."); } } void ExecuteDivergenceOrder(bool isBuy) { // Ensure the magic number is set for the trade trade.SetExpertMagicNumber(DivergenceMagicNumber); double currentPrice = isBuy ? SymbolInfoDouble(_Symbol, SYMBOL_ASK) : SymbolInfoDouble(_Symbol, SYMBOL_BID); double stopLossPrice = isBuy ? currentPrice - DivergenceStopLoss * _Point : currentPrice + DivergenceStopLoss * _Point; double takeProfitPrice = isBuy ? currentPrice + DivergenceTakeProfit * _Point : currentPrice - DivergenceTakeProfit * _Point; if (isBuy) { if (trade.Buy(DivergenceLots, _Symbol, 0, stopLossPrice, takeProfitPrice, "Divergence Buy")) { Print("Divergence Buy order placed."); } } else { if (trade.Sell(DivergenceLots, _Symbol, 0, stopLossPrice, takeProfitPrice, "Divergence Sell")) { Print("Divergence Sell order placed."); } } } int CountOrdersByMagic(int magic) { int count = 0; for (int i = 0; i < PositionsTotal(); i++) { ulong ticket = PositionGetTicket(i); if (PositionSelectByTicket(ticket)) { if (PositionGetInteger(POSITION_MAGIC) == magic) { count++; } } } return count; } //+------------------------------------------------------------------+ //| Profit Locking Logic | //+------------------------------------------------------------------+ void LockProfits() { for (int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if (PositionSelectByTicket(ticket)) { double entryPrice = PositionGetDouble(POSITION_PRICE_OPEN); double currentProfit = PositionGetDouble(POSITION_PROFIT); double currentPrice = PositionGetDouble(POSITION_PRICE_CURRENT); // Convert profit to points double profitPoints = MathAbs(currentProfit / _Point); // Check if profit has exceeded 100 points if (profitPoints >= 100) { double newStopLoss; if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { newStopLoss = entryPrice + profitLockerPoints * _Point; // 20 points above entry for buys } else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) { newStopLoss = entryPrice - profitLockerPoints * _Point; // 20 points below entry for sells } else { continue; // Skip if not a buy or sell position } // Modify stop loss only if the new stop loss is more protective double currentStopLoss = PositionGetDouble(POSITION_SL); if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { if (currentStopLoss < newStopLoss || currentStopLoss == 0) { if (trade.PositionModify(ticket, newStopLoss, PositionGetDouble(POSITION_TP))) { Print("Profit locking for buy position: Stop Loss moved to ", newStopLoss); } } } else // POSITION_TYPE_SELL { if (currentStopLoss > newStopLoss || currentStopLoss == 0) { if (trade.PositionModify(ticket, newStopLoss, PositionGetDouble(POSITION_TP))) { Print("Profit locking for sell position: Stop Loss moved to ", newStopLoss); } } } } } } } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { if (UseTrendFollowingStrategy) CheckTrendFollowing(); if (UseBreakoutStrategy) CheckBreakoutTrading(); if (UseDivergenceStrategy) CheckDivergenceTrading(); LockProfits(); // Call this function to check and lock profits }
Resultados de las pruebas retrospectivas y aplicación práctica
Para realizar nuestra prueba, debemos localizar Trend Constraint en la sección Experts del terminal. Asegúrese de estar ejecutando una cuenta de demostración. Se abre una ventana del Probador de estrategias, donde se pueden ajustar los parámetros de entrada para diferentes optimizaciones. Vea las imágenes siguientes con la configuración predeterminada:
Asesor experto Trend Constraint: Configuración de demostración
Ejecutamos el Probador de estrategias y las operaciones se ejecutaron exitosamente. El sistema limitaba el número máximo de posiciones a tres por sesión, lo que impedía de manera efectiva la ejecución incontrolada de múltiples órdenes. A continuación se muestra una imagen que muestra un segmento del proceso de prueba retrospectiva en acción:
Trend Constraint: Prueba en EURUSD M15
La imagen siguiente muestra que nuestras funciones de gestión de posiciones funcionan según lo previsto. Según la lógica implementada, hay un máximo de tres órdenes activas, cada una etiquetada con el comentario «Divergence Sell» (Venta por divergencia), lo que las hace fácilmente identificables y alineadas con la estrategia.
Trend Constraint: Máximo de 3 posiciones
Conclusión
Exploramos varios tipos de divergencias y las implementamos en código como parte de una estrategia de confluencia que combina indicadores como el RSI y el MACD para generar señales de trading precisas. Estas señales se perfeccionaron aún más incorporando restricciones diarias de tendencia de velas japonesas, lo que garantiza que se alineen con las tendencias generales del mercado para mejorar su fiabilidad. Nuestro Asesor Experto (EA) Trend Constraint ahora cuenta con tres estrategias distintas y configurables, lo que permite a los usuarios adaptar el EA a sus preferencias de negociación y adaptarse a diversas condiciones del mercado.
Para mejorar la gestión de las operaciones, hemos introducido funciones como números mágicos únicos para cada posición, lo que permite un control preciso de las operaciones abiertas y limita el número de posiciones por estrategia. Además, se desarrolló una función personalizada de bloqueo de ganancias para asegurar las ganancias mediante el ajuste dinámico de los niveles de stop-loss si el mercado se invierte antes de alcanzar el objetivo de Take Profit. Esta funcionalidad garantiza tanto la gestión de riesgos como la flexibilidad, lo que hace que el EA sea robusto y adaptable. A continuación se adjuntan los archivos fuente del EA. Le animamos a que los explore, pruebe varias configuraciones y comparta sus comentarios en la sección correspondiente. Nota: Estos ejemplos tienen fines exclusivamente educativos, y todas las pruebas deben realizarse en cuentas demo.
¡Feliz desarrollo, traders!
Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/16549
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