English Русский Deutsch 日本語
preview
Introducción a MQL5 (Parte 22): Creación de un Asesor Experto para el patrón armónico 5-0

Introducción a MQL5 (Parte 22): Creación de un Asesor Experto para el patrón armónico 5-0

MetaTrader 5Sistemas comerciales |
27 2
ALGOYIN LTD
Israel Pelumi Abioye

Introducción

¡Bienvenidos de nuevo a la parte 22 de la serie Introducción a MQL5! En el artículo anterior, exploramos cómo automatizar la detección de patrones armónicos, como la formación de Gartley, en MQL5. En esta continuación, nos centraremos en otra estructura fascinante, aunque menos común, conocida como el patrón armónico 5-0. Este patrón destaca porque, a diferencia de la mayoría de las configuraciones armónicas que comienzan con un retroceso, el patrón 5-0 comienza con un fuerte movimiento contra tendencia, seguido de una corrección estructurada que ofrece valiosas oportunidades de trading.

Este artículo le enseñará cómo reconocer automáticamente el patrón 5-0 en un Asesor Experto y cómo detectarlo mediante programación. Aprenderá a determinar los puntos de inflexión principales de la estructura 5-0 (0, X, A, B, C y D), a calcular y validar las proporciones de Fibonacci específicas para ella y a representar visualmente el patrón en el gráfico. Al finalizar este artículo, sabrá cómo convertir la idea técnica subyacente al patrón 5-0 en código MQL5 funcional que pueda analizar la acción del precio automáticamente.

 

Patrón armónico 5-0

El patrón armónico 5-0 es una formación de reversión que suele aparecer tras un movimiento de precios significativo y prolongado. Se considera un patrón de continuación con transición a reversión, más que una configuración de reversión pura, e indica un posible cambio en la dirección de la tendencia. El patrón se compone de cuatro patas (XA, AB, BC y CD) formadas por los seis puntos principales: 0, X, A, B, C y D. El punto de partida y la estructura distintivos del patrón 5-0 lo diferencian de otros patrones armónicos. A diferencia de la mayoría de los patrones armónicos, que comienzan con un punto de giro, el patrón 5-0 comienza con un movimiento correctivo, que suele ocurrir después de que una tendencia o patrón anterior haya finalizado. Esto la hace destacar porque su objetivo es capturar el agotamiento de un movimiento contrario a la tendencia, en lugar del comienzo de un nuevo impulso.

El punto 0, que crea un claro máximo en el gráfico, es donde comienza el patrón alcista 5-0. El mercado cae desde este nivel hasta formar el punto X, que es el primer tramo bajista significativo de la estructura. El movimiento subsiguiente de X a A representa una corrección de esa caída. Si bien no existe un nivel de Fibonacci fijo para este retroceso, el punto A debe estar por debajo del punto 0 para indicar que la tendencia general sigue siendo bajista.

Tras el establecimiento del punto A, el mercado desciende aún más para producir el punto B, que se sitúa entre la extensión de Fibonacci del 113% y el 161,8% del tramo XA. La fase de agotamiento de la tendencia bajista actual suele estar representada por este tramo. El mercado vuelve a subir desde el punto B para formar el punto C, que normalmente representa entre el 161,8% y el 224% del tramo AB. Dentro de este patrón, este movimiento demuestra una fuerte reacción correctiva. La estructura se completa en el punto D, donde el mercado retrocede una vez más. Se recomienda que el punto D retroceda entre un 50% y un 55% del tramo BC. La posible zona de compra es esta zona de retroceso.

Figura 1: Patrón alcista 5-0

El punto 0 establece un mínimo local (swing low) claro en el gráfico e inicia el patrón bajista 5-0. El primer tramo alcista del patrón se establece cuando el mercado sube desde este punto hasta el punto X. Si bien el movimiento subsiguiente, de X a A, es un retroceso correctivo, este tramo no requiere un retroceso de Fibonacci preciso. Para garantizar que la tendencia general siga siendo positiva en la actualidad, el punto A debe ser superior al punto 0.

El punto B, que debería estar entre la extensión de Fibonacci del 113% y el 161,8% del tramo XA, se crea cuando el precio vuelve a subir después de que se forma el punto A. Por lo general, este nivel indica que la tendencia alcista ha alcanzado su límite. Posteriormente, el mercado retrocede hasta formar el punto C, que debería representar una corrección significativa del patrón y abarcar entre el 161,8 % y el 224 % del tramo AB. La estructura se completa cuando el precio vuelve a subir hasta alcanzar el punto D. Se recomienda que el punto D retroceda entre un 50 % y un 55 % del tramo BC. Esta zona de retroceso sirve como un posible punto de venta.

Figura 3: Patrón bajista 5-0


Identificando 0XAB

El siguiente paso es implementar programáticamente el patrón 5-0 en MQL5 ahora que conocemos su significado y los principios esenciales de su proporción. Esto implica poner la idea en práctica recopilando y actualizando datos de velas, identificando con precisión los puntos de inflexión, creando secuencias potenciales para 0, X, A, B, C y D, verificando cada segmento de acuerdo con los requisitos de proporción del patrón y etiquetando los patrones verificados en el gráfico.

En la práctica, seguiremos un proceso sencillo: copiaremos las barras recientes a arrays, localizaremos los puntos de giro importantes utilizando una técnica fiable de detección de oscilaciones y, a continuación, recorreremos estos pivotes para crear posibles tramos 0X, XA, AB y BC. Posteriormente, se utilizarán los criterios de extensión y retroceso de Fibonacci para verificar que los puntos B, C y D son auténticos. Si se cumplen todos los requisitos, conectaremos la lógica de detección con la ejecución de la operación y dibujaremos el patrón y los elementos gráficos de confirmación visual. Si bien la identificación del patrón armónico alcista 5-0 será el objetivo principal de este artículo, cabe destacar que, con algunas ligeras modificaciones direccionales, el mismo razonamiento y procedimiento de detección también puede utilizarse para identificar el patrón bajista 5-0.

Copiar los datos de las velas y localizar la estructura 0XAB es el primer paso para desarrollar el algoritmo de detección del patrón 5-0. Utilizando las funciones de copia integradas en MQL5, el proceso comienza con la recopilación de datos recientes del mercado, incluyendo la apertura, el cierre, el máximo, el mínimo y la hora. El programa puede acceder a los movimientos históricos de precios a través de estas matrices de datos, lo cual es crucial para identificar los máximos y mínimos significativos.

El programa utiliza una lógica de detección de oscilaciones para identificar posibles ppuntos de giro en la acción del precio una vez que se dispone de los datos. El EA utiliza estos puntos de inflexión para determinar los posibles puntos 0, X, A y B, que forman la base del patrón 5-0. Un máximo local (swing high) importante está representado por el punto 0, y un mínimo local (swing low) está representado por el punto X. Luego, el punto B se expande más allá de X de acuerdo con el rango de extensión de Fibonacci (entre el 113 % y el 161,8 % de XA), mientras que el punto A emerge como un máximo inferior al punto 0. Dado que determinan si el patrón puede avanzar hacia una formación alcista 5-0 válida cuando los puntos C y D se confirmen posteriormente, detectar correctamente estos primeros cuatro puntos es esencial.

Ejemplo:
input ENUM_TIMEFRAMES timeframe = PERIOD_CURRENT;

datetime time_bar;
int bars_check = 400;
int total_symbol_bars;

double open[];
double close[];
double low[];
double high[];
datetime time[];

int z = 4;

double O;
datetime O_time;
string O_line;
string O_letter;

double X;
datetime X_time;
string X_letter;

double A;
datetime A_time;
string A_letter;

double B;
datetime B_time;
string B_line;
string B_letter;

double C;
datetime C_time;
string C_line;
string C_letter;

double D;
datetime D_time;
string D_line;
string D_letter;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---


//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---

   total_symbol_bars = Bars(_Symbol, timeframe);
   time_bar = iTime(_Symbol, timeframe, 0);
   CopyOpen(_Symbol, timeframe, time_bar, bars_check, open);
   CopyClose(_Symbol, timeframe, time_bar, bars_check, close);
   CopyLow(_Symbol, timeframe, time_bar, bars_check, low);
   CopyHigh(_Symbol, timeframe, time_bar, bars_check, high);
   CopyTime(_Symbol, timeframe, time_bar, bars_check, time);

  }

//+------------------------------------------------------------------+
//| FUNCTION FOR SWING LOW                                           |
//+------------------------------------------------------------------+
bool IsSwingLow(const double &low_price[], int index, int lookback)
  {
   for(int i = 1; i <= lookback; i++)
     {
      if(low_price[index] > low_price[index - i] || low_price[index] > low_price[index + i])
         return false;
     }
   return true;
  }

//+------------------------------------------------------------------+
//| FUNCTION FOR SWING HIGH                                          |
//+------------------------------------------------------------------+
bool IsSwingHigh(const double &high_price[], int index, int lookback)
  {
   for(int i = 1; i <= lookback; i++)
     {
      if(high_price[index] < high_price[index - i] || high_price[index] < high_price[index + i])
         return false; // If the current high is not the highest, return false.
     }
   return true;
  }

Explicación:

input ENUM_TIMEFRAMES timeframe = PERIOD_CURRENT;

Aquí se especifica el período de tiempo del gráfico que examinará el asesor experto. Aunque por defecto utiliza el marco temporal del gráfico actual, los operadores pueden cambiarlo fácilmente para probar el EA en otros marcos temporales, incluidos M15, H1 o D1, sin modificar el código básico. 

Para gestionar los datos de las velas y la información general del gráfico, se declaran varias variables globales:

datetime time_bar;
int bars_check = 400;
int total_symbol_bars;

double open[];
double close[];
double low[];
double high[];
datetime time[];

En conjunto, estas variables almacenan datos de mercado. La variable bars_check especifica el número de barras (velas) que el EA debe examinar; en este ejemplo, las últimas 400 velas. Los datos de las velas correspondientes del gráfico se cargarán a continuación en las matrices. Estos conjuntos de datos son cruciales porque ofrecen el historial de precios a partir del cual se identificarán los máximos y mínimos de las oscilaciones.

El programa define una serie de variables para almacenar los detalles de cada punto significativo en el patrón 5-0 después de declarar los contenedores de datos fundamentales:

double O;
datetime O_time;
string O_line;
string O_letter;

double X;
datetime X_time;
string X_letter;

double A;
datetime A_time;
string A_letter;

double B;
datetime B_time;
string B_line;
string B_letter;

double C;
datetime C_time;
string C_line;
string C_letter;

double D;
datetime D_time;
string D_line;
string D_letter;

Cada punto de inflexión tiene asignada una colección única de variables. Por ejemplo, O_time registra el momento en que ocurrió el punto O, mientras que O almacena el precio del punto O. El punto se puede etiquetar y se pueden dibujar marcadores visuales en el gráfico utilizando las variables O_line y O_letter. Con los puntos de inflexión, se repite el mismo patrón. Esta estructura permite trazar el patrón completo de 5-0 una vez verificadas todas las piernas, ya que posibilita que el software registre las coordenadas de cada punto.

Para determinar los mínimos de oscilación, la función IsSwingLow analiza si el precio mínimo de un índice es inferior a los mínimos de las velas que lo rodean. El parámetro lookback regula el número de velas que se comparan antes y después de la actual. Se verifica que existe un mínimo local (swing low) si el mínimo de la vela es, de hecho, el más bajo de sus vecinas. Para identificar los puntos de inflexión que podrían crear las bases 0 o X del patrón, los mínimos de oscilación son esenciales. Dentro del rango de análisis retrospectivo especificado, la función IsSwingHigh verifica además si el máximo de una vela es superior a los máximos de las velas cercanas.

El siguiente paso tras establecer el marco fundamental para gestionar los datos de mercado e identificar los puntos de inflexión es encontrar la formación 0XAB. Para encontrar máximos y mínimos notables que se correspondan con las ondas del patrón armónico alcista 5-0, es necesario examinar los datos históricos de las velas. El punto X se reconocerá como un mínimo local (swing low) inferior, y el punto 0 como un máximo local (swing high) significativo. El punto B debe entonces extenderse más allá del punto X dentro del rango de extensión de Fibonacci del 113% al 161,8% del tramo XA, después de lo cual el punto A debería formarse como un máximo inferior debajo del punto 0.

Ejemplo:

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---

   total_symbol_bars = Bars(_Symbol, timeframe);
   time_bar = iTime(_Symbol, timeframe, 0);
   CopyOpen(_Symbol, timeframe, time_bar, bars_check, open);
   CopyClose(_Symbol, timeframe, time_bar, bars_check, close);
   CopyLow(_Symbol, timeframe, time_bar, bars_check, low);
   CopyHigh(_Symbol, timeframe, time_bar, bars_check, high);
   CopyTime(_Symbol, timeframe, time_bar, bars_check, time);

   if(total_symbol_bars >= bars_check)
     {

      for(int i = z ; i < bars_check - z; i++)
        {
         if(IsSwingHigh(high, i, z))
           {

            for(int j = i; j < bars_check - z; j++)
              {

               if(IsSwingLow(low, j, z) && low[j] < high[i])
                 {

                  X = low[j];
                  X_time = time[j];
                  X_letter = StringFormat("X  %d",j);

                  for(int a = j; a >= i; a--)
                    {
                     if(IsSwingHigh(high, a, z) && high[a] > X)
                       {

                        O = high[a];
                        O_time = time[a];
                        O_letter = StringFormat("0  %d",a);

                        for(int k = j; k < bars_check - z; k++)
                          {

                           if(IsSwingHigh(high, k, z) && high[k] > X)
                             {

                              A = high[k];
                              A_time = time[k];
                              A_letter = StringFormat("A  %d",k);

                              for(int l = k; l < bars_check - z; l++)
                                {

                                 if(IsSwingLow(low, l, z) && low[l] < X)
                                   {
                                    B = low[l];
                                    B_time = time[l];
                                    B_letter = StringFormat("B  %d",l);

                                    break;
                                   }
                                }

                              break;
                             }
                          }

                        break;
                       }
                    }

                  break;
                 }
              }
           }
        }
     }
  }

Explicación:

El programa comienza comprobando si hay suficientes barras para analizar. La búsqueda no se inicia si hay menos barras disponibles en total de las necesarias para el análisis. Esto es similar a asegurarse de que la estantería esté bien surtida antes de buscar una secuencia, porque si no, se puede llegar a la conclusión demasiado rápido y perderse todo el patrón.

Luego comienza a buscar un primer máximo en el gráfico. Para determinar si una barra en una ubicación específica es un máximo local, el bucle externo comprueba cada barra utilizando la función IsSwingHigh(). Ese lugar se convierte en un posible punto de partida para la estructura 5-0 cuando se cumple este requisito.

El programa busca un mínimo local (swing low) que pueda utilizarse como punto X tras identificar un máximo local (swing high). Para ello se utiliza otro bucle que comienza en el máximo y recorre las barras buscando una posición baja que sea inferior al máximo anterior. Cuando se cumplen los criterios, el precio más bajo, la marca de tiempo y la etiqueta para la visualización del gráfico se almacenan en la variable X. Has marcado el siguiente libro en tu secuencia potencial después de encontrar uno más corto un poco más abajo en el estante que el más alto.

El algoritmo localiza el punto correcto 0 retrocediendo desde X después de detectarlo. Para encontrar el pico más alto que esté por encima de X, invierte el escaneo entre X y el máximo inicial. Una vez registrados su precio, fecha y etiqueta, el primer pico descubierto se convierte en el punto 0. La búsqueda se realiza hacia atrás para asegurar que el punto 0 sea el máximo más reciente anterior a X.

Tras identificar los puntos 0 y X, el algoritmo procede una vez más a encontrar el punto A. Cuando el siguiente máximo oscilatorio cruza X, lo busca y lo marca como A. El punto A marca el inicio de un nuevo repunte de precios dentro del patrón en evolución, al representar un nuevo pico tras la caída inicial. Esto indica que tu serie aún se está formando según el patrón alternativo previsto, de forma similar a cuando ves un libro de altura moderada después del corto en el ejemplo de la estantería.

La siguiente etapa consiste en encontrar el punto B. Para encontrar un mínimo oscilante que caiga por debajo de X, el código continúa escaneando hacia adelante después de A. El precio, el tiempo y la etiqueta de dicha barra se registran como B cuando se encuentra. El código marca entonces B como el último punto de la secuencia 0XAB y deja de buscar más niveles bajos. La agrupación de cuatro libros que caracteriza la estructura inicial del patrón 5-0 ya está completa, puesto que has descubierto otro libro pequeño que está incluso más abajo que el anterior en la metáfora de la estantería.

Los bucles internos de esta secuencia emplean comandos break para finalizar cuando se alcanza un punto válido. Esto permite que la detección sea específica y eficaz, al garantizar que el algoritmo no genere muchos conjuntos superpuestos de la misma región. Cuando hayas reunido una pila de libros que cumpla con las normas de altura y orden, deja de revisar esa sección y pasa a la siguiente. El programa localiza y guarda correctamente los cuatro primeros puntos cruciales, 0, X, A y B, junto con sus tiempos y etiquetas después de estos bucles anidados.

Como ya mencioné, el máximo local (swing high) A, que es un retroceso de 0X, debe ser mayor que X y menor que 0, y el máximo local (swing high) 0 debe ser mayor que X. Sin embargo, para A, no es necesario ningún porcentaje de retroceso de Fibonacci en particular. El punto B debe estar comprendido entre los niveles de extensión de Fibonacci del tramo XA, que son del 113,0% y del 161,8%. Se supone que debemos crear un objeto en el gráfico para identificar y expresar visualmente el desarrollo de este patrón una vez que el algoritmo haya verificado estas condiciones.

Ejemplo:

input ENUM_TIMEFRAMES timeframe = PERIOD_CURRENT;
input double b_xa_max = 161.8; // MAX B EXTENSION LEVEL FOR XA
input double b_xa_min = 113.0; // MIN B EXTENSION LEVEL FOR XA
double fib_ext_b_161;
double fib_ext_b_113;
string fib_xa_ext_obj;
string fib_xa_ext_lvl;

string ox_line;
string xa_line;
string ab_line;
ulong chart_id = ChartID();
for(int l = k; l < bars_check - z; l++)
  {

   if(IsSwingLow(low, l, z) && low[l] < X)
     {

      B = low[l];
      B_time = time[l];
      B_letter = StringFormat("B  %d",l);

      fib_ext_b_113 =  MathAbs((((A - X) / 100) * (b_xa_min - 100)) - X);
      fib_ext_b_161 =   MathAbs((((A - X) / 100) * (b_xa_max - 100)) - X);

      if(X < O && A > X && A < O && B <= fib_ext_b_113 && B >= fib_ext_b_161)
        {

         ObjectCreate(chart_id,O_letter,OBJ_TEXT,0,O_time,O);
         ObjectSetString(chart_id,O_letter,OBJPROP_TEXT,"0");
         ObjectSetInteger(chart_id,O_letter,OBJPROP_COLOR,clrBlue);

         ObjectCreate(chart_id,X_letter,OBJ_TEXT,0,X_time,X);
         ObjectSetString(chart_id,X_letter,OBJPROP_TEXT,"X");
         ObjectSetInteger(chart_id,X_letter,OBJPROP_COLOR,clrBlue);

         ObjectCreate(chart_id,A_letter,OBJ_TEXT,0,A_time,A);
         ObjectSetString(chart_id,A_letter,OBJPROP_TEXT,"A");
         ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,clrBlue);

         ObjectCreate(chart_id,B_letter,OBJ_TEXT,0,B_time,B);
         ObjectSetString(chart_id,B_letter,OBJPROP_TEXT,"B");
         ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,clrBlue);

         ox_line = StringFormat("0X Line  %d",i);
         xa_line = StringFormat("XA Line  %d",i);
         ab_line = StringFormat("AB Line  %d",i);

         ObjectCreate(chart_id,ox_line,OBJ_TREND,0, O_time, O,X_time,X);
         ObjectSetInteger(chart_id,ox_line,OBJPROP_COLOR,clrBlue);

         ObjectCreate(chart_id,xa_line,OBJ_TREND,0, X_time, X,A_time,A);
         ObjectSetInteger(chart_id,xa_line,OBJPROP_COLOR,clrBlue);

         ObjectCreate(chart_id,ab_line,OBJ_TREND,0, A_time, A,B_time,B);
         ObjectSetInteger(chart_id,ab_line,OBJPROP_COLOR,clrBlue);

         fib_xa_ext_obj = StringFormat("XA Expansion  %d",i);
         ObjectCreate(chart_id,fib_xa_ext_obj,OBJ_EXPANSION,0,A_time,A,X_time,X,A_time,A);
         ObjectSetInteger(chart_id,fib_xa_ext_obj,OBJPROP_COLOR,clrBlue);
         for(int i = 0; i <= 2; i++)
           {

            ObjectSetInteger(chart_id,fib_xa_ext_obj,OBJPROP_LEVELCOLOR,i,clrBlue);

           }

         fib_xa_ext_lvl = StringFormat("XA Expansion Levels %d",i);

         ObjectCreate(chart_id,fib_xa_ext_lvl,OBJ_RECTANGLE,0,X_time,fib_ext_b_113,B_time,fib_ext_b_161);
         ObjectSetInteger(chart_id,fib_xa_ext_lvl,OBJPROP_COLOR,clrBlue);

        }

      break;
     }
  }

Resultado:

Figura 3: 0XAB

Explicación:

El código primero declara algunas variables de entrada. El programa utilizará automáticamente el mismo período de tiempo que el gráfico al que se aplica. A continuación, el rango de extensión de Fibonacci del segmento XA se representa mediante dos entradas. Para que el patrón sea válido, el punto B debe estar dentro del rango definido por estos valores.

A continuación se declaran variables para almacenar los valores calculados y los nombres de los objetos. Los niveles de precios de extensión de Fibonacci calculados que corresponden al 113% y al 161,8% de XA se almacenarán posteriormente en las variables fib_ext_b_113 y fib_ext_b_161. Los distintos componentes gráficos que se representarán en el gráfico para ilustrar el patrón identificado se nombran utilizando las variables fib_xa_ext_obj, fib_xa_ext_lvl, ox_line, xa_line y ab_line. Para garantizar que todas las actividades de dibujo se realicen en la ventana de gráfico adecuada, la variable chart_id obtiene el ID del gráfico activo.

Tras declarar estas variables, el programa calcula los niveles de extensión de Fibonacci utilizando las correlaciones matemáticas entre los puntos A y X. Determina los precios que coinciden con las extensiones del 113 % y el 161,8 % de XA. Considere medir la separación entre los puntos X y A en un estante para comprender mejor este fenómeno. El primer segmento XA está representado por la distancia base (100%), y la extensión del siguiente punto más allá de ella está representada por las extensiones del 113% y del 161,8%. Para que el patrón sea legítimo, el punto B debe estar dentro de este rango permitido, según lo determinado por estos niveles calculados.

En la siguiente línea de código se introduce una instrucción condicional que garantiza que se cumplan todas las relaciones geométricas y de Fibonacci necesarias del patrón 5-0. Mantiene la estructura de precios bajista a alcista determinando si el punto X está por debajo del punto 0. Además, confirma que el punto A se mantiene dentro de una zona de retroceso legítima al retroceder hacia arriba desde X sin sobrepasar el punto 0. Por último, verifica que el punto B se encuentra dentro del rango de 113% y 161,8% de XA, que es el rango de extensión de Fibonacci permitido.

Una vez que se hayan cumplido todos estos requisitos, el algoritmo dibujará la estructura identificada en el gráfico. Comienza etiquetando los ppuntos de giro importantes (0, X, A y B) con objetos de texto. Para que sean fácilmente visibles, cada elemento de texto tiene un color azul. Estas designaciones facilitan a los operadores la identificación de la estructura esencial del patrón.

El código etiqueta las ubicaciones y luego conecta 0X, XA y AB con líneas de tendencia. El movimiento de las fluctuaciones de precios que sirven de base para el patrón 5-0 está representado gráficamente por cada una de estas líneas. La designación de cada línea (como "Línea 0X" o "Línea XA") garantiza que cada elemento del gráfico permanezca distinto y sea fácil de reconocer.

Posteriormente, se proyectan visualmente las posibles zonas de extensión entre los segmentos XA utilizando la herramienta de extensión de Fibonacci. Esta expansión refuerza el vínculo que establece la veracidad del punto B, al demostrar a los operadores hasta dónde pudo haberse extendido el precio más allá de XA. Por último, para enfatizar visualmente el área entre los niveles de extensión del 113 % y el 161,8 %, se dibuja un objeto rectangular. Esta área rectangular ilustra claramente la formación prevista del punto B, actuando como una sección resaltada del estante. El punto B puede ayudarle a verificar visualmente la configuración armónica en sus gráficos, indicando una zona de extensión adecuada para el posible patrón 5-0 si este se encuentra dentro de este rango.


Identificación de C

Al encontrar los puntos C y D, se completará la estructura del patrón 5-0 una vez que se hayan localizado correctamente los puntos 0, X, A y B. Estos dos puntos son esenciales porque determinan si la configuración detectada se convierte en una formación armónica legítima. Dependiendo de cómo responda el precio a B, el punto C puede formarse como una extensión o un retroceso del tramo AB. En este contexto, se espera que C se sitúe entre el 161,8% y el 224% de la extensión de Fibonacci de AB en el caso del patrón bajista 5-0. Esto indica que el precio debería moverse más allá del final de AB aproximadamente entre 1,618 y 2,24 veces la distancia de AB una vez que llegue al punto B.

Dicho de otro modo, piensa en la pata AB como una sección de un estante. Cuando el precio supera B, lo que sucede es colocar un nuevo libro (C) más adelante en ese estante, ni demasiado cerca de B (menos del 161,8%) ni demasiado lejos (más del 224%). Esta zona, que indica que el mercado se ha expandido lo suficiente como para mantener el equilibrio armónico sin sobrepasarlo, es el lugar ideal para que llegue C.

Una vez identificado el punto C, la estructura se completará determinando el punto D como un retroceso del tramo BC. Para verificar la configuración bajista 5-0 antes de aplicar cualquier lógica de confirmación de operación o alerta, es necesario que tanto C como D estén correctamente alineados para que el patrón conserve su simetría armónica.

Ejemplo:

input double c_ab_max = 224.0; // MAX C EXTENSION LEVEL FOR AB
input double c_ab_min = 161.8; // MIN C EXTENSION LEVEL FOR AB
double fib_ext_c_161;
double fib_ext_c_224;
string fib_ab_ext_obj;
string fib_ab_ext_lvl;
string bc_line;

if(total_symbol_bars >= bars_check)
  {
   for(int i = z ; i < bars_check - z; i++)
     {
      if(IsSwingHigh(high, i, z))
        {
         for(int j = i; j < bars_check - z; j++)
           {
            if(IsSwingLow(low, j, z) && low[j] < high[i])
              {
               X = low[j];
               X_time = time[j];
               X_letter = StringFormat("X  %d",j);

               for(int a = j; a >= i; a--)
                 {
                  if(IsSwingHigh(high, a, z) && high[a] > X)
                    {
                     O = high[a];
                     O_time = time[a];
                     O_letter = StringFormat("0  %d",a);

                     for(int k = j; k < bars_check - z; k++)
                       {

                        if(IsSwingHigh(high, k, z) && high[k] > X)
                          {
                           A = high[k];
                           A_time = time[k];
                           A_letter = StringFormat("A  %d",k);

                           for(int l = k; l < bars_check - z; l++)
                             {

                              if(IsSwingLow(low, l, z) && low[l] < X)
                                {
                                 B = low[l];
                                 B_time = time[l];
                                 B_letter = StringFormat("B  %d",l);

                                 for(int m = l; m < bars_check - z; m++)
                                   {

                                    if(IsSwingHigh(high, m, z) && high[m] > A)
                                      {

                                       C = high[m];
                                       C_time = time[m];
                                       C_letter = StringFormat("C  %d",m);

                                       fib_ext_b_113 =  MathAbs((((A - X) / 100) * (b_xa_min - 100)) - X);
                                       fib_ext_b_161 =   MathAbs((((A - X) / 100) * (b_xa_max - 100)) - X);

                                       fib_ext_c_161 = MathAbs((((A - B) / 100) * (c_ab_min - 100)) + A);
                                       fib_ext_c_224 =    MathAbs((((A - B) / 100) * (c_ab_max - 100)) + A);

                                       if(X < O && A > X && A < O && B <= fib_ext_b_113 && B >= fib_ext_b_161 && C >= fib_ext_c_161 && C <= fib_ext_c_224)
                                         {
                                          ObjectCreate(chart_id,O_letter,OBJ_TEXT,0,O_time,O);
                                          ObjectSetString(chart_id,O_letter,OBJPROP_TEXT,"0");
                                          ObjectSetInteger(chart_id,O_letter,OBJPROP_COLOR,clrBlue);

                                          ObjectCreate(chart_id,X_letter,OBJ_TEXT,0,X_time,X);
                                          ObjectSetString(chart_id,X_letter,OBJPROP_TEXT,"X");
                                          ObjectSetInteger(chart_id,X_letter,OBJPROP_COLOR,clrBlue);

                                          ObjectCreate(chart_id,A_letter,OBJ_TEXT,0,A_time,A);
                                          ObjectSetString(chart_id,A_letter,OBJPROP_TEXT,"A");
                                          ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,clrBlue);

                                          ObjectCreate(chart_id,B_letter,OBJ_TEXT,0,B_time,B);
                                          ObjectSetString(chart_id,B_letter,OBJPROP_TEXT,"B");
                                          ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,clrBlue);

                                          ox_line = StringFormat("0X Line  %d",i);
                                          xa_line = StringFormat("XA Line  %d",i);
                                          ab_line = StringFormat("AB Line  %d",i);

                                          ObjectCreate(chart_id,ox_line,OBJ_TREND,0, O_time, O,X_time,X);
                                          ObjectSetInteger(chart_id,ox_line,OBJPROP_COLOR,clrBlue);

                                          ObjectCreate(chart_id,xa_line,OBJ_TREND,0, X_time, X,A_time,A);
                                          ObjectSetInteger(chart_id,xa_line,OBJPROP_COLOR,clrBlue);

                                          ObjectCreate(chart_id,ab_line,OBJ_TREND,0, A_time, A,B_time,B);
                                          ObjectSetInteger(chart_id,ab_line,OBJPROP_COLOR,clrBlue);

                                          fib_xa_ext_obj = StringFormat("XA Expansion  %d",i);
                                          ObjectCreate(chart_id,fib_xa_ext_obj,OBJ_EXPANSION,0,A_time,A,X_time,X,A_time,A);
                                          ObjectSetInteger(chart_id,fib_xa_ext_obj,OBJPROP_COLOR,clrBlue);
                                          for(int i = 0; i <= 2; i++)
                                            {
                                             ObjectSetInteger(chart_id,fib_xa_ext_obj,OBJPROP_LEVELCOLOR,i,clrBlue);
                                            }

                                          fib_xa_ext_lvl = StringFormat("XA Expansion Levels %d",i);

                                          ObjectCreate(chart_id,fib_xa_ext_lvl,OBJ_RECTANGLE,0,X_time,fib_ext_b_113,B_time,fib_ext_b_161);
                                          ObjectSetInteger(chart_id,fib_xa_ext_lvl,OBJPROP_COLOR,clrBlue);

                                          ObjectCreate(chart_id,C_letter,OBJ_TEXT,0,C_time,C);
                                          ObjectSetString(chart_id,C_letter,OBJPROP_TEXT,"C");
                                          ObjectSetInteger(chart_id,C_letter,OBJPROP_COLOR,clrBlue);

                                          bc_line = StringFormat("BC Line  %d",i);
                                          ObjectCreate(chart_id,bc_line,OBJ_TREND,0, B_time, B,C_time,C);
                                          ObjectSetInteger(chart_id,bc_line,OBJPROP_COLOR,clrBlue);

                                          fib_ab_ext_obj = StringFormat("AB Expansion  %d",i);
                                          ObjectCreate(chart_id,fib_ab_ext_obj,OBJ_EXPANSION,0,B_time,B,A_time,A,B_time,B);
                                          ObjectSetInteger(chart_id,fib_ab_ext_obj,OBJPROP_COLOR,clrBlue);
                                          for(int i = 0; i <= 2; i++)
                                            {

                                             ObjectSetInteger(chart_id,fib_ab_ext_obj,OBJPROP_LEVELCOLOR,i,clrBlue);

                                            }

                                          fib_ab_ext_lvl = StringFormat("AB Expansion Levels %d",i);

                                          ObjectCreate(chart_id,fib_ab_ext_lvl,OBJ_RECTANGLE,0,A_time,fib_ext_c_161,C_time,fib_ext_c_224);
                                          ObjectSetInteger(chart_id,fib_ab_ext_lvl,OBJPROP_COLOR,clrBlue);

                                         }

                                       break;
                                      }
                                   }
                                 break;
                                }
                             }
                           break;
                          }
                       }
                     break;
                    }
                 }
               break;
              }
           }
        }
     }
  }

Resultado:

Figura 4. C

Explicación:

Para evitar que el punto C se extienda demasiado más allá de la distancia AB, el nivel máximo de extensión de Fibonacci permitido para el tramo AB se establece en un 224%. Para evitar que el punto C se forme demasiado cerca del punto B, el nivel mínimo de extensión de Fibonacci también se establece en 161,8%. La zona de precios legítima en la que se prevé que se produzca el punto C se define por la suma de estos dos niveles. Además, hay varias variables listas para su cálculo y visualización. Para mejorar la claridad de la estructura del patrón, crean la línea de tendencia que conecta los puntos B y C, guardan los niveles de extensión de Fibonacci calculados y controlan la expansión de Fibonacci y su representación visual correspondiente en el gráfico.

El programa registra el precio, la hora y la etiqueta como referencia cuando detecta un posible máximo que cumple con los criterios del punto C. Para verificar el rango legítimo del punto B y determinar la zona de precios prevista para el punto C, se recalculan los niveles de extensión de Fibonacci. Estos cálculos determinan los umbrales de extensión del 161,8 % y del 224 % que especifican dónde debería aparecer idealmente el punto C, dependiendo de la diferencia entre los puntos A y B. El Asesor Experto puede verificar, mediante este procedimiento, si el cambio detectado se encuentra dentro de los límites permitidos del patrón 5-0.

A continuación, el programa utiliza una instrucción condicional para determinar si todos los puntos del patrón coinciden correctamente. A es mayor que X pero menor que O, B está entre el 113% y el 161,8% de XA, y C está entre el 161,8% y el 224% de la extensión de Fibonacci de AB. Confirma que X es menor que O. Se confirma una estructura 0XABC legítima para un posible patrón alcista 5-0 cuando se cumplen todas estas reglas geométricas y de Fibonacci.

El EA representa gráficamente el patrón en el gráfico una vez que se cumple este requisito. Tras crear una etiqueta de texto para C y dibujar una línea que une B y C, se muestra la zona de extensión para C añadiendo un rectángulo y un objeto de expansión de Fibonacci. El rectángulo muestra a los operadores la posición exacta en la que se ha formado el punto C en relación con AB, destacando el rango del 161,8% al 224%.

 

Identificación de D

El punto D es la onda final del patrón armónico alcista 5-0, que completa toda la estructura. Encontrar el punto D dentro del rango correcto de retroceso de Fibonacci es el último paso después de identificar y validar los puntos 0, X, A, B y C. El punto D es la zona de finalización del patrón y suele indicar la región donde los operadores esperan una posible reversión alcista.

Para que una configuración alcista 5-0 se considere legítima, el punto D debe desarrollarse entre el retroceso de Fibonacci del 50% y el 55% del tramo BC. El equilibrio armónico que establece la estructura del patrón lo proporciona esta zona de retroceso. En otras palabras, D debería retroceder aproximadamente la mitad del movimiento de BC, lo que indica que la corrección a la baja desde C podría estar llegando a su fin.

Ejemplo:

input double d_bc_max = 55.0; // MAX D RETRACEMENT LEVEL FOR BC
input double d_bc_min = 50.0; // MIN D RETRACEMENT LEVEL FOR BC
double fib_ret_d_50;
double fib_ret_d_55;
string fib_bc_ret_lvl;
string cd_line;
for(int n = m; n < bars_check - z; n++)
  {
   if(IsSwingLow(low, n, z) && low[n] < C)
     {

      D = low[n];
      D_time = time[n];
      D_letter = StringFormat("D  %d",l);
      cd_line = StringFormat("CD %d",i);

      fib_ext_b_113 =  MathAbs((((A - X) / 100) * (b_xa_min - 100)) - X);
      fib_ext_b_161 =   MathAbs((((A - X) / 100) * (b_xa_max - 100)) - X);

      fib_ext_c_161 = MathAbs((((A - B) / 100) * (c_ab_min - 100)) + A);
      fib_ext_c_224 =    MathAbs((((A - B) / 100) * (c_ab_max - 100)) + A);

      fib_ret_d_50 = C - ((d_bc_min / 100) * (C - B));
      fib_ret_d_55 = C - ((d_bc_max / 100) * (C - B));

      if(X < O && A > X && A < O && B <= fib_ext_b_113 && B >= fib_ext_b_161 && C >= fib_ext_c_161 && C <= fib_ext_c_224 && D <= fib_ret_d_50 && D >= fib_ret_d_55)
        {
         ObjectCreate(chart_id,O_letter,OBJ_TEXT,0,O_time,O);
         ObjectSetString(chart_id,O_letter,OBJPROP_TEXT,"0");
         ObjectSetInteger(chart_id,O_letter,OBJPROP_COLOR,clrBlue);

         ObjectCreate(chart_id,X_letter,OBJ_TEXT,0,X_time,X);
         ObjectSetString(chart_id,X_letter,OBJPROP_TEXT,"X");
         ObjectSetInteger(chart_id,X_letter,OBJPROP_COLOR,clrBlue);

         ObjectCreate(chart_id,A_letter,OBJ_TEXT,0,A_time,A);
         ObjectSetString(chart_id,A_letter,OBJPROP_TEXT,"A");
         ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,clrBlue);

         ObjectCreate(chart_id,B_letter,OBJ_TEXT,0,B_time,B);
         ObjectSetString(chart_id,B_letter,OBJPROP_TEXT,"B");
         ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,clrBlue);

         ox_line = StringFormat("0X Line  %d",i);
         xa_line = StringFormat("XA Line  %d",i);
         ab_line = StringFormat("AB Line  %d",i);

         ObjectCreate(chart_id,ox_line,OBJ_TREND,0, O_time, O,X_time,X);
         ObjectSetInteger(chart_id,ox_line,OBJPROP_COLOR,clrBlue);

         ObjectCreate(chart_id,xa_line,OBJ_TREND,0, X_time, X,A_time,A);
         ObjectSetInteger(chart_id,xa_line,OBJPROP_COLOR,clrBlue);

         ObjectCreate(chart_id,ab_line,OBJ_TREND,0, A_time, A,B_time,B);
         ObjectSetInteger(chart_id,ab_line,OBJPROP_COLOR,clrBlue);

         fib_xa_ext_obj = StringFormat("XA Expansion  %d",i);
         ObjectCreate(chart_id,fib_xa_ext_obj,OBJ_EXPANSION,0,A_time,A,X_time,X,A_time,A);
         ObjectSetInteger(chart_id,fib_xa_ext_obj,OBJPROP_COLOR,clrBlue);
         for(int i = 0; i <= 2; i++)
           {
            ObjectSetInteger(chart_id,fib_xa_ext_obj,OBJPROP_LEVELCOLOR,i,clrBlue);
           }
         fib_xa_ext_lvl = StringFormat("XA Expansion Levels %d",i);

         ObjectCreate(chart_id,fib_xa_ext_lvl,OBJ_RECTANGLE,0,X_time,fib_ext_b_113,B_time,fib_ext_b_161);
         ObjectSetInteger(chart_id,fib_xa_ext_lvl,OBJPROP_COLOR,clrBlue);

         ObjectCreate(chart_id,C_letter,OBJ_TEXT,0,C_time,C);
         ObjectSetString(chart_id,C_letter,OBJPROP_TEXT,"C");
         ObjectSetInteger(chart_id,C_letter,OBJPROP_COLOR,clrBlue);

         bc_line = StringFormat("BC Line  %d",i);
         ObjectCreate(chart_id,bc_line,OBJ_TREND,0, B_time, B,C_time,C);
         ObjectSetInteger(chart_id,bc_line,OBJPROP_COLOR,clrBlue);

         fib_ab_ext_obj = StringFormat("AB Expansion  %d",i);
         ObjectCreate(chart_id,fib_ab_ext_obj,OBJ_EXPANSION,0,B_time,B,A_time,A,B_time,B);
         ObjectSetInteger(chart_id,fib_ab_ext_obj,OBJPROP_COLOR,clrBlue);
         for(int i = 0; i <= 2; i++)
           {

            ObjectSetInteger(chart_id,fib_ab_ext_obj,OBJPROP_LEVELCOLOR,i,clrBlue);

           }

         fib_ab_ext_lvl = StringFormat("AB Expansion Levels %d",i);

         ObjectCreate(chart_id,fib_ab_ext_lvl,OBJ_RECTANGLE,0,A_time,fib_ext_c_161,C_time,fib_ext_c_224);
         ObjectSetInteger(chart_id,fib_ab_ext_lvl,OBJPROP_COLOR,clrBlue);

         ObjectCreate(chart_id,D_letter,OBJ_TEXT,0,D_time,D);
         ObjectSetString(chart_id,D_letter,OBJPROP_TEXT,"D");
         ObjectSetInteger(chart_id,D_letter,OBJPROP_COLOR,clrBlue);

         cd_line = StringFormat("CD Line  %d",i);
         ObjectCreate(chart_id,cd_line,OBJ_TREND,0, C_time, C,D_time,D);
         ObjectSetInteger(chart_id,cd_line,OBJPROP_COLOR,clrBlue);

         fib_bc_ret_lvl = StringFormat("BC RETRACEMENT Levels %d",i);

         ObjectCreate(chart_id,fib_bc_ret_lvl,OBJ_RECTANGLE,0,B_time,fib_ret_d_50,D_time,fib_ret_d_55);
         ObjectSetInteger(chart_id,fib_bc_ret_lvl,OBJPROP_COLOR,clrBlue);

        }

      break;
     }
  }

Resultado:

Figura 5. D

Explicación:

Fib_ret_d_50 y fib_ret_d_55 son dos variables que se utilizan para determinar los niveles de retroceso precisos en los que puede ocurrir D. El cálculo multiplica la diferencia entre C y B por la representación decimal del porcentaje de retroceso y luego resta el resultado de C. Esto proporciona los niveles de precio que delimitan la zona de retroceso del punto D. La fórmula garantiza la correcta ubicación de D dentro del límite de retroceso de Fibonacci previsto.

El programa determina si la estructura completa del patrón 5-0 cumple con los requisitos armónicos necesarios una vez que se han determinado los niveles de retroceso. El punto D se encuentra dentro del rango de retroceso del 50% al 55% de BC, mientras que los puntos B y C se extienden entre el 113% y el 161,8% del tramo XA, el punto C se sitúa entre el 161,8% y el 224% de la extensión AB, y el punto X es inferior a O, según las circunstancias. La estructura solo se considera un patrón 5-0 legítimo cuando se cumplen todas estas relaciones.

Tras la validación, el programa utiliza el gráfico para representar visualmente la estructura. En la posición D, se coloca una etiqueta de texto "D" para indicar su ubicación. La última sección del patrón se muestra claramente cuando se traza una línea que une C y D para producir la pata CD. Para indicar visualmente la posible zona de finalización del punto D, también se crea un rectángulo para enfatizar el área de retroceso del 50% al 55%. Esto facilita a los operadores la detección en tiempo real de posibles giros o finalizaciones del patrón.

El siguiente paso consiste en verificar que cada punto identificado represente con precisión el movimiento predominante dentro de su pierna correspondiente. Dado que las pequeñas variaciones de precio pueden distorsionar la estructura general del patrón y producir confusión o señales engañosas, simplemente registrar los máximos y los mínimos es insuficiente. Es necesario desarrollar directrices claras para verificar cada punto de oscilación y así preservar la precisión.

Debe ser el punto más alto entre los puntos 0 y X, comenzando en el punto 0. Esto garantiza que un verdadero máximo local (swing high), en lugar de una ligera subida de precio, marque el inicio del primer tramo descendente (0X). Sin embargo, entre los puntos X y A, el punto X debe ser el más bajo. Esto demuestra que la fase XA comienza con un verdadero mínimo local (swing low) en lugar de una caída transitoria.

De forma similar, para garantizar que el tramo AB refleje un pico de oscilación legítimo, el punto A debe ser el máximo más alto entre los puntos A y B. El tramo BC debe entonces retroceder desde un valle dominante si el punto B es el mínimo más bajo entre los puntos B y C. Para garantizar que el tramo CD comience desde un máximo local (swing high) verdadero, el punto C debe ser el máximo más alto entre los puntos C y D.

Ejemplo:
int c_d_bars;
int c_highest_index;
double c_d_hh;
datetime c_d_hh_t;

int b_c_bars;
int b_lowest_index;
double b_c_ll;
datetime b_c_ll_t;

int a_b_bars;
int a_highest_index;
double a_b_hh;
datetime a_b_hh_t;

int x_a_bars;
int x_lowest_index;
double x_a_ll;
datetime x_a_ll_t;

int o_x_bars;
int o_highest_index;
double o_x_hh;
datetime o_x_hh_t;
for(int n = m; n < bars_check - z; n++)
  {
   if(IsSwingLow(low, n, z) && low[n] < C)
     {

      D = low[n];
      D_time = time[n];
      D_letter = StringFormat("D  %d",l);
      cd_line = StringFormat("CD %d",i);

      c_d_bars = Bars(_Symbol,PERIOD_CURRENT,C_time,D_time);
      c_highest_index = ArrayMaximum(high,m,c_d_bars);
      c_d_hh = high[c_highest_index];
      c_d_hh_t = time[c_highest_index];

      b_c_bars = Bars(_Symbol,PERIOD_CURRENT,B_time,c_d_hh_t);
      b_lowest_index = ArrayMinimum(low,l,b_c_bars);
      b_c_ll = low[b_lowest_index];
      b_c_ll_t = time[b_lowest_index];

      a_b_bars = Bars(_Symbol,PERIOD_CURRENT,A_time,b_c_ll_t);
      a_highest_index = ArrayMaximum(high,k,a_b_bars);
      a_b_hh = high[a_highest_index];
      a_b_hh_t = time[a_highest_index];

      x_a_bars = Bars(_Symbol,PERIOD_CURRENT,X_time,a_b_hh_t);
      x_lowest_index = ArrayMinimum(low,j,x_a_bars);
      x_a_ll = low[x_lowest_index];
      x_a_ll_t = time[x_lowest_index];

      o_x_bars = Bars(_Symbol,PERIOD_CURRENT,O_time,x_a_ll_t);
      o_highest_index = ArrayMaximum(high,a,o_x_bars);
      o_x_hh = high[o_highest_index];
      o_x_hh_t = time[o_highest_index];

      fib_ext_b_113 =  MathAbs((((a_b_hh - x_a_ll) / 100) * (b_xa_min - 100)) - x_a_ll);
      fib_ext_b_161 =   MathAbs((((a_b_hh - x_a_ll) / 100) * (b_xa_max - 100)) - x_a_ll);

      fib_ext_c_161 = MathAbs((((a_b_hh - b_c_ll) / 100) * (c_ab_min - 100)) + a_b_hh);
      fib_ext_c_224 =    MathAbs((((a_b_hh - b_c_ll) / 100) * (c_ab_max - 100)) + a_b_hh);

      fib_ret_d_50 = c_d_hh - ((d_bc_min / 100) * (c_d_hh - b_c_ll));
      fib_ret_d_55 = c_d_hh - ((d_bc_max / 100) * (c_d_hh - b_c_ll));

      if(x_a_ll < o_x_hh && a_b_hh > x_a_ll && a_b_hh < o_x_hh && b_c_ll <= fib_ext_b_113 && b_c_ll >= fib_ext_b_161 && c_d_hh >= fib_ext_c_161 && c_d_hh <= fib_ext_c_224 && D <= fib_ret_d_50 && D >= fib_ret_d_55)
        {
         ObjectCreate(chart_id,O_letter,OBJ_TEXT,0,o_x_hh_t,o_x_hh);
         ObjectSetString(chart_id,O_letter,OBJPROP_TEXT,"0");
         ObjectSetInteger(chart_id,O_letter,OBJPROP_COLOR,clrBlue);

         ObjectCreate(chart_id,X_letter,OBJ_TEXT,0,x_a_ll_t,x_a_ll);
         ObjectSetString(chart_id,X_letter,OBJPROP_TEXT,"X");
         ObjectSetInteger(chart_id,X_letter,OBJPROP_COLOR,clrBlue);

         ObjectCreate(chart_id,A_letter,OBJ_TEXT,0,a_b_hh_t,a_b_hh);
         ObjectSetString(chart_id,A_letter,OBJPROP_TEXT,"A");
         ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,clrBlue);

         ObjectCreate(chart_id,B_letter,OBJ_TEXT,0,b_c_ll_t,b_c_ll);
         ObjectSetString(chart_id,B_letter,OBJPROP_TEXT,"B");
         ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,clrBlue);

         ox_line = StringFormat("0X Line  %d",i);
         xa_line = StringFormat("XA Line  %d",i);
         ab_line = StringFormat("AB Line  %d",i);

         ObjectCreate(chart_id,ox_line,OBJ_TREND,0, o_x_hh_t, o_x_hh,x_a_ll_t,x_a_ll);
         ObjectSetInteger(chart_id,ox_line,OBJPROP_COLOR,clrBlue);

         ObjectCreate(chart_id,xa_line,OBJ_TREND,0, x_a_ll_t, x_a_ll,a_b_hh_t,a_b_hh);
         ObjectSetInteger(chart_id,xa_line,OBJPROP_COLOR,clrBlue);

         ObjectCreate(chart_id,ab_line,OBJ_TREND,0, a_b_hh_t, a_b_hh,b_c_ll_t,b_c_ll);
         ObjectSetInteger(chart_id,ab_line,OBJPROP_COLOR,clrBlue);

         fib_xa_ext_obj = StringFormat("XA Expansion  %d",i);
         ObjectCreate(chart_id,fib_xa_ext_obj,OBJ_EXPANSION,0,a_b_hh_t,a_b_hh,x_a_ll_t,x_a_ll,a_b_hh_t,a_b_hh);
         ObjectSetInteger(chart_id,fib_xa_ext_obj,OBJPROP_COLOR,clrBlue);
         for(int i = 0; i <= 2; i++)
           {
            ObjectSetInteger(chart_id,fib_xa_ext_obj,OBJPROP_LEVELCOLOR,i,clrBlue);
           }

         fib_xa_ext_lvl = StringFormat("XA Expansion Levels %d",i);

         ObjectCreate(chart_id,fib_xa_ext_lvl,OBJ_RECTANGLE,0,x_a_ll_t,fib_ext_b_113,b_c_ll_t,fib_ext_b_161);
         ObjectSetInteger(chart_id,fib_xa_ext_lvl,OBJPROP_COLOR,clrBlue);

         ObjectCreate(chart_id,C_letter,OBJ_TEXT,0,c_d_hh_t,c_d_hh);
         ObjectSetString(chart_id,C_letter,OBJPROP_TEXT,"C");
         ObjectSetInteger(chart_id,C_letter,OBJPROP_COLOR,clrBlue);

         bc_line = StringFormat("BC Line  %d",i);
         ObjectCreate(chart_id,bc_line,OBJ_TREND,0, b_c_ll_t, b_c_ll,c_d_hh_t,c_d_hh);
         ObjectSetInteger(chart_id,bc_line,OBJPROP_COLOR,clrBlue);

         fib_ab_ext_obj = StringFormat("AB Expansion  %d",i);
         ObjectCreate(chart_id,fib_ab_ext_obj,OBJ_EXPANSION,0,b_c_ll_t,b_c_ll,a_b_hh_t,a_b_hh,b_c_ll_t,b_c_ll);
         ObjectSetInteger(chart_id,fib_ab_ext_obj,OBJPROP_COLOR,clrBlue);
         for(int i = 0; i <= 2; i++)
           {
            ObjectSetInteger(chart_id,fib_ab_ext_obj,OBJPROP_LEVELCOLOR,i,clrBlue);
           }

         fib_ab_ext_lvl = StringFormat("AB Expansion Levels %d",i);

         ObjectCreate(chart_id,fib_ab_ext_lvl,OBJ_RECTANGLE,0,a_b_hh_t,fib_ext_c_161,c_d_hh_t,fib_ext_c_224);
         ObjectSetInteger(chart_id,fib_ab_ext_lvl,OBJPROP_COLOR,clrBlue);

         ObjectCreate(chart_id,D_letter,OBJ_TEXT,0,D_time,D);
         ObjectSetString(chart_id,D_letter,OBJPROP_TEXT,"D");
         ObjectSetInteger(chart_id,D_letter,OBJPROP_COLOR,clrBlue);

         cd_line = StringFormat("CD Line  %d",i);
         ObjectCreate(chart_id,cd_line,OBJ_TREND,0, C_time, C,D_time,D);
         ObjectSetInteger(chart_id,cd_line,OBJPROP_COLOR,clrBlue);

         fib_bc_ret_lvl = StringFormat("BC RETRACEMENT Levels %d",i);

         ObjectCreate(chart_id,fib_bc_ret_lvl,OBJ_RECTANGLE,0,b_c_ll_t,fib_ret_d_50,D_time,fib_ret_d_55);
         ObjectSetInteger(chart_id,fib_bc_ret_lvl,OBJPROP_COLOR,clrBlue);

        }
      break;
     }
  }

Explicación:

Para garantizar que cada punto represente con precisión una oscilación del mercado, se utiliza el mismo procedimiento de validación para los tramos restantes. El algoritmo determina el mínimo más bajo entre X y A para el tramo XA, validando así X como un mínimo local (swing low). Para garantizar que 0 represente el máximo dominante al inicio del patrón, el tramo 0X busca de forma similar el máximo entre 0 y X. Este método de evaluación de cada punto mantiene la estructura del patrón estable y fiable, a la vez que elimina los falsos movimientos que podrían distorsionar la precisión de la identificación.

El programa garantiza que todos los máximos y mínimos verificados recientemente se incorporen en los cálculos posteriores tras validar cada punto de inflexión dominante. Esta mejora permite recalcular con mayor precisión los niveles de extensión y retroceso de Fibonacci, garantizando que las proporciones de cada tramo se correspondan con las fluctuaciones reales del mercado. Una vez finalizada esta recalibración, el software verifica que cada punto del patrón alcista 5-0 conserve el orden y las conexiones adecuadas. El método verifica que se ha desarrollado una estructura 5-0 legítima en el gráfico una vez que se han cumplido todos los requisitos geométricos y de Fibonacci.


Ejecución de operaciones

Tras confirmar que el patrón armónico alcista 5-0 se ha identificado correctamente, el siguiente paso es ejecutar operaciones basadas en dicha estructura. En esta configuración, la entrada en la operación se produce cuando el precio alcanza el punto D, que representa la posible finalización del patrón y una posible zona de reversión alcista. En MQL5, esto se puede implementar comprobando si el precio actual está cerca del punto D y, a continuación, abriendo una orden de compra con parámetros predefinidos como el tamaño del lote, el stop loss y el take profit.

Ejemplo:

#include <Trade/Trade.mqh>
CTrade trade;
input double lot_size = 0.6;
datetime time_price[];
double ask_price;
double take_p;
datetime last_trade_time = 0;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---

   ArraySetAsSeries(time_price,true);

//---
   return(INIT_SUCCEEDED);
  }
CopyTime(_Symbol, timeframe, 0, 2, time_price);
ask_price = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
datetime current_bar_time = iTime(_Symbol,timeframe,0);
if(x_a_ll < o_x_hh && a_b_hh > x_a_ll && a_b_hh < o_x_hh && b_c_ll <= fib_ext_b_113 && b_c_ll >= fib_ext_b_161 && c_d_hh >= fib_ext_c_161 && c_d_hh <= fib_ext_c_224 && D <= fib_ret_d_50 && D >= fib_ret_d_55)
  {

   ObjectCreate(chart_id,O_letter,OBJ_TEXT,0,o_x_hh_t,o_x_hh);
   ObjectSetString(chart_id,O_letter,OBJPROP_TEXT,"0");
   ObjectSetInteger(chart_id,O_letter,OBJPROP_COLOR,clrBlue);

   ObjectCreate(chart_id,X_letter,OBJ_TEXT,0,x_a_ll_t,x_a_ll);
   ObjectSetString(chart_id,X_letter,OBJPROP_TEXT,"X");
   ObjectSetInteger(chart_id,X_letter,OBJPROP_COLOR,clrBlue);

   ObjectCreate(chart_id,A_letter,OBJ_TEXT,0,a_b_hh_t,a_b_hh);
   ObjectSetString(chart_id,A_letter,OBJPROP_TEXT,"A");
   ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,clrBlue);

   ObjectCreate(chart_id,B_letter,OBJ_TEXT,0,b_c_ll_t,b_c_ll);
   ObjectSetString(chart_id,B_letter,OBJPROP_TEXT,"B");
   ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,clrBlue);

   ox_line = StringFormat("0X Line  %d",i);
   xa_line = StringFormat("XA Line  %d",i);
   ab_line = StringFormat("AB Line  %d",i);

   ObjectCreate(chart_id,ox_line,OBJ_TREND,0, o_x_hh_t, o_x_hh,x_a_ll_t,x_a_ll);
   ObjectSetInteger(chart_id,ox_line,OBJPROP_COLOR,clrBlue);

   ObjectCreate(chart_id,xa_line,OBJ_TREND,0, x_a_ll_t, x_a_ll,a_b_hh_t,a_b_hh);
   ObjectSetInteger(chart_id,xa_line,OBJPROP_COLOR,clrBlue);

   ObjectCreate(chart_id,ab_line,OBJ_TREND,0, a_b_hh_t, a_b_hh,b_c_ll_t,b_c_ll);
   ObjectSetInteger(chart_id,ab_line,OBJPROP_COLOR,clrBlue);

   fib_xa_ext_obj = StringFormat("XA Expansion  %d",i);
   ObjectCreate(chart_id,fib_xa_ext_obj,OBJ_EXPANSION,0,a_b_hh_t,a_b_hh,x_a_ll_t,x_a_ll,a_b_hh_t,a_b_hh);
   ObjectSetInteger(chart_id,fib_xa_ext_obj,OBJPROP_COLOR,clrBlue);
   for(int i = 0; i <= 2; i++)
     {
      ObjectSetInteger(chart_id,fib_xa_ext_obj,OBJPROP_LEVELCOLOR,i,clrBlue);
     }

   fib_xa_ext_lvl = StringFormat("XA Expansion Levels %d",i);

   ObjectCreate(chart_id,fib_xa_ext_lvl,OBJ_RECTANGLE,0,x_a_ll_t,fib_ext_b_113,b_c_ll_t,fib_ext_b_161);
   ObjectSetInteger(chart_id,fib_xa_ext_lvl,OBJPROP_COLOR,clrBlue);

   ObjectCreate(chart_id,C_letter,OBJ_TEXT,0,c_d_hh_t,c_d_hh);
   ObjectSetString(chart_id,C_letter,OBJPROP_TEXT,"C");
   ObjectSetInteger(chart_id,C_letter,OBJPROP_COLOR,clrBlue);

   bc_line = StringFormat("BC Line  %d",i);
   ObjectCreate(chart_id,bc_line,OBJ_TREND,0, b_c_ll_t, b_c_ll,c_d_hh_t,c_d_hh);
   ObjectSetInteger(chart_id,bc_line,OBJPROP_COLOR,clrBlue);

   fib_ab_ext_obj = StringFormat("AB Expansion  %d",i);
   ObjectCreate(chart_id,fib_ab_ext_obj,OBJ_EXPANSION,0,b_c_ll_t,b_c_ll,a_b_hh_t,a_b_hh,b_c_ll_t,b_c_ll);
   ObjectSetInteger(chart_id,fib_ab_ext_obj,OBJPROP_COLOR,clrBlue);
   for(int i = 0; i <= 2; i++)
     {
      ObjectSetInteger(chart_id,fib_ab_ext_obj,OBJPROP_LEVELCOLOR,i,clrBlue);
     }

   fib_ab_ext_lvl = StringFormat("AB Expansion Levels %d",i);

   ObjectCreate(chart_id,fib_ab_ext_lvl,OBJ_RECTANGLE,0,a_b_hh_t,fib_ext_c_161,c_d_hh_t,fib_ext_c_224);
   ObjectSetInteger(chart_id,fib_ab_ext_lvl,OBJPROP_COLOR,clrBlue);

   ObjectCreate(chart_id,D_letter,OBJ_TEXT,0,D_time,D);
   ObjectSetString(chart_id,D_letter,OBJPROP_TEXT,"D");
   ObjectSetInteger(chart_id,D_letter,OBJPROP_COLOR,clrBlue);

   cd_line = StringFormat("CD Line  %d",i);
   ObjectCreate(chart_id,cd_line,OBJ_TREND,0, c_d_hh_t, c_d_hh,D_time,D);
   ObjectSetInteger(chart_id,cd_line,OBJPROP_COLOR,clrBlue);

   fib_bc_ret_lvl = StringFormat("BC RETRACEMENT Levels %d",i);

   ObjectCreate(chart_id,fib_bc_ret_lvl,OBJ_RECTANGLE,0,b_c_ll_t,fib_ret_d_50,D_time,fib_ret_d_55);
   ObjectSetInteger(chart_id,fib_bc_ret_lvl,OBJPROP_COLOR,clrBlue);

   if(time[n+z] == time_price[1] && close[n+z] > D && current_bar_time != last_trade_time)
     {
      take_p = ask_price + (MathAbs(ask_price - D) * 3);

      trade.Buy(lot_size,_Symbol,ask_price,D,take_p);

      last_trade_time = current_bar_time;

     }
  }

Resultado:

Figura 6. Ejecución de operaciones

Explicación:

Tras la confirmación del patrón armónico alcista 5-0, la ejecución de la operación se gestiona mediante esta sección del software. La biblioteca de negociación MQL5, que proporciona la clase CTrade necesaria para transmitir órdenes al bróker, se importa en la primera línea, #include<Trade/Trade.mqh> . Después de crear una instancia de esa clase, la línea CTrade trade; permite que el programa realice operaciones comerciales como compra y venta. Cada operación que se abra empleará 0,6 lotes, tal como lo define la variable de entrada lot_size = 0,6.

Para controlar la ejecución de las operaciones y evitar entradas duplicadas, el programa define una serie de variables. Ask_price guarda el precio ask actual del mercado, take_p se utiliza para determinar el objetivo de toma de ganancias, last_trade_time registra la hora de la operación más reciente y el array time_price[] rastrea los tiempos de las velas. Para que sea compatible con el manejo de datos de series temporales de MQL5, el array time_price se inicializa en orden del más reciente al más antiguo. El software recupera los horarios de las velas más recientes y el precio de mercado para cada tick.

La hora de la vela actual debe coincidir con la hora copiada más reciente, el precio de cierre debe estar por encima del punto D y no debe haberse ejecutado ninguna operación en la misma vela. Estos criterios se comprueban posteriormente para determinar si se debe abrir una operación. Para evitar entradas múltiples dentro de la misma barra, el programa realiza una orden de compra si se cumplen estos requisitos, determina un objetivo de toma de ganancias tres veces la distancia entre el precio ask actual y el punto D, y registra la hora de la operación.


Conclusión

Este artículo explicó cómo crear un Asesor Experto que detecta y opera con el patrón armónico 5-0. En él se explicó cómo identificar y validar cada punto de inflexión, confirmar la estructura del patrón, ejecutar operaciones automáticamente y mostrar el patrón en el gráfico utilizando objetos gráficos como líneas de tendencia y etiquetas. Esto marca la parte final de la serie Patrones Gráficos Avanzados. En la siguiente parte, se explorarán nuevos aspectos de MQL5.

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

Archivos adjuntos |
kimo161
kimo161 | 24 dic 2025 en 15:10

¿Las ondas de Elliott?


Sí, son las ondas de Elliott. Y no hace falta inventarse nuevos conceptos, a Guillermo de Ockham no le gusta eso.

Ryan L Johnson
Ryan L Johnson | 24 dic 2025 en 16:32
kimo161 #:

¿Las olas de Eliot?


Sí, son ondas de Eliot. Y no inventes nuevas entidades, a Guillermo de Ockham no le gusta.

Es más matizado que eso. Los patrones armónicos, incluido el patrón 5-0 (estado de marcas registradas y recuperación de documentos), se inventaron después de que se inventaran las ondas de Elliott. Las ondas de Elliott se basan en nueve grados de ondas en ciclos, mientras que el patrón 5-0 se basa en las proporciones de Fibonacci. Es inevitable que se produzca cierto solapamiento cuando se aplican ambos patrones a un gráfico, lo que puede generar confusión.
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.
Del básico al intermedio: Colas, listas y árboles (IV) Del básico al intermedio: Colas, listas y árboles (IV)
En este artículo, finalizaremos la parte relativa a la implementación y explicación de una lista enlazada. Sin embargo, la implementación mostrada aquí no incluirá cierto detalle que podemos implementar en una lista enlazada. Esto se verá más adelante, en otro artículo.
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.
Simulación de mercado: Position View (XI) Simulación de mercado: Position View (XI)
En este artículo, te mostraré, querido y estimado lector, cómo puedes modificar el indicador de posición para que sea capaz de hacer muchas más cosas de las que podía hacer originalmente. Veremos cómo incorporar la capacidad de mover los precios y crear líneas de precio directamente en el gráfico. Algo que muchos considerarían extremadamente complicado y difícil de resolver. Sin embargo, verás que lo haremos con mucha facilidad y con un mínimo de esfuerzo. Solo hará falta detenerse y pensar un poco.