English Русский 中文 Deutsch 日本語
preview
Desarrollo de un kit de herramientas para el análisis de la acción del precio (Parte 26): Herramienta de patrones pin bar y envolventes con divergencia del RSI (patrones múltiples)

Desarrollo de un kit de herramientas para el análisis de la acción del precio (Parte 26): Herramienta de patrones pin bar y envolventes con divergencia del RSI (patrones múltiples)

MetaTrader 5Ejemplos |
35 0
Christian Benjamin
Christian Benjamin

Introducción

En mi artículo anterior, me centré en identificar cuatro formaciones de velas japonesas: pin bar, doji, envolvente y marubozu. Estos patrones se utilizaban para generar señales de compra o venta en cuanto se detectaban. Sin embargo, este enfoque generaba a veces señales erróneas, ya que la confirmación se basaba únicamente en el reconocimiento de patrones, sin filtros adicionales.

Este artículo presenta una nueva herramienta que se centra en dos patrones clave: la pin bar y el patrón envolvente. Estos patrones se combinan con la divergencia del RSI para confirmar cada señal. La divergencia del RSI es una herramienta que desarrollé en el pasado como indicador independiente basado en la evolución del precio. Al integrar el reconocimiento de patrones con la divergencia del RSI, creamos un método analítico más sólido y eficaz, que ofrece una visión más profunda y mejora la precisión de las operaciones gracias a un análisis exhaustivo de la evolución de los precios.

Comenzaremos analizando ambos patrones con mayor detalle, para luego pasar a una visión general de la estrategia, un desglose de los componentes del código, los resultados del backtesting y el análisis. Por último, concluiremos con los puntos clave. Consulte el índice que figura a continuación.


Comprender los patrones de velas japonesas

Los patrones de velas japonesas son formaciones que se utilizan en el análisis técnico para analizar los movimientos de los precios en los mercados financieros. Representan visualmente los precios de apertura, máximo, mínimo y cierre de un mercado durante un periodo concreto, lo que ofrece información sobre la posible dirección y el sentimiento del mercado. Existen muchos patrones de velas japonesas, pero, tal y como se menciona en este artículo, nos centraremos en dos patrones principales: la vela pin bar y el patrón envolvente. Estos patrones pueden aparecer como una o dos velas en los timeframes superiores, o como varias velas en los gráficos de menor intervalo de tiempo. Veamos la ilustración siguiente, donde lo explicaré con más detalle para que entiendas a qué me refiero.

El primer gráfico (Fig. 1) muestra un patrón de envolvente bajista en el marco temporal M30. Consta de dos velas: la primera es una vela alcista con un cuerpo pequeño, seguida de una vela bajista con un cuerpo más grande que envuelve a la vela alcista anterior.

Fig. 1. Patrón envolvente bajista en M30

El mismo patrón puede representarse mediante varias velas cuando se observa en un marco temporal inferior. Echemos un vistazo al siguiente diagrama (Fig. 2). Muestra el mismo patrón de velas que antes, pero ahora en el marco temporal M5, donde se representa mediante una serie de varias velas.

Fig. 2. Patrón envolvente bajista en el M5

Pasemos ahora a analizar los dos patrones en los que nos vamos a centrar: la pin bar y el patrón envolvente, así como la divergencia del RSI. No profundizaremos en estos temas aquí, ya que los tratamos ampliamente en nuestro artículo anterior. Puedes consultar ese artículo a través del enlace proporcionado.

Pin Bar

Una vela pin bar es un tipo de vela japonesa que se caracteriza por un cuerpo real pequeño y una mecha prominente, lo que indica un rechazo significativo del precio en un nivel específico. Aparece como una sola vela que a menudo indica un posible cambio de tendencia o un punto de inflexión crítico en el mercado. La mecha extendida demuestra que los precios se movieron bruscamente en una dirección, pero fueron rápidamente rechazados, lo que implica un cambio en el sentimiento del mercado y un posible cambio en la tendencia.

Patrón envolvente

El patrón de vela envolvente es una herramienta popular en el análisis técnico que señala una posible reversión en la dirección del mercado. Consiste en dos velas consecutivas, donde el cuerpo de la segunda vela "envuelve" por completo el cuerpo de la primera, lo que indica un cambio en el sentimiento del mercado. Este patrón sirve como señal de reversión, lo que sugiere que la tendencia anterior puede estar terminando y que está comenzando una nueva tendencia, ya sea una reversión alcista cuando una vela ascendente más grande envuelve a una vela descendente más pequeña, o una reversión bajista cuando una vela descendente más grande envuelve a una vela ascendente más pequeña.

Divergencia del RSI

La divergencia del RSI (Índice de Fuerza Relativa) se produce cuando el precio de un activo y el indicador RSI se mueven en direcciones opuestas, lo que indica un posible cambio en el impulso y una posible inversión de la tendencia. Esta divergencia se hace evidente cuando el precio forma nuevos máximos o mínimos, pero el RSI no coincide con los máximos o mínimos correspondientes. Existen dos tipos principales: la divergencia bajista, que se produce cuando el precio alcanza un nuevo máximo mientras que el RSI crea un máximo inferior, lo que indica un debilitamiento del impulso alcista y una posible caída inminente; y la divergencia alcista, donde el precio alcanza un nuevo mínimo, pero el RSI forma un mínimo superior, lo que sugiere que el impulso bajista está disminuyendo y que podría producirse un movimiento alcista.

El RSI, como oscilador de impulso, mide la velocidad y el cambio de los movimientos de precios, lo que ayuda a los operadores a identificar condiciones de sobrecompra o sobreventa, pero también revela patrones de divergencia. Cuando el precio alcanza nuevos extremos sin un movimiento correspondiente en el RSI, indica un posible cambio de impulso y una reversión de la tendencia.

Divergencia bajista

Fig. 3. Divergencia bajista del RSI

Divergencia alcista del RSI

Fig. 4. Divergencia alcista del RSI


Resumen de la estrategia

Nuestra herramienta busca y reconoce minuciosamente los patrones de velas pin bar y envolventes, al tiempo que comprueba la divergencia del RSI para confirmar cada señal, ya sea de compra o de venta. En otras palabras, cuando se detecta una vela pin bar o un patrón envolvente, el EA verifica la divergencia del RSI como confirmación antes de validar la señal. La herramienta solo muestra la señal de trading si el RSI confirma el patrón. A continuación, se muestra un diagrama que ilustra cómo una vela pin bar puede confirmarse mediante una divergencia alcista del RSI.

Fig. 5. Confirmación de pin bar


Desglose de los componentes del código

1. Propiedades de metadatos e inicialización

La sección inicial del EA define metadatos esenciales que ayudan a identificar y gestionar el script dentro del entorno MetaTrader. La declaración de derechos de autor, el enlace y el número de versión proporcionan atribución y control de versiones, lo que garantiza que los usuarios conozcan el origen y el estado de actualización del script. La directiva #property strict impone reglas de compilación más estrictas, lo que permite detectar posibles errores en una fase temprana y fomenta unas mejores prácticas de programación. Esta configuración garantiza que el EA cumpla con los estándares esperados, lo que facilita el mantenimiento, la resolución de problemas y la identificación cuando se ejecutan varios scripts simultáneamente.

//+------------------------------------------------------------------+
//|                                           Multi-Pattern Signal EA|
//|                                   Copyright 2025, MetaQuotes Ltd.|
//|                           https://www.mql5.com/en/users/lynnchris|
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link      "https://www.mql5.com/en/users/lynnchris"
#property version   "1.0"
#property strict

2. Incluir bibliotecas y definir entradas de usuario

El EA incluye la biblioteca <Trade/Trade.mqh> para permitir operaciones con órdenes, como la apertura, el cierre y la gestión de operaciones. Si bien esta versión se centra principalmente en la detección de patrones y las alertas, la integración de la biblioteca de operaciones permite una futura ampliación hacia el trading automatizado. Los parámetros de entrada son vitales para la personalización: los operadores pueden ajustar el período del RSI para modificar la sensibilidad, establecer umbrales de sobrecompra y sobreventa para la detección de divergencias, y configurar los niveles de stop-loss y take-profit en pips.

El EntryBuffer actúa como una zona de amortiguación para evitar entradas demasiado cercanas a los extremos recientes de los precios, lo que reduce las señales falsas. Las opciones de notificación permiten activar o desactivar las alertas sonoras, las notificaciones push y los correos electrónicos, lo que da a los operadores control sobre cómo reciben las alertas. En conjunto, estos parámetros hacen que el EA sea adaptable a diversos estilos de negociación y condiciones de mercado.

#include <Trade/Trade.mqh>

input int    RSI_Period     = 14;      // RSI calculation period
input double RSI_Overbought = 70.0;    // RSI level indicating overbought
input double RSI_Oversold   = 30.0;    // RSI level indicating oversold
input double SL_Pips        = 20.0;    // Default stop loss in pips
input double TP_Pips        = 20.0;    // Default take profit in pips
input double EntryBuffer    = 5.0;     // Buffer in points for entry price
input bool   EnableSound    = true;    // Enable sound alerts
input bool   EnablePush     = true;    // Enable push notifications
input bool   EnableEmail    = false;   // Enable email alerts

3. Inicialización: Creación de manejadores de indicadores y búferes

Durante la configuración inicial, el EA crea un manejador para el indicador RSI usandoiRSI()especificando el símbolo, el período y los parámetros RSI. Este identificador es esencial para recuperar los valores RSI en tiempo real durante cada tick, constituyendo la base de la detección de divergencias. Los arrays están configurados como series, lo que significa que los datos más recientes siempre están en el índice 0. Los búferes internos para el tiempo, la apertura, el precio máximo, el precio mínimo y el precio de cierre se inicializan para almacenar datos históricos para su análisis. La variable lastBarTime registra la marca de tiempo de la última vela procesada, lo que impide que se generen múltiples señales dentro de la misma vela, evitando así alertas redundantes y garantizando la precisión de las señales.

int OnInit()
{
    rsiHandle = iRSI(_Symbol, _Period, RSI_Period, PRICE_CLOSE);
    if(rsiHandle == INVALID_HANDLE)
        return INIT_FAILED;

    // Set arrays as series for easier access to recent data
    ArraySetAsSeries(rsiBuffer,   true);
    ArraySetAsSeries(timeBuffer,  true);
    ArraySetAsSeries(openBuffer,  true);
    ArraySetAsSeries(highBuffer,  true);
    ArraySetAsSeries(lowBuffer,   true);
    ArraySetAsSeries(closeBuffer, true);

    return INIT_SUCCEEDED;
}

4. Monitorización y procesamiento continuo de datos en OnTick()

La función OnTick() se ejecuta con cada tick del mercado y actúa como el bucle principal del EA. El proceso comienza verificando que haya al menos 20 barras disponibles, lo que garantiza suficientes datos históricos para el reconocimiento de patrones. A continuación, copia los últimos 20 puntos de datos de marcas de tiempo y datos de precios (apertura, máximo, mínimo, cierre) en búferes internos. Este paso es crucial porque los datos de mercado se actualizan constantemente y el análisis depende de datos recientes y precisos. Si falla alguna operación de copia, la función se detiene para evitar errores o señales falsas.

Para evitar que se generen múltiples señales dentro de la misma vela, comprueba si la marca de tiempo de la vela anterior coincide con lastBarTime. En ese caso, omite el procesamiento; de lo contrario, actualiza lastBarTime con la marca de tiempo de la nueva vela. A continuación, actualiza los datos del RSI. Una vez preparados los datos, se llama a la función FindSignalBar() para analizar las barras recientes en busca de patrones de divergencia y señales de velas japonesas, lo que constituye la base para la generación de alertas.

void OnTick()
{
    // Ensure enough data is available
    if(Bars(_Symbol, _Period) < 20)
        return;

    // Copy recent market data
    if(CopyTime(_Symbol, _Period, 0, 20, timeBuffer)   <= 0 ||
       CopyOpen(_Symbol, _Period, 0, 20, openBuffer)   <= 0 ||
       CopyHigh(_Symbol, _Period, 0, 20, highBuffer)   <= 0 ||
       CopyLow(_Symbol, _Period, 0, 20, lowBuffer)     <= 0 ||
       CopyClose(_Symbol, _Period, 0, 20, closeBuffer) <= 0)
       return;

    // Prevent multiple signals in the same candle
    if(timeBuffer[1] == lastBarTime)
        return;
    lastBarTime = timeBuffer[1];

    // Update RSI data
    if(CopyBuffer(rsiHandle, 0, 0, 20, rsiBuffer) <= 0)
        return;

    // Detect potential divergence and pattern
    int dir = FindSignalBar();
    if(dir == 0)
        return;

    // Determine direction and compute entry/stop levels
    bool isBullish = (dir > 0);
    int idx = 1; // most recent completed bar
    double entry = isBullish
                   ? highBuffer[idx] + EntryBuffer * _Point
                   : lowBuffer[idx] - EntryBuffer * _Point;
    double stopL = isBullish
                   ? lowBuffer[idx] - SL_Pips * _Point
                   : highBuffer[idx] + SL_Pips * _Point;

    // Visualize and notify
    DrawSignal(idx, isBullish, entry, stopL);
}

5. Reconocimiento de patrones mediante el análisis de divergencias y velas japonesas

La función FindSignalBar() desempeña un papel fundamental a la hora de identificar posibles señales de reversión. Analiza las barras recientes (de 5 a 15 barras atrás) para detectar patrones de divergencia. La divergencia alcista se confirma cuando el precio marca un mínimo más bajo mientras el RSI forma un mínimo más alto en zona de sobreventa. Por el contrario, la divergencia bajista se produce cuando el precio marca un máximo más alto mientras el RSI forma un máximo más bajo en zona de sobrecompra.

La función también analiza la última barra en busca de patrones de velas que respalden la divergencia, como las velas pin bar y las velas envolventes, conocidas por su importancia en los cambios de tendencia. Si se cumplen tanto las condiciones de divergencia como las del patrón, devuelve +1 para una señal alcista o -1 para una señal bajista; de lo contrario, devuelve 0, lo que indica que no hay una configuración válida en ese momento. Este enfoque por capas combina la divergencia del impulso con la evolución del precio para mejorar la fiabilidad de las señales.

int FindSignalBar()
{
    bool bullDiv = false, bearDiv = false;
    for(int i = 5; i <= 15; i++)
    {
        // Bullish divergence condition
        if(lowBuffer[i] > lowBuffer[1] && rsiBuffer[i] < rsiBuffer[1] && rsiBuffer[1] < RSI_Oversold)
            bullDiv = true;
        // Bearish divergence condition
        if(highBuffer[i] < highBuffer[1] && rsiBuffer[i] > rsiBuffer[1] && rsiBuffer[1] > RSI_Overbought)
            bearDiv = true;
    }

    // No divergence detected
    if(!bullDiv && !bearDiv)
        return 0;

    // Check for candlestick patterns supporting divergence
    bool bullPat = IsBullishPinBar(1) || IsBullishEngulfing(1);
    bool bearPat = IsBearishPinBar(1) || IsBearishEngulfing(1);

    // Confirmed signals
    if(bullDiv && bullPat)
        return +1;
    if(bearDiv && bearPat)
        return -1;

    return 0; // No valid signal
}

6. Detección de patrones de velas japonesas para la confirmación

Estas funciones analizan las velas individuales para confirmar señales de reversión. La función IsBullishPinBar() comprueba si la vela tiene un cuerpo pequeño con una mecha inferior larga, lo que indica un rechazo de los precios más bajos —un indicio de reversión alcista—. IsBearishPinBar() hace lo contrario. IsBullishEngulfing() confirma si el cuerpo de la vela actual envuelve al de la anterior, lo que indica una fuerte presión compradora, mientras que IsBearishEngulfing() indica una fuerte presión vendedora. Estas funciones de detección de patrones utilizan medidas proporcionales de los cuerpos y las mechas de las velas en relación con su rango de máximos y mínimos para garantizar que solo se tengan en cuenta los patrones bien formados, lo que reduce los falsos positivos y aumenta la fiabilidad de las señales.

// Bullish Pin Bar Pattern
bool IsBullishPinBar(int i)
{
    double body = MathAbs(openBuffer[i] - closeBuffer[i]);
    double rng  = highBuffer[i] - lowBuffer[i];
    double lw   = MathMin(openBuffer[i], closeBuffer[i]) - lowBuffer[i];
    double uw   = highBuffer[i] - MathMax(openBuffer[i], closeBuffer[i]);
    return closeBuffer[i] > openBuffer[i]
           && lw > 2.0 * body
           && uw < 0.5 * body
           && body > 0.1 * rng;
}

// Bearish Pin Bar Pattern
bool IsBearishPinBar(int i)
{
    double body = MathAbs(openBuffer[i] - closeBuffer[i]);
    double rng  = highBuffer[i] - lowBuffer[i];
    double uw   = highBuffer[i] - MathMax(openBuffer[i], closeBuffer[i]);
    double lw   = MathMin(openBuffer[i], closeBuffer[i]) - lowBuffer[i];
    return closeBuffer[i] < openBuffer[i]
           && uw > 2.0 * body
           && lw < 0.5 * body
           && body > 0.1 * rng;
}

// Bullish Engulfing Pattern
bool IsBullishEngulfing(int i)
{
    if(closeBuffer[i] <= openBuffer[i])
        return false;
    if(openBuffer[i] > closeBuffer[i+1])
        return false;
    if(closeBuffer[i] < openBuffer[i+1])
        return false;
    return true;
}

// Bearish Engulfing Pattern
bool IsBearishEngulfing(int i)
{
    if(closeBuffer[i] >= openBuffer[i])
        return false;
    if(openBuffer[i] < closeBuffer[i+1])
        return false;
    if(closeBuffer[i] > openBuffer[i+1])
        return false;
    return true;
}

7. Visualización y generación de alertas

Una vez confirmados un patrón válido y una divergencia, DrawSignal() visualiza la configuración trazando flechas en los puntos de entrada, líneas horizontales para los niveles de entrada y de stop-loss, y líneas de tendencia que ilustran el patrón de divergencia. El color y el código de la flecha indican la dirección: verde para las tendencias alcistas y rojo para las bajistas. Las líneas de tendencia conectan los mínimos o máximos recientes para confirmar visualmente la divergencia.

Esta función también genera un mensaje de alerta detallado que incluye el tipo de patrón, el lado, el símbolo, la hora, el punto de entrada y los niveles de stop-loss. A continuación, activa notificaciones (reproduciendo un sonido, enviando notificaciones push o correos electrónicos) según las preferencias del usuario, lo que garantiza que el operador esté informado de inmediato y pueda actuar con rapidez. Este completo sistema de visualización y alerta mejora el conocimiento de la situación y la toma de decisiones.

void DrawSignal(int i, bool isBullish, double entry, double stopL)
{
    string tag = TimeToString(timeBuffer[i], TIME_SECONDS);
    string nameA = "Arr_" + tag;
    string nameE = "Ent_" + tag;
    string nameS = "SL_" + tag;
    string nameL = "Div_" + tag;

    color clrArr = isBullish ? clrLime : clrRed;
    int code = isBullish ? 233 : 234;

    // Arrow at entry point
    ObjectCreate(0, nameA, OBJ_ARROW, 0, timeBuffer[i], entry);
    ObjectSetInteger(0, nameA, OBJPROP_COLOR, clrArr);
    ObjectSetInteger(0, nameA, OBJPROP_ARROWCODE, code);
    ObjectSetInteger(0, nameA, OBJPROP_WIDTH, 2);

    // Horizontal lines for entry and stop-loss
    ObjectCreate(0, nameE, OBJ_HLINE, 0, 0, entry);
    ObjectSetInteger(0, nameE, OBJPROP_COLOR, clrAqua);
    ObjectCreate(0, nameS, OBJ_HLINE, 0, 0, stopL);
    ObjectSetInteger(0, nameS, OBJPROP_COLOR, clrOrangeRed);
    ObjectSetInteger(0, nameS, OBJPROP_STYLE, STYLE_DASH);

    // Divergence trend line for visual confirmation
    for(int j = i + 5; j < i + 15; j++)
    {
        if(isBullish && lowBuffer[j] > lowBuffer[i])
        {
            ObjectCreate(0, nameL, OBJ_TREND, 0,
                         timeBuffer[j], lowBuffer[j],
                         timeBuffer[i], lowBuffer[i]);
            ObjectSetInteger(0, nameL, OBJPROP_COLOR, clrDodgerBlue);
            break;
        }
        if(!isBullish && highBuffer[j] < highBuffer[i])
        {
            ObjectCreate(0, nameL, OBJ_TREND, 0,
                         timeBuffer[j], highBuffer[j],
                         timeBuffer[i], highBuffer[i]);
            ObjectSetInteger(0, nameL, OBJPROP_COLOR, clrOrange);
            break;
        }
    }

    // Construct alert message
    string pattern = isBullish
                     ? (IsBullishEngulfing(i) ? "Engulfing" : "PinBar")
                     : (IsBearishEngulfing(i) ? "Engulfing" : "PinBar");
    string side = isBullish ? "Buy" : "Sell";
    string txt = StringFormat(
                     "%s + RSI Divergence %s Signal\nSymbol: %s\nTime: %s\nEntry: %.5f\nSL: %.5f",
                     pattern, side, _Symbol,
                     TimeToString(timeBuffer[i], TIME_MINUTES),
                     entry, stopL
                 );

    // Notify trader
    Alert(txt);
    if(EnableSound)
        PlaySound("alert.wav");
    if(EnablePush)
        SendNotification(txt);
    if(EnableEmail)
        SendMail("Signal EA Alert", txt);

    Print(txt);
}

EA completo para MQL5

//+------------------------------------------------------------------+
//|                                           Multi-Pattern Signal EA|
//|                                   Copyright 2025, MetaQuotes Ltd.|
//|                           https://www.mql5.com/en/users/lynnchris|
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link      "https://www.mql5.com/en/users/lynnchris"
#property version   "1.0"
#property strict

#include <Trade/Trade.mqh>

input int    RSI_Period     = 14;
input double RSI_Overbought = 70.0;
input double RSI_Oversold   = 30.0;
input double SL_Pips        = 20.0;  // in pips
input double TP_Pips        = 20.0;  // in pips
input double EntryBuffer    = 5.0;   // in points
input bool   EnableSound    = true;
input bool   EnablePush     = true;
input bool   EnableEmail    = false;

CTrade   trade;

// internal buffers
double   rsiBuffer[];
datetime timeBuffer[];
double   openBuffer[], highBuffer[], lowBuffer[], closeBuffer[];
int      rsiHandle;
datetime lastBarTime = 0;

//+------------------------------------------------------------------+
int OnInit()
  {
   rsiHandle = iRSI(_Symbol, _Period, RSI_Period, PRICE_CLOSE);
   if(rsiHandle == INVALID_HANDLE)
      return INIT_FAILED;

   ArraySetAsSeries(rsiBuffer,   true);
   ArraySetAsSeries(timeBuffer,  true);
   ArraySetAsSeries(openBuffer,  true);
   ArraySetAsSeries(highBuffer,  true);
   ArraySetAsSeries(lowBuffer,   true);
   ArraySetAsSeries(closeBuffer, true);

   return INIT_SUCCEEDED;
  }

//+------------------------------------------------------------------+
void OnTick()
  {
   if(Bars(_Symbol,_Period) < 20)
      return;

   if(CopyTime(_Symbol,_Period,0,20,timeBuffer)   <= 0 ||
      CopyOpen(_Symbol,_Period,0,20,openBuffer)   <= 0 ||
      CopyHigh(_Symbol,_Period,0,20,highBuffer)   <= 0 ||
      CopyLow(_Symbol,_Period,0,20,lowBuffer)     <= 0 ||
      CopyClose(_Symbol,_Period,0,20,closeBuffer) <= 0)
      return;

   if(timeBuffer[1] == lastBarTime)
      return;
   lastBarTime = timeBuffer[1];

   if(CopyBuffer(rsiHandle,0,0,20,rsiBuffer) <= 0)
      return;

   int dir = FindSignalBar();
   if(dir == 0)
      return;

   int idx = 1;
   bool isBullish = (dir > 0);

   double entry = isBullish
                  ? highBuffer[idx] + EntryBuffer * _Point
                  : lowBuffer[idx]  - EntryBuffer * _Point;
   double stopL = isBullish
                  ? lowBuffer[idx]  - SL_Pips * _Point
                  : highBuffer[idx] + SL_Pips * _Point;

   DrawSignal(idx, isBullish, entry, stopL);
  }

//+------------------------------------------------------------------+
int FindSignalBar()
  {
   bool bullDiv = false, bearDiv = false;
   for(int i = 5; i <= 15; i++)
     {
      if(lowBuffer[i] > lowBuffer[1] && rsiBuffer[i] < rsiBuffer[1] && rsiBuffer[1] < RSI_Oversold)
         bullDiv = true;
      if(highBuffer[i] < highBuffer[1] && rsiBuffer[i] > rsiBuffer[1] && rsiBuffer[1] > RSI_Overbought)
         bearDiv = true;
     }
   if(!bullDiv && !bearDiv)
      return 0;

   bool bullPat = IsBullishPinBar(1) || IsBullishEngulfing(1);
   bool bearPat = IsBearishPinBar(1) || IsBearishEngulfing(1);

   if(bullDiv && bullPat)
      return +1;
   if(bearDiv && bearPat)
      return -1;
   return 0;
  }

//+------------------------------------------------------------------+
bool IsBullishPinBar(int i)
  {
   double body = MathAbs(openBuffer[i] - closeBuffer[i]);
   double rng  = highBuffer[i] - lowBuffer[i];
   double lw   = MathMin(openBuffer[i], closeBuffer[i]) - lowBuffer[i];
   double uw   = highBuffer[i] - MathMax(openBuffer[i], closeBuffer[i]);
   return closeBuffer[i] > openBuffer[i]
          && lw > 2.0 * body
          && uw < 0.5 * body
          && body > 0.1 * rng;
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool IsBearishPinBar(int i)
  {
   double body = MathAbs(openBuffer[i] - closeBuffer[i]);
   double rng  = highBuffer[i] - lowBuffer[i];
   double uw   = highBuffer[i] - MathMax(openBuffer[i], closeBuffer[i]);
   double lw   = MathMin(openBuffer[i], closeBuffer[i]) - lowBuffer[i];
   return closeBuffer[i] < openBuffer[i]
          && uw > 2.0 * body
          && lw < 0.5 * body
          && body > 0.1 * rng;
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool IsBullishEngulfing(int i)
  {
   if(closeBuffer[i] <= openBuffer[i])
      return false;
   if(openBuffer[i]  > closeBuffer[i+1])
      return false;
   if(closeBuffer[i] < openBuffer[i+1])
      return false;
   return true;
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool IsBearishEngulfing(int i)
  {
   if(closeBuffer[i] >= openBuffer[i])
      return false;
   if(openBuffer[i]  < closeBuffer[i+1])
      return false;
   if(closeBuffer[i] > openBuffer[i+1])
      return false;
   return true;
  }

//+------------------------------------------------------------------+
void DrawSignal(int i, bool isBullish, double entry, double stopL)
  {
   string tag   = TimeToString(timeBuffer[i], TIME_SECONDS);
   string nameA = "Arr_" + tag;
   string nameE = "Ent_" + tag;
   string nameS = "SL_"  + tag;
   string nameL = "Div_" + tag;

   color clrArr = isBullish ? clrLime : clrRed;
   int   code   = isBullish ? 233 : 234;

   ObjectCreate(0, nameA, OBJ_ARROW, 0, timeBuffer[i], entry);
   ObjectSetInteger(0, nameA, OBJPROP_COLOR, clrArr);
   ObjectSetInteger(0, nameA, OBJPROP_ARROWCODE, code);
   ObjectSetInteger(0, nameA, OBJPROP_WIDTH, 2);

   ObjectCreate(0, nameE, OBJ_HLINE, 0, 0, entry);
   ObjectSetInteger(0, nameE, OBJPROP_COLOR, clrAqua);
   ObjectCreate(0, nameS, OBJ_HLINE, 0, 0, stopL);
   ObjectSetInteger(0, nameS, OBJPROP_COLOR, clrOrangeRed);
   ObjectSetInteger(0, nameS, OBJPROP_STYLE, STYLE_DASH);

   for(int j = i + 5; j < i + 15; j++)
     {
      if(isBullish && lowBuffer[j] > lowBuffer[i])
        {
         ObjectCreate(0, nameL, OBJ_TREND, 0,
                      timeBuffer[j], lowBuffer[j],
                      timeBuffer[i], lowBuffer[i]);
         ObjectSetInteger(0, nameL, OBJPROP_COLOR, clrDodgerBlue);
         break;
        }
      if(!isBullish && highBuffer[j] < highBuffer[i])
        {
         ObjectCreate(0, nameL, OBJ_TREND, 0,
                      timeBuffer[j], highBuffer[j],
                      timeBuffer[i], highBuffer[i]);
         ObjectSetInteger(0, nameL, OBJPROP_COLOR, clrOrange);
         break;
        }
     }

   string pattern = isBullish
                    ? (IsBullishEngulfing(i) ? "Engulfing" : "PinBar")
                    : (IsBearishEngulfing(i) ? "Engulfing" : "PinBar");
   string side    = isBullish ? "Buy" : "Sell";
   string txt     = StringFormat(
                       "%s + RSI Divergence %s Signal\nSymbol: %s\nTime: %s\nEntry: %.5f\nSL: %.5f",
                       pattern, side, _Symbol,
                       TimeToString(timeBuffer[i], TIME_MINUTES),
                       entry, stopL
                    );

   Alert(txt);
   if(EnableSound)
      PlaySound("alert.wav");
   if(EnablePush)
      SendNotification(txt);
   if(EnableEmail)
      SendMail("Signal EA Alert", txt);
   Print(txt);
  }
//+------------------------------------------------------------------+


Backtesting y resultados

El backtesting es un proceso que consiste en evaluar una estrategia de negociación utilizando datos históricos del mercado para estimar cuál habría sido su rendimiento en el pasado. Esta simulación permite a los operadores ver cómo habrían funcionado sus reglas predefinidas en condiciones reales de mercado, lo que les ofrece una visión de la rentabilidad y los riesgos potenciales. Al analizar los resultados de estas operaciones simuladas, los operadores pueden tomar decisiones fundamentadas sobre si aplicar la estrategia en operaciones reales.

El primer paso para realizar un backtesting es definir claramente la estrategia de negociación. Esto implica establecer reglas específicas para entrar y salir de las operaciones, incluyendo los indicadores, los patrones de precios u otras condiciones que activarán señales de compra o venta. Una estrategia bien definida garantiza la realización de pruebas sistemáticas y la obtención de resultados precisos. A continuación, los operadores deben recopilar datos históricos relevantes, como gráficos de precios, volumen y otra información pertinente correspondiente al periodo que deseen analizar. Para obtener resultados fiables en las pruebas retrospectivas, es fundamental disponer de datos precisos y exhaustivos.

Es fundamental elegir la plataforma de backtesting adecuada. Existen diversas herramientas de software disponibles, algunas que permiten el análisis manual y otras que admiten pruebas totalmente automatizadas. La plataforma elegida debe ser capaz de simular con precisión las operaciones basándose en las reglas de su estrategia y de proporcionar métricas detalladas de rendimiento. Una vez seleccionada la plataforma, el operador debe configurar el entorno de backtesting. Esto incluye la configuración de parámetros como los timeframes, los costes de transacción, el slippage y otros factores que pueden influir en el rendimiento, garantizando que la simulación refleje las condiciones reales de negociación con la mayor fidelidad posible.

Tras la configuración inicial, el siguiente paso es aplicar la estrategia ejecutando la prueba retrospectiva. La plataforma genera entonces operaciones simuladas de acuerdo con las reglas predefinidas y los datos históricos del mercado. Durante este proceso, es importante analizar los resultados minuciosamente. Los indicadores clave, como el beneficio o la pérdida total, la tasa de éxito, el drawdown máximo y la relación riesgo-beneficio, proporcionan información valiosa sobre la eficacia y la solidez de la estrategia.

En función del análisis, los operadores deberían refinar y optimizar su estrategia. Los ajustes en los parámetros o las reglas pueden mejorar el rendimiento y ayudar a solucionar cualquier deficiencia detectada durante las pruebas. Para garantizar la fiabilidad de la estrategia y evitar el sobreajuste, es fundamental validarla con datos fuera de muestra. Ejecutar la estrategia refinada sobre un conjunto independiente de datos históricos ayuda a confirmar su solidez y su potencial para obtener buenos resultados en mercados reales.

A continuación se muestran los resultados de mis backtests.

Fig. 6. Confirmación de patrón envolvente alcista

La figura anterior (Fig. 6) muestra una captura de pantalla de la prueba retrospectiva del EURUSD en el marco temporal M30, que muestra un patrón envolvente alcista que fue confirmado por una divergencia alcista.

Fig. 7. Backtesting del USDCHF

La figura anterior (Fig. 7) muestra una captura de pantalla de la prueba retrospectiva del USDCHF en el marco temporal M30, que muestra un patrón envolvente alcista confirmado por una divergencia alcista. Además, a continuación se muestra un GIF que ilustra el proceso de backtesting del par USDCHF, destacando cómo se identificaron varias señales.


Conclusión

Este Asesor Experto (EA) ejemplifica un enfoque avanzado para el reconocimiento de patrones y la detección de divergencias dentro de una estrategia de trading. Al combinar indicadores técnicos como el RSI con el análisis de patrones de velas japonesas, como las pin bars y los patrones envolventes, identifica eficazmente señales de reversión de alta probabilidad. El diseño modular del EA le permite analizar datos recientes del mercado en tiempo real, generar señales visuales en el gráfico y enviar alertas oportunas, lo que lo convierte en una herramienta valiosa para los operadores que buscan entradas sistemáticas y disciplinadas. 

Los resultados de las pruebas retrospectivas demuestran que el EA puede lograr altas tasas de éxito, especialmente cuando las señales se confirman mediante múltiples criterios. Sin embargo, como ocurre con cualquier estrategia automatizada, es fundamental validar su solidez en diferentes pares de divisas y condiciones de mercado mediante pruebas fuera de la muestra. Una correcta optimización de los parámetros y una gestión eficaz del riesgo son esenciales para maximizar la rentabilidad y reducir los drawdowns. En definitiva, este asesor experto demuestra el potencial de combinar el reconocimiento de patrones con el análisis de divergencias, sentando una base sólida para una mayor integración del aprendizaje automático y la toma de decisiones inteligentes en los sistemas de negociación.


Fecha Nombre de la herramienta  Descripción Versión  Actualizaciones  Notas
01/10/24 Chart Projector Script para superponer un efecto fantasma a la evolución del precio del día anterior. 1.0 Versión inicial Herramienta número 1
18/11/24 Analytical Comment Proporciona la información del día anterior en formato tabular, además de anticipar la dirección futura del mercado. 1.0 Versión 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 Versión inicial Herramienta número 5
19/12/24 Mean Reversion Signal Reaper  Analiza el mercado utilizando una estrategia de reversión a la media y proporciona una señal.  1.0  Versión inicial  Herramienta número 6 
09/01/25  Signal Pulse  Analizador de múltiples marcos temporales 1.0  Versión inicial  Herramienta número 7 
17/01/25  Metrics Board  Panel con botón para análisis  1.0  Versión inicial Herramienta número 8 
21/01/25 External Flow Análisis a través de bibliotecas externas 1.0  Versión inicial Herramienta número 9 
27/01/25 VWAP Volume Weighted Average Price   1.3  Versión inicial  Herramienta número 10 
02/02/25  Heikin Ashi  Suavizado de tendencias e identificación de señales de reversión  1.0  Versión inicial  Herramienta número 11
04/02/25  FibVWAP  Generación de señales mediante análisis con Python  1.0  Versión inicial  Herramienta número 12
14/02/25  RSI DIVERGENCE  Divergencias entre la acción del precio y el RSI  1.0  Versión inicial  Herramienta número 13 
17/02/25  Parabolic Stop and Reverse (PSAR)  Automatización de la estrategia PSAR 1.0 Versión inicial  Herramienta número 14
20/02/25  Quarters Drawer Script  Trazar los niveles de los cuartos en el gráfico  1.0  Versión inicial  Herramienta número 15 
27/02/25  Intrusion Detector Detecta y alerta cuando el precio alcanza niveles de cuartos 1.0   Versión inicial Herramienta número 16 
27/02/25  TrendLoom Tool Panel de análisis de múltiples marcos temporales 1.0 Versión inicial Herramienta número 17
11/03/25  Quarters Board  Panel con botones para activar o desactivar los niveles de cuartos  1.0  Versión inicial Herramienta número 18
26/03/25  ZigZag Analyzer  Trazado de líneas de tendencia con el indicador ZigZag  1.0  Versión inicial  Herramienta número 19 
10/04/25  Correlation Pathfinder Representación gráfica de correlaciones monetarias mediante bibliotecas de Python 1.0 Versión inicial  Herramienta número 20 
23/04/25 Market Structure Flip Detector Tool Detección de cambios en la estructura del mercado 1.0  Versión inicial  Herramienta número 21
08/05/25  Correlation Dashboard  Relación entre diferentes pares 1.0 Versión inicial Herramienta número 22 
13/05/25 Currency Strength Meter  Medir la fortaleza de cada divisa en diferentes pares 1.0 Versión inicial Herramienta número 23 
21/05/25 PAQ Analysis Tool  Detector de formación de velas 1.0 Versión inicial Herramienta número 24 
23/05/25 Pin bar, Engulfing and RSI divergence Uso de la divergencia del RSI para confirmar las señales de los patrones de «pin bar» y «engulfing»  1.0 Versión inicial Herramienta número 25 

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

Utilizando redes neuronales en MetaTrader Utilizando redes neuronales en MetaTrader
En el artículo se muestra la aplicación de las redes neuronales en los programas de MQL, usando la biblioteca de libre difusión FANN. Usando como ejemplo una estrategia que utiliza el indicador MACD se ha construido un experto que usa el filtrado con red neuronal de las operaciones. Dicho filtrado ha mejorado las características del sistema comercial.
Análisis de las brechas temporales de precios en MQL5 (Parte I): Creando un indicador básico Análisis de las brechas temporales de precios en MQL5 (Parte I): Creando un indicador básico
El análisis de brechas temporales ayuda a los tráders a identificar posibles puntos de reversión del mercado. El artículo analiza qué es un desfase temporal, cómo interpretarlo y de qué manera se puede utilizar para detectar la inyección de un gran volumen en el mercado.
Particularidades del trabajo con números del tipo double en MQL4 Particularidades del trabajo con números del tipo double en MQL4
En estos apuntes hemos reunido consejos para resolver los errores más frecuentes al trabajar con números del tipo double en los programas en MQL4.
Algoritmo de ecolocalización de delfines — Dolphin Echolocation Algorithm (DEA) Algoritmo de ecolocalización de delfines — Dolphin Echolocation Algorithm (DEA)
En este artículo, analizaremos más de cerca el algoritmo DEA, un método de optimización metaheurística inspirado en la capacidad única de los delfines para encontrar presas mediante la ecolocalización. Desde los fundamentos matemáticos hasta la implementación práctica en MQL5, desde el análisis hasta la comparación con algunos algoritmos clásicos, examinaremos con detalle por qué este método relativamente nuevo merece un lugar en el arsenal de quienes se enfrentan a problemas de optimización.