Desarrollo de un kit de herramientas para el análisis de la acción del precio (Parte 14): Herramienta Parabolic SAR (Stop and Reverse)
Contenido
Introducción
Los indicadores técnicos son señales generadas a través del análisis de patrones de datos históricos, tales como el precio, el volumen y el interés abierto. Estas herramientas heurísticas permiten a los operadores evaluar el comportamiento del mercado y pronosticar movimientos futuros basándose en tendencias probadas y modelos estadísticos.
En este artículo, nos centramos en el desarrollo de un Asesor Experto (EA) utilizando MQL5, diseñado para identificar posibles reversiones del mercado. El EA emplea el Parabolic SAR para la detección de señales, generando señales de trading mediante la supervisión de indicadores técnicos, evaluando su validez en tiempo real e identificando puntos de salida óptimos cuando se alcanzan niveles predefinidos.
Nuestro análisis comienza con una descripción general de la estrategia subyacente y los fundamentos para emplear indicadores técnicos en el trading. A continuación, detallaremos el proceso de implementación en MQL5, analizaremos exhaustivamente los resultados de nuestras pruebas y concluiremos con conclusiones y recomendaciones para los operadores que deseen integrar estas técnicas en sus sistemas.
Entendiendo la estrategia
Parabolic SAR
En el indicador Parabolic SAR, el término «parabólico» se refiere a la forma de la curva trazada. A medida que avanza la tendencia, los puntos del indicador se aceleran de forma curva y parabólica, reflejando el aumento del impulso a medida que los precios se alejan de los extremos recientes.
Por otro lado, «SAR» significa «Stop and Reverse» (detener y revertir). Este componente del indicador señala posibles reversiones de tendencia. Cuando los puntos cambian de un lado del precio al otro, esto sugiere que la tendencia actual puede estar llegando a su fin, lo que lleva a los operadores a considerar la posibilidad de cerrar su posición actual y prepararse para un posible cambio de dirección del mercado.
Antes de profundizar en nuestro concepto, es esencial añadir el SAR parabólico a su gráfico para facilitar su consulta. Hay dos métodos para hacerlo, pero voy a explicar uno de ellos. En su aplicación MetaTrader 5, haga clic en el menú Insertar, luego navegue hasta Indicadores y seleccione Tendencia. Localice e inserte el Parabolic SAR. Una vez añadidos, configura los parámetros según tus preferencias, asegurándote de que coincidan con los utilizados en tu Asesor Experto (EA).
Para obtener más información sobre cómo añadir el indicador, consulte la figura 1 a continuación.

Figura 1. Añadiendo el indicador
Lógica de generación de señales
Trabajar con el indicador Parabolic SAR implica supervisar de cerca la interacción entre la parábola SAR y la acción del precio. En esta estrategia, las señales se generan basándose en la siguiente lógica:
Señal de compra
Se activa una señal de compra cuando:
- La barra actual es alcista (su cierre es superior a su apertura) y su valor PSAR está por debajo del cierre.
- Las dos barras anteriores confirman una tendencia bajista al tener sus puntos PSAR por encima de sus precios de cierre.
- La diferencia entre los valores PSAR de las barras anteriores se encuentra dentro de un rango aceptable, lo que garantiza la coherencia.

Figura 2. Condiciones de compra
Señal de venta
Una señal de venta se activa cuando:
- La barra actual es bajista (su cierre es inferior a su apertura) y su valor PSAR está por encima del cierre.
- Las dos barras anteriores confirman una tendencia alcista al tener sus puntos PSAR por debajo de sus precios de cierre.
- De manera similar, la brecha entre los valores PSAR de las barras anteriores debe estar dentro de un umbral predefinido.

Figura 3. Condiciones de venta
Implementación en MQL5
Encabezado de archivo y propiedades
En la parte superior del código, comenzamos con un encabezado que incluye información esencial del archivo, como el nombre del archivo, los detalles de los derechos de autor y un enlace a la página web del autor. En este caso, he proporcionado la mía. A continuación, aparecen varias directivas #property, que configuran propiedades de compilación críticas, como el número de versión y el modo estricto.
//+--------------------------------------------------------------------+ //| Parabolic SAR EA.mql5 | //| Copyright 2025, Christian Benjamin | //| https://www.mql5.com | //+--------------------------------------------------------------------+ #property copyright "2025, Christian Benjamin" #property link "https://www.mql5.com/en/users/lynnchris" #property version "1.0" #property strict
El uso de #property strict es fundamental, ya que impone una rigurosa comprobación de tipos y validación de parámetros dentro del EA. Esta precaución ayuda a identificar posibles errores de codificación antes de que se conviertan en errores de tiempo de ejecución. Tanto si planeas publicar el EA como si vas a utilizarlo en un entorno de trading real, esta configuración actúa como medida de seguridad, garantizando un funcionamiento fluido y el cumplimiento futuro de las actualizaciones de MetaTrader 5. Considérelo como una medida esencial de control de calidad para su código.
Parámetros de entrada
A continuación, el código define una serie de parámetros de entrada que se pueden personalizar directamente desde la interfaz de MetaTrader 5. Estas entradas incluyen parámetros para el indicador Parabolic SAR, tales como SARStep y SARMaximum, que controlan el factor de aceleración y la aceleración máxima, respectivamente. También hay ajustes para refinar la detección de señales, como MinConsecutiveDots y MaxDotGapPercentage, que ayudan a garantizar que solo las tendencias fuertes activen las señales. También puede habilitar alertas, notificaciones sonoras y dibujos de flechas en el gráfico.
// Input parameters for the Parabolic SAR indicator input double SARStep = 0.02; // Acceleration factor for PSAR input double SARMaximum = 0.2; // Maximum acceleration for PSAR // Input parameters for refining the signal based on PSAR dots input int MinConsecutiveDots = 2; // Require at least 2 consecutive bars in one trend before reversal input double MaxDotGapPercentage = 1.0; // Maximum allowed gap between consecutive PSAR dots (% of current close) // Input parameters for alerts and arrow drawing input bool EnableAlerts = true; // Enable popup alerts input bool EnableSound = true; // Enable sound alerts input bool EnableArrows = true; // Draw arrows on chart input string BuyArrowSymbol = "233"; // Wingdings up arrow (as string) input string SellArrowSymbol = "234"; // Wingdings down arrow (as string) input int ArrowWidth = 2; // Arrow thickness input double ArrowOffsetMultiplier = 5; // Multiplier for arrow placement offset
Estas entradas le permiten personalizar el EA para adaptarlo a las diferentes condiciones del mercado y a sus preferencias de trading. Un aspecto importante aquí es la versatilidad de los símbolos de flecha en MetaTrader 5. Estos símbolos, procedentes de la fuente Wingdings, se pueden personalizar fácilmente. Por ejemplo, puede elegir una marca de verificación para las señales de compra o una «X» para las señales de venta, dependiendo de su estilo de negociación. El ajuste de parámetros como el ancho de las flechas mejora aún más la visibilidad de las señales, lo que le permite ajustar con precisión los elementos visuales del gráfico para mayor claridad y reconocimiento inmediato.
Variables globales y enumeraciones
Para gestionar el estado interno del EA, se declaran varias variables globales y una enumeración. Por ejemplo, almacenamos el identificador del indicador Parabolic SAR en la variable sarHandle, lo que nos permite hacer referencia al indicador en todo nuestro código. También hacemos un seguimiento del tiempo de la última barra procesada con lastBarTime para que el EA procese cada barra solo una vez. La enumeración SignalType define los posibles estados de la señal: sin señal, señal de compra o señal de venta.
// Global indicator handle for PSAR int sarHandle = INVALID_HANDLE; // Global variable to track last processed bar time datetime lastBarTime = 0; // Enumeration for signal types enum SignalType { NO_SIGNAL, BUY_SIGNAL, SELL_SIGNAL }; // Global variables for pending signal mechanism SignalType pendingSignal = NO_SIGNAL; int waitCount = 0; // Counts new closed bars since signal detection double pendingReversalLevel = 0.0; // Stores the PSAR value at signal detection
Además, variables como pendingSignal, waitCount y pendingReversalLevel se utilizan para gestionar las señales pendientes que esperan una confirmación adicional durante unos compases antes de que se tome una decisión definitiva. Una variable crítica es pendingReversalLevel, que captura el valor PSAR en el momento en que se genera una señal. Este nivel sirve como punto de referencia y ayuda al EA a supervisar los movimientos posteriores del precio para determinar si una reversión es real o solo una falsa alarma. Este mecanismo de control es fundamental para reducir las operaciones innecesarias y perfeccionar la precisión general del EA.
Dibujar flechas en el gráfico
Para una representación visual más intuitiva, el EA incluye una función denominada DrawSignalArrow. Esta función se encarga de dibujar una flecha en el gráfico cuando se detecta una señal. Funciona generando un nombre de objeto único basado en el tiempo de barra, comprobando si existe algún objeto con ese nombre y eliminándolo para evitar duplicaciones.
void DrawSignalArrow(string prefix, datetime barTime, double price, color arrowColor, long arrowCode) { string arrowName = prefix + "_" + TimeToString(barTime, TIME_SECONDS); // Remove existing object with the same name to prevent duplicates if(ObjectFind(0, arrowName) != -1) ObjectDelete(0, arrowName); if(ObjectCreate(0, arrowName, OBJ_ARROW, 0, barTime, price)) { ObjectSetInteger(0, arrowName, OBJPROP_COLOR, arrowColor); ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, arrowCode); ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, ArrowWidth); } else { Print("Failed to create arrow object: ", arrowName); } }
El EA emplea el objeto OBJ_ARROW para representar visualmente las señales en el gráfico. Para evitar el desorden causado por los marcadores duplicados, el código primero comprueba y elimina cualquier flecha existente antes de dibujar una nueva. Este enfoque mantiene un gráfico limpio y legible, lo cual es crucial para tomar decisiones comerciales en tiempo real. También puede personalizar diversos aspectos, como el símbolo de la flecha, el color y el desplazamiento, para adaptarlos a sus preferencias personales en cuanto a señales visuales.
Función de detección de señales
El núcleo de EA reside en la función CheckForSignal. Aquí, el código examina las tres barras más recientes de datos de precios y PSAR. Para que se reconozca una señal de compra, la función comprueba que la barra actual sea alcista (lo que significa que su precio de cierre es superior a su precio de apertura) y que el punto PSAR esté por debajo de la vela, mientras que las dos barras anteriores sean bajistas con sus puntos PSAR por encima de las velas. La lógica inversa se aplica a una señal de venta.
SignalType CheckForSignal(const double &sarArray[], const double &openArray[], const double &closeArray[]) { // Mapping indices: // Index 0: Last closed bar (current candidate) // Index 1: Previous bar // Index 2: Bar before previous double sar0 = sarArray[0], sar1 = sarArray[1], sar2 = sarArray[2]; double open0 = openArray[0], close0 = closeArray[0]; double open1 = openArray[1], close1 = closeArray[1]; double open2 = openArray[2], close2 = closeArray[2]; // Check for BUY signal: if((close0 > open0) && (sar0 < close0) && (sar1 > close1) && (sar2 > close2)) { int countBearish = 0; if(sar1 > close1) countBearish++; if(sar2 > close2) countBearish++; double dotGap = MathAbs(sar1 - sar2); double gapThreshold = (MaxDotGapPercentage / 100.0) * close0; if(countBearish >= MinConsecutiveDots && dotGap <= gapThreshold) return BUY_SIGNAL; } // Check for SELL signal: if((close0 < open0) && (sar0 > close0) && (sar1 < close1) && (sar2 < close2)) { int countBullish = 0; if(sar1 < close1) countBullish++; if(sar2 < close2) countBullish++; double dotGap = MathAbs(sar1 - sar2); double gapThreshold = (MaxDotGapPercentage / 100.0) * close0; if(countBullish >= MinConsecutiveDots && dotGap <= gapThreshold) return SELL_SIGNAL; } return NO_SIGNAL; }
La función también utiliza un umbral de separación para garantizar que el espacio entre puntos PSAR consecutivos se mantenga dentro de límites aceptables. Si se cumplen las condiciones, devuelve el tipo de señal adecuado (compra o venta); de lo contrario, no devuelve ninguna señal. La función de detección de señales identifica eficazmente los cambios de tendencia utilizando el posicionamiento PSAR y los patrones de velas japonesas. Sin embargo, su diseño permite mejoras adicionales mediante la incorporación de filtros adicionales, como medias móviles, RSI o incluso el índice de volatilidad. Añadir estas capas puede ayudar a eliminar las señales falsas durante los mercados laterales o durante los periodos influenciados por acontecimientos noticiosos importantes. Básicamente, el EA está diseñado para ser adaptable, lo que le da la libertad de ajustar su lógica a su estrategia comercial única y a las condiciones del mercado.
Detección de nuevas barras
Antes de procesar cualquier dato, el EA debe determinar si se ha cerrado una nueva barra. La función IsNewBar gestiona esto recuperando la hora de la barra cerrada más reciente y comparándola con la lastBarTime almacenada. Si los tiempos difieren, significa que se ha formado una nueva barra, por lo que la función actualiza lastBarTime y devuelve verdadero (true).
bool IsNewBar() { datetime times[]; if(CopyTime(_Symbol, _Period, 1, 1, times) <= 0) { Print("Failed to retrieve bar time in IsNewBar()."); return false; } if(times[0] != lastBarTime) { lastBarTime = times[0]; return true; } return false; }
Esta comprobación es crucial porque garantiza que el EA procese los datos solo una vez por cada nueva barra, evitando así el procesamiento repetitivo o erróneo de las señales. La función IsNewBar es un potenciador inteligente de la eficiencia del EA. Al garantizar que las señales solo se procesen una vez por cada nueva barra, se evitan cálculos redundantes y alertas repetidas. Esta sencilla comprobación mantiene el EA funcionando de manera eficiente y reduce el riesgo de malinterpretar los movimientos de precios dentro de una sola barra. En general, ayuda a mantener un rendimiento constante y predecible en la plataforma MetaTrader 5.
Inicialización y desinicialización
Cuando se carga el EA, la función OnInit se ejecuta primero. Su tarea principal es crear un controlador para el indicador Parabolic SAR integrado utilizando los parámetros proporcionados por el usuario. Si el indicador se inicializa correctamente, se imprime un mensaje de confirmación; si no, se genera un mensaje de error y la inicialización falla. Por el contrario, la función OnDeinit se invoca cuando el EA se elimina del gráfico o cuando se cierra el terminal.
int OnInit() { // Create the built-in Parabolic SAR indicator handle sarHandle = iSAR(_Symbol, _Period, SARStep, SARMaximum); if(sarHandle == INVALID_HANDLE) { Print("Error creating PSAR handle"); return INIT_FAILED; } Print("SAR EA initialized successfully."); return INIT_SUCCEEDED; }
Esta función se encarga de liberar el identificador del indicador y limpiar cualquier objeto gráfico (como flechas) que se haya creado durante el funcionamiento del EA, asegurando que no quede ningún desorden innecesario. Un EA bien diseñado presta atención a la limpieza durante la desinicialización. Al eliminar las flechas u otros elementos visuales creados durante la operación, se evita que el gráfico se sature con marcadores obsoletos. Este proceso de limpieza es similar a una buena organización doméstica, ya que garantiza que cada vez que inicie el EA, trabajará con un gráfico limpio y ordenado y con un rendimiento óptimo del sistema.
Lógica principal (función OnTick)
Por último, la función OnTick es el motor principal que se ejecuta en cada tick. Primero comprueba si se acaba de cerrar una nueva barra utilizando la función IsNewBar. Si no se detecta ninguna barra nueva, la función se cierra antes de tiempo para evitar un procesamiento redundante. Una vez confirmada una nueva barra, el EA recupera los últimos valores PSAR junto con los precios de apertura y cierre correspondientes a las barras recientes. En este punto, el EA evalúa si hay alguna señal pendiente que esté esperando confirmación. Si hay una señal pendiente, se incrementa un contador (waitCount) para llevar la cuenta de cuántas barras han pasado.
void OnTick() { // Process only once per new closed bar if(!IsNewBar()) return; // Retrieve PSAR and price data double sarArray[4]; if(CopyBuffer(sarHandle, 0, 1, 4, sarArray) < 3) { /* error handling */ } double openArray[4], closeArray[4]; if(CopyOpen(_Symbol, _Period, 1, 4, openArray) < 3 || CopyClose(_Symbol, _Period, 1, 4, closeArray) < 3) { /* error handling */ } // Pending Signal Logic... if(pendingSignal != NO_SIGNAL) { waitCount++; // Increment waiting counter if(pendingSignal == BUY_SIGNAL) { if(closeArray[0] <= pendingReversalLevel) { // Confirm reversal: Close alert for BUY signal } else if(waitCount >= 3) { // Warn about a possible fake BUY signal } } else if(pendingSignal == SELL_SIGNAL) { if(closeArray[0] >= pendingReversalLevel) { // Confirm reversal: Close alert for SELL signal } else if(waitCount >= 3) { // Warn about a possible fake SELL signal } } return; // Wait until pending signal is resolved } // Check for a new reversal signal if no pending signal exists SignalType newSignal = CheckForSignal(sarArray, openArray, closeArray); if(newSignal != NO_SIGNAL) { pendingSignal = newSignal; waitCount = 0; // Reset counter pendingReversalLevel = sarArray[0]; // Store current PSAR value // Alert and optionally draw an arrow based on the new signal if(newSignal == BUY_SIGNAL) { /* process BUY signal */ } else if(newSignal == SELL_SIGNAL) { /* process SELL signal */ } } }
A continuación, el EA comprueba si el precio actual ha alcanzado el nivel de reversión almacenado: si es así, se emite una alerta para «cerrar aquí» la señal; si pasan tres barras sin confirmación, el EA advierte de una posible señal falsa. Si no hay ninguna señal pendiente activa, el EA llama a la función CheckForSignal para comprobar si ha surgido una nueva señal. Si es así, almacena la señal, restablece el contador de espera, establece el nivel de reversión pendiente en función del valor PSAR actual y activa las alertas y los marcadores visuales adecuados. Una característica innovadora de la función OnTick es su método para filtrar posibles señales falsas.
Mediante el uso de un contador (waitCount) para supervisar cuántas barras pasan después de que se genera una señal, el EA da tiempo para la confirmación antes de actuar. Este retraso resulta especialmente útil en mercados volátiles, donde las rápidas fluctuaciones de precios podrían, de otro modo, desencadenar señales prematuras. Ajustar el número de barras de confirmación le permite equilibrar la capacidad de respuesta y la precaución, lo que hace que el EA sea lo suficientemente flexible como para admitir tanto estrategias de scalping a corto plazo como estrategias de tendencia a largo plazo.
Código completo del EA MQL5
//+--------------------------------------------------------------------+ //| Parabolic SAR EA.mql5 | //| Copyright 2025, Christian Benjamin | //| https://www.mql5.com | //+--------------------------------------------------------------------+ #property copyright "2025, Christian Benjamin" #property link "https://www.mql5.com/en/users/lynnchris" #property version "1.2" #property strict // Input parameters for the Parabolic SAR indicator input double SARStep = 0.1; // Acceleration factor for PSAR input double SARMaximum = 1; // Maximum acceleration for PSAR // Input parameters for refining the signal based on PSAR dots input int MinConsecutiveDots = 2; // Require at least 2 consecutive bars in one trend before reversal input double MaxDotGapPercentage = 1.0; // Maximum allowed gap between consecutive PSAR dots (% of current close) // Input parameters for alerts and arrow drawing input bool EnableAlerts = true; // Enable popup alerts input bool EnableSound = true; // Enable sound alerts input bool EnableArrows = true; // Draw arrows on chart input string BuyArrowSymbol = "233"; // Wingdings up arrow (as string) input string SellArrowSymbol = "234"; // Wingdings down arrow (as string) input int ArrowWidth = 2; // Arrow thickness input double ArrowOffsetMultiplier = 5; // Multiplier for arrow placement offset // Global indicator handle for PSAR int sarHandle = INVALID_HANDLE; // Global variable to track last processed bar time datetime lastBarTime = 0; // Enumeration for signal types enum SignalType { NO_SIGNAL, BUY_SIGNAL, SELL_SIGNAL }; // Global variables for pending signal mechanism SignalType pendingSignal = NO_SIGNAL; int waitCount = 0; // Counts new closed bars since signal detection double pendingReversalLevel = 0.0; // Stores the PSAR value at signal detection //+------------------------------------------------------------------+ //| DrawSignalArrow - Draws an arrow object on the chart | //+------------------------------------------------------------------+ void DrawSignalArrow(string prefix, datetime barTime, double price, color arrowColor, long arrowCode) { string arrowName = prefix + "_" + TimeToString(barTime, TIME_SECONDS); // Remove existing object with the same name to prevent duplicates if(ObjectFind(0, arrowName) != -1) ObjectDelete(0, arrowName); if(ObjectCreate(0, arrowName, OBJ_ARROW, 0, barTime, price)) { ObjectSetInteger(0, arrowName, OBJPROP_COLOR, arrowColor); ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, arrowCode); ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, ArrowWidth); } else { Print("Failed to create arrow object: ", arrowName); } } //+-------------------------------------------------------------------+ //| CheckForSignal - Evaluates PSAR and price data to determine signal| //+-------------------------------------------------------------------+ SignalType CheckForSignal(const double &sarArray[], const double &openArray[], const double &closeArray[]) { // Mapping indices: // Index 0: Last closed bar (current candidate) // Index 1: Previous bar // Index 2: Bar before previous double sar0 = sarArray[0], sar1 = sarArray[1], sar2 = sarArray[2]; double open0 = openArray[0], close0 = closeArray[0]; double open1 = openArray[1], close1 = closeArray[1]; double open2 = openArray[2], close2 = closeArray[2]; // Check for BUY signal: if((close0 > open0) && (sar0 < close0) && (sar1 > close1) && (sar2 > close2)) { int countBearish = 0; if(sar1 > close1) countBearish++; if(sar2 > close2) countBearish++; double dotGap = MathAbs(sar1 - sar2); double gapThreshold = (MaxDotGapPercentage / 100.0) * close0; if(countBearish >= MinConsecutiveDots && dotGap <= gapThreshold) return BUY_SIGNAL; } // Check for SELL signal: if((close0 < open0) && (sar0 > close0) && (sar1 < close1) && (sar2 < close2)) { int countBullish = 0; if(sar1 < close1) countBullish++; if(sar2 < close2) countBullish++; double dotGap = MathAbs(sar1 - sar2); double gapThreshold = (MaxDotGapPercentage / 100.0) * close0; if(countBullish >= MinConsecutiveDots && dotGap <= gapThreshold) return SELL_SIGNAL; } return NO_SIGNAL; } //+------------------------------------------------------------------+ //| IsNewBar - Determines if a new closed bar is available | //+------------------------------------------------------------------+ bool IsNewBar() { datetime times[]; if(CopyTime(_Symbol, _Period, 1, 1, times) <= 0) { Print("Failed to retrieve bar time in IsNewBar()."); return false; } if(times[0] != lastBarTime) { lastBarTime = times[0]; return true; } return false; } //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { // Create the built-in Parabolic SAR indicator handle sarHandle = iSAR(_Symbol, _Period, SARStep, SARMaximum); if(sarHandle == INVALID_HANDLE) { Print("Error creating PSAR handle"); return INIT_FAILED; } Print("SAR EA initialized successfully."); return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { if(sarHandle != INVALID_HANDLE) IndicatorRelease(sarHandle); // Remove all arrow objects from the current chart window ObjectsDeleteAll(0, (int)OBJ_ARROW, 0); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { // Process only once per new closed bar if(!IsNewBar()) return; // Retrieve the last 4 PSAR values (we require at least 3 values) double sarArray[4]; if(CopyBuffer(sarHandle, 0, 1, 4, sarArray) < 3) { Print("Failed to retrieve PSAR data."); return; } // Retrieve the last 4 bars' price data (Open and Close) double openArray[4], closeArray[4]; if(CopyOpen(_Symbol, _Period, 1, 4, openArray) < 3 || CopyClose(_Symbol, _Period, 1, 4, closeArray) < 3) { Print("Failed to retrieve price data."); return; } // Process pending signal logic if a signal is waiting confirmation if(pendingSignal != NO_SIGNAL) { waitCount++; // Increment the waiting counter if(pendingSignal == BUY_SIGNAL) { if(closeArray[0] <= pendingReversalLevel) { Print("Reversal level reached for BUY signal. Close here."); if(EnableAlerts) Alert("Close here for BUY signal on ", _Symbol, " at price ", DoubleToString(closeArray[0], _Digits)); if(EnableSound) PlaySound("alert.wav"); pendingSignal = NO_SIGNAL; waitCount = 0; } else if(waitCount >= 3) { Print("Warning: Possible fake BUY signal - reversal not confirmed in 3 candles."); if(EnableAlerts) Alert("Warning: Possible fake BUY signal on ", _Symbol); pendingSignal = NO_SIGNAL; waitCount = 0; } } else if(pendingSignal == SELL_SIGNAL) { if(closeArray[0] >= pendingReversalLevel) { Print("Reversal level reached for SELL signal. Close here."); if(EnableAlerts) Alert("Close here for SELL signal on ", _Symbol, " at price ", DoubleToString(closeArray[0], _Digits)); if(EnableSound) PlaySound("alert.wav"); pendingSignal = NO_SIGNAL; waitCount = 0; } else if(waitCount >= 3) { Print("Warning: Possible fake SELL signal - reversal not confirmed in 3 candles."); if(EnableAlerts) Alert("Warning: Possible fake SELL signal on ", _Symbol); pendingSignal = NO_SIGNAL; waitCount = 0; } } return; } // Check for a new reversal signal SignalType newSignal = CheckForSignal(sarArray, openArray, closeArray); if(newSignal != NO_SIGNAL) { pendingSignal = newSignal; waitCount = 0; // Reset waiting counter pendingReversalLevel = sarArray[0]; // Set reversal level from current PSAR value if(newSignal == BUY_SIGNAL) { Print("Buy signal detected on ", TimeToString(lastBarTime, TIME_DATE|TIME_SECONDS), ". Waiting for reversal confirmation (up to 3 candles)."); if(EnableAlerts) Alert("Buy signal detected on ", _Symbol, " at price ", DoubleToString(closeArray[0], _Digits)); if(EnableArrows) { double lowVal[]; if(CopyLow(_Symbol, _Period, 1, 1, lowVal) > 0) { double offset = _Point * ArrowOffsetMultiplier; DrawSignalArrow("BuyArrow", lastBarTime, lowVal[0] - offset, clrGreen, StringToInteger(BuyArrowSymbol)); } else Print("Failed to retrieve low price for arrow placement."); } } else if(newSignal == SELL_SIGNAL) { Print("Sell signal detected on ", TimeToString(lastBarTime, TIME_DATE|TIME_SECONDS), ". Waiting for reversal confirmation (up to 3 candles)."); if(EnableAlerts) Alert("Sell signal detected on ", _Symbol, " at price ", DoubleToString(closeArray[0], _Digits)); if(EnableArrows) { double highVal[]; if(CopyHigh(_Symbol, _Period, 1, 1, highVal) > 0) { double offset = _Point * ArrowOffsetMultiplier; DrawSignalArrow("SellArrow", lastBarTime, highVal[0] + offset, clrRed, StringToInteger(SellArrowSymbol)); } else Print("Failed to retrieve high price for arrow placement."); } } } } //+------------------------------------------------------------------+
Pruebas y resultados
Antes de pasar al trading real, recomiendo realizar pruebas retrospectivas en una cuenta demo. A continuación, le indicamos cómo puede ajustar su EA en función de los resultados de las pruebas:- Una vez que haya compilado correctamente su EA en MetaEditor, abra MetaTrader.
- En MetaTrader, vaya al Probador de estrategias. Seleccione el EA que desea probar, luego elija el marco temporal deseado, el período de prueba y cualquier otro parámetro relevante.
- Después de configurar los ajustes, haga clic en «Iniciar» para comenzar la prueba retrospectiva.

Figura 4. Inicializando el probador
A continuación, he incluido imágenes y varios GIF capturados durante mis sesiones de pruebas retrospectivas. La primera imagen es un diagrama del índice Volatility 25, en el que se destacan los puntos en los que se confirmaron las señales de venta y compra durante la prueba. A continuación, se incluyen varios GIF para una visualización adicional, que pueden ayudarle a comprender mejor el rendimiento del EA.

Figura 5. Pruebas retrospectivas sobre el índice Volatility 25
Pruebas retrospectivas sobre el índice Volatility 25 GIF.

Figura 6: Prueba retrospectiva sobre el índice Volatility 25
Prueba retrospectiva en Step Index.

Figura 7: Prueba retrospectiva en el Step Index
Comercio en vivo en el Step Index.

Figura 8: Trading en vivo
Conclusión
Hemos desarrollado y probado el EA, obteniendo resultados positivos. Sin embargo, algunas señales pueden requerir un filtrado adicional. Recuerde que este EA está diseñado para complementar sus propias estrategias comerciales, en lugar de reemplazarlas. Verifique siempre todas las condiciones relevantes antes de ejecutar cualquier operación basada en sus señales. Además, trabajar con marcos temporales más amplios puede ser crucial para minimizar las señales falsas.
| Fecha | Nombre de la herramienta | Descripción | Versión | Actualizaciones | Notas |
|---|---|---|---|---|---|
| 01/10/24 | Chart Projector | Script para superponer la acción del precio del día anterior con efecto fantasma. | 1.0 | Lanzamiento inicial | Herramienta número 1 |
| 18/11/24 | Analytical Comment | Proporciona información del día anterior en formato tabular y anticipa la dirección futura del mercado. | 1.0 | Lanzamiento inicial | Herramienta número 2 |
| 27/11/24 | Analytics Master | Actualización periódica de las métricas del mercado cada dos horas. | 1.01 | Segundo lanzamiento | Herramienta número 3 |
| 02/12/24 | Analytics Forecaster | Actualización periódica de las métricas del mercado cada dos horas con integración de Telegram. | 1.1 | Tercera edición | Herramienta número 4 |
| 09/12/24 | Volatility Navigator | El EA analiza las condiciones del mercado utilizando los indicadores Bandas de Bollinger, RSI y ATR. | 1.0 | Lanzamiento inicial | Herramienta número 5 |
| 19/12/24 | Mean Reversion Signal Reaper | Analiza el mercado utilizando la estrategia de reversión a la media y proporciona señales. | 1.0 | Lanzamiento inicial | Herramienta número 6 |
| 09/01/25 | Signal Pulse | Analizador de múltiples marcos temporales. | 1.0 | Lanzamiento inicial | Herramienta número 7 |
| 17/01/25 | Metrics Board | Panel con botón para análisis. | 1.0 | Lanzamiento inicial | Herramienta número 8 |
| 21/01/25 | External Flow | Análisis a través de bibliotecas externas. | 1.0 | Lanzamiento inicial | Herramienta número 9 |
| 27/01/25 | VWAP | Volume Weighted Average Price | 1.3 | Lanzamiento inicial | Herramienta número 10 |
| 02/02/25 | Heikin Ashi | Identificación de señales de suavizado y reversión de tendencias. | 1.0 | Lanzamiento inicial | Herramienta número 11 |
| 04/02/25 | FibVWAP | Generación de señales mediante análisis de Python. | 1.0 | Lanzamiento inicial | Herramienta número 12 |
| 14/02/25 | RSI DIVERGENCE | Acción del precio frente a divergencias del RSI. | 1.0 | Lanzamiento inicial | Herramienta número 13 |
| 17/02/2025 | Parabolic SAR | Automatización de la estrategia Parabolic SAR. | 1.0 | Lanzamiento inicial | Herramienta número 14 |
Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/17234
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.
Desarrollo de asesores expertos autooptimizables en MQL5 (Parte 6): Prevención del cierre de posiciones
Redes neuronales en el trading: Clusterización doble de series temporales (DUET)
Automatización de estrategias de trading en MQL5 (Parte 8): Creación de un Asesor Experto con patrones armónicos Butterfly
Automatización de estrategias de trading en MQL5 (Parte 7): Creación de un EA para el comercio en cuadrícula con escalado dinámico de lotes
- 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