Introducción a MQL5 (Parte 19): Automatización de la detección de las ondas de Wolfe
Introducción
¡Bienvenidos de nuevo a la parte 19 de la serie «Introducción a MQL5»! En la parte 18, presenté el patrón de la onda de Wolfe, una estructura única de cinco ondas que se utiliza para anticipar reversiones del precio con precisión. Analizamos los dos tipos principales de ondas de Wolfe: la configuración bajista, que indica una posible caída del precio, y la configuración alcista, que apunta a un repunte inminente. También aprendiste a obtener datos de velas japonesas, algo esencial para el análisis de la acción del precio, y hemos explicado la lógica para detectar oportunidades de trading válidas basadas en este patrón.
En esta parte, pasamos de la teoría a la práctica. Veremos cómo identificar las estructuras de la onda de Wolfe mediante programación y cómo abrir operaciones basadas en estas señales utilizando MQL5. Esto incluye detectar puntos de inflexión clave, validar las reglas de los patrones y preparar el EA para que actúe en función de las señales que detecte.
En este artículo, aprenderás:
- Cómo detectar la estructura clásica de cinco ondas de las «ondas de Wolfe» utilizando datos históricos de precios.
- Identificar mediante algoritmos los máximos y mínimos de oscilación para determinar los puntos de las ondas.
- Aprende a aplicar y modificar los niveles de expansión de Fibonacci para validar la formación de ondas, especialmente en las ondas 3 y 5.
- El artículo explica cómo trazar tres líneas de tendencia importantes (las ondas 1-3, 2-4 y 1-4), que resultan fundamentales para confirmar los patrones y tomar decisiones de trading.
- Cómo comprobar la simetría y las relaciones proporcionales entre las ondas 1 y 2 y las ondas 3 y 4 para mejorar la fiabilidad del patrón.
- Aprende a etiquetar ondas y a dibujar elementos visuales, como texto, rectángulos y líneas de tendencia, directamente en el gráfico utilizando MQL5.
- Implementar una lógica que espere a recibir la confirmación antes de ejecutar las operaciones, evitando entradas erróneas.
- Cómo programar salidas automáticas de las operaciones cuando el mercado toca la línea de tendencia entre la onda 1 y la 4, lo que ayuda a gestionar el riesgo.
Identificación de los patrones bajistas de la onda de Wolfe
En el último artículo ya analizamos en detalle la estructura y las reglas del patrón bajista «onda de Wolfe». Ahora, en esta sección, nos centraremos en cómo implementar esa lógica mediante programación. Como se ha mencionado anteriormente, la onda de Wolfe bajista se compone de cinco ondas que deben seguir una secuencia determinada y cumplir ciertos requisitos estructurales. La onda 2 debe ser un mínimo de oscilación situado por debajo de la onda 1, y la onda 1 debe ser un máximo de oscilación. A continuación, la onda 3 forma otro máximo de oscilación, pero esta vez por encima de la onda 1 y dentro de una determinada extensión de Fibonacci de los tramos de la onda 1 a la onda 2. A continuación, se identifica la onda 4, un mínimo de oscilación que se sitúa por debajo de la onda 3, pero por encima de la onda 2. La onda 5 completa el patrón al alcanzar un máximo de oscilación por encima de la onda 3 y situarse dentro de una extensión de Fibonacci predeterminada de los movimientos de la onda 3 a la onda 4.
También es fundamental tener en cuenta que las amplitudes de las ondas uno y dos deben ser comparables a las de las ondas tres y cuatro. Las ondas 3–4 deberían medir idealmente al menos el 70 % del tamaño de las ondas 1–2. Esta simetría confiere credibilidad a la estructura, lo que además sirve para confirmar la validez del patrón. En esta sección se localizarán los cinco puntos mediante funciones de detección de oscilaciones y se realizarán comprobaciones para garantizar que sus distancias y conexiones cumplen los requisitos de la onda de Wolfe.
Identificación de la primera y la segunda onda
Identificar con precisión las ondas 1 y 2 es el primer paso para detectar un patrón bajista de onda de Wolfe. Sin estos dos elementos fundamentales, resulta difícil localizar con precisión las ondas restantes. En esta parte nos centraremos en buscar máximos y mínimos de oscilación válidos que cumplan los criterios de la onda 1 y la onda 2 en el gráfico. Etiquetaremos claramente las dos ondas en el gráfico para facilitar su identificación tan pronto como se detecten.
Entre la onda 1 y la onda 2, también proporcionaremos un objeto de extensión de Fibonacci. Al establecer niveles de precios adecuados basados en las reglas del patrón, esta ampliación ayudará a orientar la identificación de las ondas tres y cinco. Esto establece desde el principio una base sólida para el resto del proceso de identificación de ondas.
Ejemplo:input ENUM_TIMEFRAMES timeframe = PERIOD_CURRENT; int bars_check = 500; datetime time_bar; double total_symbol_bars; double open[]; double close[]; double low[]; double high[]; datetime time[]; double wv1; datetime wv1_time; string wv1_txt; double wv2; datetime wv2_time; string wv2_txt; string fib_ext_wv1_wv2; ulong chart_id = ChartID(); //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { ObjectsDeleteAll(chart_id); } //+------------------------------------------------------------------+ //| 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 = 7; i < bars_check - 7; i++) { if(IsSwingHigh(high, i, 7)) { wv1 = high[i]; wv1_time = time[i]; wv1_txt = StringFormat("WAVE 1 %d", i); for(int j = i; j < bars_check - 7; j++) { if(IsSwingLow(low, j, 7) && low[j] < wv1) { wv2 = low[j]; wv2_time = time[j]; wv2_txt = StringFormat("WAVE 2 %d", j); ObjectCreate(chart_id, wv1_txt, OBJ_TEXT, 0, wv1_time, wv1); ObjectSetString(chart_id, wv1_txt, OBJPROP_TEXT, "WV1"); ObjectSetInteger(chart_id, wv1_txt, OBJPROP_COLOR, clrBlue); ObjectCreate(chart_id, wv2_txt, OBJ_TEXT, 0, wv2_time, wv2); ObjectSetString(chart_id, wv2_txt, OBJPROP_TEXT, "WV2"); ObjectSetInteger(chart_id, wv2_txt, OBJPROP_COLOR, clrBlue); fib_ext_wv1_wv2 = StringFormat("FIBO EXTENSION WAVE 1 AND 2 %d", i); ObjectCreate(chart_id, fib_ext_wv1_wv2, OBJ_EXPANSION, 0, wv2_time, wv2, wv1_time, wv1, wv2_time, wv2); ObjectSetInteger(chart_id, fib_ext_wv1_wv2, OBJPROP_COLOR, clrBlue); for(int i = 0; i <= 2; i++) { ObjectSetInteger(chart_id, fib_ext_wv1_wv2, OBJPROP_LEVELCOLOR, i, clrBlue); } break; } } } } } } //+------------------------------------------------------------------+ //| 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; } return true; }
Resultado:

Explicación:
Se declaran ciertas variables para conservar información esencial sobre las dos primeras ondas, con el fin de identificar y describir de manera eficaz patrones como la onda de Wolfe bajista en el gráfico. Se añaden tres variables para la Onda 1: wv1, que recoge el nivel de precio; wv1_time, que indica el momento exacto en que se produjo ese precio; y wv1_txt, que sirve como etiqueta de texto para la representación gráfica de la onda en el gráfico. Las variables wv2, wv2_time y wv2_txt tienen la misma función en la segunda onda.
Estos datos son fundamentales, ya que permiten al asesor experto guardar y consultar posteriormente los puntos de precio exactos y las marcas de tiempo en los que se detectaron máximos o mínimos de oscilación significativos. El operador podrá determinar más fácilmente qué onda se destaca en el gráfico gracias a las etiquetas de texto, que resultan especialmente útiles para una mayor claridad visual.
Se declara una variable de cadena denominada «fib_ext_wv1_wv2» para almacenar el nombre del objeto «Extensión de Fibonacci», además de los datos de la onda. Esta variable garantiza que el elemento que representa la extensión de la onda 1 a la onda 2 se pueda generar, modificar o eliminar adecuadamente cuando sea necesario, ya que cada objeto del gráfico debe tener una identificación única. Para que cada instancia sea única, suele incluirse el índice de onda en el nombre, sobre todo si el asesor experto genera varios patrones al analizar las barras anteriores.
Además, el código utiliza la función ChartID() para obtener el identificador único del gráfico actual y lo almacena en la variable chart_id, con el fin de facilitar todas las operaciones de creación de objetos. Esto es importante porque MetaTrader 5 permite tener abiertos varios gráficos a la vez. Para evitar conflictos o ubicaciones incorrectas, la aplicación se asegura de producir y modificar los elementos gráficos en el gráfico previsto haciendo referencia explícita al ID del gráfico correspondiente.
La línea ObjectsDeleteAll(chart_id); de la función OnDeinit() tiene una función de limpieza. Esta función elimina del gráfico todos los objetos dibujados anteriormente por el asesor experto cuando se elimina dicho asesor o se cierra el gráfico. De este modo se evita el desorden y se garantiza que, una vez que el EA haya terminado de funcionar, no queden elementos gráficos obsoletos, como etiquetas de ondas o líneas de Fibonacci.
El EA realiza una comprobación fundamental para asegurarse de que hay suficientes barras disponibles antes de que se active la lógica de detección de patrones. Compara el número de barras que tiene previsto analizar (bars_check) con el número total de barras del gráfico (total_symbol_bars). El programa comienza a analizar los datos de precios para detectar los primeros indicios de una onda de Wolfe bajista tras confirmar que hay suficientes barras históricas cargadas en la pantalla (if(total_symbol_bars >= bars_check)).
El primer paso en esta detección es un bucle «for»:
for(int i = 7; i < bars_check - 7; i++)
Con el fin de detectar de forma fiable los máximos y mínimos de oscilación, el bucle comienza en el índice 7 en lugar de en el 0. Para determinar si un precio es realmente un punto de giro (swing), las funciones de detección de inflexiones (que se describen a continuación) analizan siete barras hacia adelante y siete barras hacia atrás. No habría barras previas para comparar si el bucle comenzara en el índice 0, lo que provocaría un error de fuera de límites. De manera similar, detener el bucle en bars_check -7 garantiza que habrá suficientes barras posteriores para la comparación.
Este bucle exterior busca lo que podría ser la Onda 1 del patrón de la Onda de Wolfe, un máximo de oscilación. El código determina si el precio máximo en el índice i es un máximo local, es decir, si es más alto que el de las velas adyacentes. Cada índice i representa una vela histórica.
if(IsSwingHigh(high, i, 7))
El EA considera que esta vela podría ser una posible Onda 1 si la función devuelve «verdadero», lo que indicaría que se trata de un máximo de oscilación válido. Se crea una cadena de texto para la etiqueta (wv1_txt) que se utilizará más adelante en el gráfico, y el precio máximo y la hora correspondientes se guardan en las variables wv1 y wv1_time.
El código inicia un bucle interno para buscar hacia adelante en el tiempo el siguiente mínimo de oscilación válido, que representaría la Onda 2, una vez que se haya localizado una Onda 1 válida (máximo de oscilación):
for(int j = i; j < bars_check - 7; j++)
Este bucle comienza en el mismo índice que el bucle exterior (i) y avanza. Busca una barra que cumpla dos condiciones:
- Es un mínimo de oscilación (un mínimo local).
- Su precio es inferior al de la onda 1.
if(IsSwingLow(low, j, 7) && low[j] < wv1)
Cuando se cumplen ambos requisitos de la Onda 2, la EA registra el precio, el tiempo y la etiqueta como wv2, wv2_time y wv2_txt. Una vez localizadas las ondas 1 y 2, utiliza una instrucción «break» para salir del bucle interno, dibuja un objeto de extensión de Fibonacci entre ellas y añade etiquetas de texto al gráfico para ambas posiciones. Esto impide que el EA identifique una coincidencia adecuada para la Onda 1 actual y, a continuación, busque más posibilidades para la Onda 2.
Identificación de las ondas tres y cuatro
Para construir el patrón de la onda de Wolfe, es recomendable identificar las ondas 3 y 4 tras haber identificado correctamente las ondas 1 y 2. Sin embargo, la ubicación y la composición de las ondas 1 y 2 tienen un impacto significativo en estas ondas posteriores. La onda 3, en particular, debe cumplir dos requisitos esenciales: debe alcanzar un máximo superior al de la onda 1 y situarse dentro de un rango de extensión de Fibonacci predeterminado, calculado a partir de las ondas 1 y 2.
El movimiento del precio desde la onda 1 hasta la onda 2 se utiliza para trazar una extensión de Fibonacci con el fin de identificar este rango. Teniendo en cuenta la magnitud y el impulso de la estructura de la primera onda, esta herramienta ayuda a proyectar los posibles niveles de precios futuros. Se prevé que el precio alcance un rango determinado antes de revertir su tendencia, comprendido entre los niveles de extensión del 127,2 % y el 161,8 %, que normalmente es la zona aceptable para la Onda 3. Se considera que el precio podría ser un buen candidato para la tercera onda si alcanza un máximo dentro de este rango.
La tercera onda debe respetar la simetría del patrón, además de su nivel de precios. La estructura y la magnitud de las ondas 1 y 2 deben reflejarse o reproducirse adecuadamente en las ondas 3 y 4. Es este equilibrio geométrico lo que distingue a los patrones válidos de onda de Wolfe. A efectos de este estudio, definiremos la simetría en términos sencillos y cuantificables. El movimiento total entre la onda 1 y la onda 2 debería ser, como mínimo, del 70 % del tamaño de las ondas 3 y 4, concretamente. A medida que seguimos desarrollando el Asesor Experto, este porcentaje ofrece un marco sólido para la validación de patrones y contribuye a preservar la integridad estructural y visual de la onda de Wolfe.
Calcular el 70 % de la distancia entre la onda 1 y la onda 2
En primer lugar, calculemos el 70 % de la distancia entre la onda 1 y la onda 2.
Ejemplo:
double wv1_wv2_size; double wv1_wv2_70p;
if(total_symbol_bars >= bars_check) { for(int i = 7; i < bars_check - 7; i++) { if(IsSwingHigh(high, i, 7)) { wv1 = high[i]; wv1_time = time[i]; wv1_txt = StringFormat("WAVE 1 %d", i); for(int j = i; j < bars_check - 7; j++) { if(IsSwingLow(low, j, 7) && low[j] < wv1) { wv2 = low[j]; wv2_time = time[j]; wv2_txt = StringFormat("WAVE 2 %d", j); ObjectCreate(chart_id, wv1_txt, OBJ_TEXT, 0, wv1_time, wv1); ObjectSetString(chart_id, wv1_txt, OBJPROP_TEXT, "WV1"); ObjectSetInteger(chart_id, wv1_txt, OBJPROP_COLOR, clrBlue); ObjectCreate(chart_id, wv2_txt, OBJ_TEXT, 0, wv2_time, wv2); ObjectSetString(chart_id, wv2_txt, OBJPROP_TEXT, "WV2"); ObjectSetInteger(chart_id, wv2_txt, OBJPROP_COLOR, clrBlue); fib_ext_wv1_wv2 = StringFormat("FIBO EXTENSION WAVE 1 AND 2 %d", i); ObjectCreate(chart_id, fib_ext_wv1_wv2, OBJ_EXPANSION, 0, wv2_time, wv2, wv1_time, wv1, wv2_time, wv2); ObjectSetInteger(chart_id, fib_ext_wv1_wv2, OBJPROP_COLOR, clrBlue); for(int i = 0; i <= 2; i++) { ObjectSetInteger(chart_id, fib_ext_wv1_wv2, OBJPROP_LEVELCOLOR, i, clrBlue); } wv1_wv2_size = MathAbs(wv1 - wv2); wv1_wv2_70p = (wv1_wv2_size / 100) * 70; string luh = StringFormat("bb 2 %d", j); ObjectCreate(chart_id, luh, OBJ_TREND, 0, wv1_time, wv1 - wv1_wv2_70p, wv2_time, wv1 - wv1_wv2_70p); break; } } } } }
Resultado:

Explicación:
La tercera onda debe respetar la simetría del patrón, además de su nivel de precios. La estructura y la magnitud de las ondas 1 y 2 deben reflejarse o reproducirse adecuadamente en las ondas 3 y 4. Es este equilibrio geométrico lo que distingue a los patrones válidos de onda de Wolfe. A efectos de este estudio, definiremos la simetría en términos sencillos y cuantificables. El movimiento total entre la onda 1 y la onda 2 debería ser, como mínimo, del 70 % del tamaño de las ondas 3 y 4, concretamente. A medida que seguimos desarrollando el Asesor Experto, este porcentaje ofrece un marco sólido para la validación de patrones y contribuye a preservar la integridad estructural y visual de la onda de Wolfe.
Para ayudar a visualizar este criterio, se traza una línea de tendencia horizontal en el gráfico desde el momento de la Onda 1 hasta el momento de la Onda 2, a un nivel de precio un 70 % por debajo del máximo de la Onda 1. Esta línea sirve de referencia para garantizar que las ondas siguientes cumplan el requisito de tamaño mínimo.
Independientemente del orden de las ondas 1 y 2, aquí se utiliza la función MathAbs para garantizar que el tamaño calculado sea siempre positivo. El uso de MathAbs es una medida preventiva, aunque técnicamente no sea necesario en esta circunstancia concreta, ya que se prevé que la Onda 1 se sitúe por encima de la Onda 2 en un patrón bajista. Esto ayuda a evitar posibles errores en caso de que se subestimen o se confundan las ondas.
Expansión de Fibonacci de la onda 1 y la onda 2
Utilizando la función IsSwingHigh, el algoritmo encuentra la Onda 3 buscando un máximo de oscilación que se produzca después de la Onda 2 y que se encuentre entre la expansión de Fibonacci del 127,2 % y el 161,8 % de las Ondas 1 y 2. La tercera onda se guarda si cumple la condición. Para asegurarnos de que estamos ante el patrón correcto, solo trazamos en el gráfico las herramientas de Fibonacci, la línea del 70 % y los nombres de las ondas. A continuación, el algoritmo busca la onda 4, que debe ser un mínimo de oscilación posterior a la onda 3.
Ejemplo:
input ENUM_TIMEFRAMES timeframe = PERIOD_CURRENT; input double max_fib_ext_wv12 = 161.8; input double min_fib_ext_wv12 = 127.2; int bars_check = 500; datetime time_bar; double total_symbol_bars; double open[]; double close[]; double low[]; double high[]; datetime time[]; double wv1; datetime wv1_time; string wv1_txt; double wv2; datetime wv2_time; string wv2_txt; string fib_ext_wv1_wv2; ulong chart_id = ChartID(); double wv1_wv2_size; double wv1_wv2_70p; string perc_70; double fib_ext_1_2_161_8; double fib_ext_1_2_127_2; string fib_ext_range; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { ObjectsDeleteAll(chart_id); } //+------------------------------------------------------------------+ //| 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 = 7; i < bars_check - 7; i++) { if(IsSwingHigh(high, i, 7)) { wv1 = high[i]; wv1_time = time[i]; wv1_txt = StringFormat("WAVE 1 %d", i); for(int j = i; j < bars_check - 7; j++) { if(IsSwingLow(low, j, 7) && low[j] < wv1) { wv2 = low[j]; wv2_time = time[j]; wv2_txt = StringFormat("WAVE 2 %d", j); ObjectCreate(chart_id, wv1_txt, OBJ_TEXT, 0, wv1_time, wv1); ObjectSetString(chart_id, wv1_txt, OBJPROP_TEXT, "WV1"); ObjectSetInteger(chart_id, wv1_txt, OBJPROP_COLOR, clrBlue); ObjectCreate(chart_id, wv2_txt, OBJ_TEXT, 0, wv2_time, wv2); ObjectSetString(chart_id, wv2_txt, OBJPROP_TEXT, "WV2"); ObjectSetInteger(chart_id, wv2_txt, OBJPROP_COLOR, clrBlue); fib_ext_wv1_wv2 = StringFormat("FIBO EXTENSION WAVE 1 AND 2 %d", i); ObjectCreate(chart_id, fib_ext_wv1_wv2, OBJ_EXPANSION, 0, wv2_time, wv2, wv1_time, wv1, wv2_time, wv2); ObjectSetInteger(chart_id, fib_ext_wv1_wv2, OBJPROP_COLOR, clrBlue); for(int i = 0; i <= 2; i++) { ObjectSetInteger(chart_id, fib_ext_wv1_wv2, OBJPROP_LEVELCOLOR, i, clrBlue); } wv1_wv2_size = MathAbs(wv1 - wv2); wv1_wv2_70p = (wv1_wv2_size / 100) * 70; perc_70 = StringFormat("70 PERCENT %d", j); ObjectCreate(chart_id, perc_70, OBJ_TREND, 0, wv1_time, wv1 - wv1_wv2_70p, wv2_time, wv1 - wv1_wv2_70p); fib_ext_1_2_127_2 = MathAbs((((wv1 - wv2) / 100) * (min_fib_ext_wv12 - 100)) + wv1); fib_ext_1_2_161_8 = MathAbs((((wv1 - wv2) / 100) * (max_fib_ext_wv12 - 100)) + wv1); fib_ext_range = StringFormat("Fibo EXPENSION RANGE%d", j); ObjectCreate(chart_id, fib_ext_range, OBJ_RECTANGLE, 0, wv1_time, fib_ext_1_2_161_8, wv2_time, fib_ext_1_2_127_2); break; } } } } } } //+------------------------------------------------------------------+ //| 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; } return true; }
Resultado:

Identificación de la onda 3
El código avanza desde la Onda 2 para descubrir un máximo oscilatorio que se encuentra dentro de la expansión del 127, 2% al 161,8 % de las Ondas 1 y 2 para identificar la Onda 3 como una Onda Wolfe bajista. Esta zona se designa como «Onda 3» si se detecta allí un movimiento legítimo.
Ejemplo:double wv3; datetime wv3_time; string wv3_txt;
if(total_symbol_bars >= bars_check) { for(int i = 7; i < bars_check - 7; i++) { if(IsSwingHigh(high, i, 7)) { wv1 = high[i]; wv1_time = time[i]; wv1_txt = StringFormat("WAVE 1 %d", i); for(int j = i; j < bars_check - 7; j++) { if(IsSwingLow(low, j, 7) && low[j] < wv1) { wv2 = low[j]; wv2_time = time[j]; wv2_txt = StringFormat("WAVE 2 %d", j); wv1_wv2_size = MathAbs(wv1 - wv2); wv1_wv2_70p = (wv1_wv2_size / 100) * 70; fib_ext_1_2_127_2 = MathAbs((((wv1 - wv2) / 100) * (min_fib_ext_wv12 - 100)) + wv1); fib_ext_1_2_161_8 = MathAbs((((wv1 - wv2) / 100) * (max_fib_ext_wv12 - 100)) + wv1); for(int k = j; k < bars_check - 7; k++) { if(IsSwingHigh(high, k, 7) && time[k] > wv2_time) { wv3 = high[k]; wv3_time = time[k]; wv3_txt = StringFormat("WAVE 3 %d", k); if(wv3 >= fib_ext_1_2_127_2 && wv3 <= fib_ext_1_2_161_8) { ObjectCreate(chart_id, wv1_txt, OBJ_TEXT, 0, wv1_time, wv1); ObjectSetString(chart_id, wv1_txt, OBJPROP_TEXT, "WV1"); ObjectSetInteger(chart_id, wv1_txt, OBJPROP_COLOR, clrBlue); ObjectCreate(chart_id, wv2_txt, OBJ_TEXT, 0, wv2_time, wv2); ObjectSetString(chart_id, wv2_txt, OBJPROP_TEXT, "WV2"); ObjectSetInteger(chart_id, wv2_txt, OBJPROP_COLOR, clrBlue); fib_ext_wv1_wv2 = StringFormat("FIBO EXTENSION WAVE 1 AND 2 %d", i); ObjectCreate(chart_id, fib_ext_wv1_wv2, OBJ_EXPANSION, 0, wv2_time, wv2, wv1_time, wv1, wv2_time, wv2); ObjectSetInteger(chart_id, fib_ext_wv1_wv2, OBJPROP_COLOR, clrBlue); for(int i = 0; i <= 2; i++) { ObjectSetInteger(chart_id, fib_ext_wv1_wv2, OBJPROP_LEVELCOLOR, i, clrBlue); } perc_70 = StringFormat("70 PERCENT %d", j); ObjectCreate(chart_id, perc_70, OBJ_TREND, 0, wv1_time, wv1 - wv1_wv2_70p, wv2_time, wv1 - wv1_wv2_70p); fib_ext_range = StringFormat("Fibo EXPENSION RANGE%d", j); ObjectCreate(chart_id, fib_ext_range, OBJ_RECTANGLE, 0, wv1_time, fib_ext_1_2_161_8, wv2_time, fib_ext_1_2_127_2); ObjectCreate(chart_id, wv3_txt, OBJ_TEXT, 0, wv3_time, wv3); ObjectSetString(chart_id, wv3_txt, OBJPROP_TEXT, "WV3"); ObjectSetInteger(chart_id, wv3_txt, OBJPROP_COLOR, clrBlue); } break; } } break; } } } } }
Resultado:

Explicación:
En el código se utilizan tres variables para definir la Onda 3: wv3 para el nivel de precios, wv3_time para la sincronización y wv3_txt para el etiquetado. Al utilizar la función IsSwingHigh para identificar máximos de oscilación válidos que siguen a la onda 2, se puede determinar la onda 3 analizando hacia delante desde la onda 2. Anteriormente, todos los objetos se dibujaban tras detectar wv2. Ahora, estos objetos solo aparecerán cuando wv3 se encuentre dentro del intervalo especificado entre wv1 y wv2.
Identificación de la onda 4
El siguiente paso consiste en identificar la onda 4, que debe ser un mínimo de oscilación que se forma tras la onda 3. Debemos comprobar que el movimiento del precio de la onda 3 a la onda 4 guarde una proporción razonable respecto al movimiento de la onda 1 a la onda 2, para confirmar que el patrón sigue siendo válido. En este proyecto estamos aplicando un criterio de simetría sencillo, según el cual las ondas 3 y 4 deben tener una magnitud de al menos el 70 % de la de las ondas 1 y 2. Al evitar retrocesos desproporcionados o superficiales, este requisito contribuye a mantener el equilibrio estructural del patrón de la onda de Wolfe. En la siguiente parte, pondremos en práctica este razonamiento buscando un mínimo de oscilación válido tras la Onda 3 y comprobando que cumple los criterios de tamaño mínimo.
Ejemplo:double wv4; datetime wv4_time; string wv4_txt; double wv3_wv4_size;
if(total_symbol_bars >= bars_check) { for(int i = 7; i < bars_check - 7; i++) { if(IsSwingHigh(high, i, 7)) { wv1 = high[i]; wv1_time = time[i]; wv1_txt = StringFormat("WAVE 1 %d", i); for(int j = i; j < bars_check - 7; j++) { if(IsSwingLow(low, j, 7) && low[j] < wv1) { wv2 = low[j]; wv2_time = time[j]; wv2_txt = StringFormat("WAVE 2 %d", j); wv1_wv2_size = MathAbs(wv1 - wv2); wv1_wv2_70p = (wv1_wv2_size / 100) * 70; fib_ext_1_2_127_2 = MathAbs((((wv1 - wv2) / 100) * (min_fib_ext_wv12 - 100)) + wv1); fib_ext_1_2_161_8 = MathAbs((((wv1 - wv2) / 100) * (max_fib_ext_wv12 - 100)) + wv1); for(int k = j; k < bars_check - 7; k++) { if(IsSwingHigh(high, k, 7) && time[k] > wv2_time) { wv3 = high[k]; wv3_time = time[k]; wv3_txt = StringFormat("WAVE 3 %d", k); if(wv3 >= fib_ext_1_2_127_2 && wv3 <= fib_ext_1_2_161_8) { for(int l = k; l < bars_check - 7; l++) { if(IsSwingLow(low, l, 7) && time[l] > wv3_time) { wv4 = low[l]; wv4_time = time[l]; wv4_txt = StringFormat("WAVE 4 %d", l); wv3_wv4_size = MathAbs(wv3 - wv4); if(wv3_wv4_size >= wv1_wv2_size && wv4 > wv2 && wv4 < wv3) { ObjectCreate(chart_id, wv1_txt, OBJ_TEXT, 0, wv1_time, wv1); ObjectSetString(chart_id, wv1_txt, OBJPROP_TEXT, "WV1"); ObjectSetInteger(chart_id, wv1_txt, OBJPROP_COLOR, clrBlue); ObjectCreate(chart_id, wv2_txt, OBJ_TEXT, 0, wv2_time, wv2); ObjectSetString(chart_id, wv2_txt, OBJPROP_TEXT, "WV2"); ObjectSetInteger(chart_id, wv2_txt, OBJPROP_COLOR, clrBlue); fib_ext_wv1_wv2 = StringFormat("FIBO EXTENSION WAVE 1 AND 2 %d", i); ObjectCreate(chart_id, fib_ext_wv1_wv2, OBJ_EXPANSION, 0, wv2_time, wv2, wv1_time, wv1, wv2_time, wv2); ObjectSetInteger(chart_id, fib_ext_wv1_wv2, OBJPROP_COLOR, clrBlue); for(int i = 0; i <= 2; i++) { ObjectSetInteger(chart_id, fib_ext_wv1_wv2, OBJPROP_LEVELCOLOR, i, clrBlue); } perc_70 = StringFormat("70 PERCENT %d", j); ObjectCreate(chart_id, perc_70, OBJ_TREND, 0, wv1_time, wv1 - wv1_wv2_70p, wv2_time, wv1 - wv1_wv2_70p); fib_ext_range = StringFormat("Fibo EXPENSION RANGE%d", j); ObjectCreate(chart_id, fib_ext_range, OBJ_RECTANGLE, 0, wv1_time, fib_ext_1_2_161_8, wv2_time, fib_ext_1_2_127_2); ObjectCreate(chart_id, wv3_txt, OBJ_TEXT, 0, wv3_time, wv3); ObjectSetString(chart_id, wv3_txt, OBJPROP_TEXT, "WV3"); ObjectSetInteger(chart_id, wv3_txt, OBJPROP_COLOR, clrBlue); ObjectCreate(chart_id, wv4_txt, OBJ_TEXT, 0, wv4_time, wv4); ObjectSetString(chart_id, wv4_txt, OBJPROP_TEXT, "WV4"); ObjectSetInteger(chart_id, wv4_txt, OBJPROP_COLOR, clrBlue); } break; } } } break; } } break; } } } } }
Resultado:

Explicación:
Una vez que el programa haya identificado wv3, el siguiente paso es identificar wv4. Calculará la distancia entre wv3 y wv4 y la almacenará en wv3_wv4_size. Una vez que el programa detecta un mínimo de oscilación, almacena la hora y el precio de la barra en las variables wv4_time y wv4. El programa garantiza que wv3 y wv4 sean similares a wv1 y wv2, y también asegura que la onda 4 se mantenga por encima de la onda 2 y por debajo de la onda 3 para preservar la estructura correcta. El programa comprueba si wv3 se encuentra dentro de la expansión especificada. La onda 4, que completa la configuración del patrón utilizando la lógica de oscilación, los filtros de Fibonacci y los criterios de simetría, se marca en el gráfico una vez que se han superado todas las comprobaciones.


Como se puede ver en la primera imagen (Figura 11), la Onda 3 no es el máximo más alto durante la transición de la Onda 3 a la Onda 4. Se supone que la onda 3 es el pico más importante antes de la caída hacia la onda 4, por lo que esto resulta problemático. Nuestro mecanismo de detección no ha identificado la estructura correcta si se produce un máximo superior después del punto que hemos designado como Onda 3. La segunda imagen (Figura 12) también muestra que la onda 1 no es la más alta en la zona comprendida entre las ondas 1 y 2.
Además, esto incumple las reglas del patrón, ya que la Onda 1 debería ser el máximo oscilatorio dominante en ese tramo. No obtendremos resultados fiables para el patrón de onda de Wolfe si nuestro algoritmo sigue seleccionando puntos de onda que son, en esencia, incorrectos. Para aumentar la fiabilidad de la lógica de detección, es necesario resolver este problema.
Ahora añadiremos un paso de validación adicional para cada onda con el fin de resolver los problemas que hemos observado en los ejemplos anteriores. Para asegurarnos de que la onda 3 representa con precisión el pico anterior al descenso, debe ser el máximo alcanzado entre las ondas 3 y 4. La onda 2 debe ser el mínimo más bajo entre las ondas 2 y 3 para reflejar realmente el fondo antes de la siguiente tendencia alcista. La onda 1 debe ser el máximo más alto entre las ondas 1 y 2 para que se pueda reconocer fácilmente como el máximo de oscilación significativo en ese segmento del patrón.
Ejemplo:
int wv3_wv4_bars; int wv3_highest_index; double wv3_hh; datetime wv3_hh_t; int wv2_wv3_bars; int wv2_lowest_index; double wv2_ll; datetime wv2_ll_t; int wv1_wv2_bars; int wv1_highest_index; double wv1_hh; datetime wv1_hh_t;
for(int l = k; l < bars_check - 7; l++) { if(IsSwingLow(low, l, 7) && time[l] > wv3_time) { wv4 = low[l]; wv4_time = time[l]; wv4_txt = StringFormat("WAVE 4 %d", l); wv3_wv4_bars = Bars(_Symbol, timeframe, wv3_time, wv4_time); wv3_highest_index = ArrayMaximum(high, k, wv3_wv4_bars); wv3_hh = high[wv3_highest_index]; wv3_hh_t = time[wv3_highest_index]; wv2_wv3_bars = Bars(_Symbol, timeframe, wv2_time, wv3_time); wv2_lowest_index = ArrayMinimum(low, j, wv2_wv3_bars); wv2_ll = low[wv2_lowest_index]; wv2_ll_t = time[wv2_lowest_index]; wv1_wv2_bars = Bars(_Symbol, timeframe, wv1_time, wv2_time); wv1_highest_index = ArrayMaximum(high, i, wv1_wv2_bars); wv1_hh = high[wv1_highest_index]; wv1_hh_t = time[wv1_highest_index]; wv1_wv2_size = MathAbs(wv1_hh - wv2_ll); wv1_wv2_70p = (wv1_wv2_size / 100) * 70; fib_ext_1_2_127_2 = MathAbs((((wv1_hh - wv2_ll) / 100) * (min_fib_ext_wv12 - 100)) + wv1_hh); fib_ext_1_2_161_8 = MathAbs((((wv1_hh - wv2_ll) / 100) * (max_fib_ext_wv12 - 100)) + wv1_hh); wv3_wv4_size = MathAbs(wv3_hh - wv4); if(wv3_wv4_size >= wv1_wv2_size && wv4 > wv2_ll && wv4 < wv3_hh && wv3_hh >= fib_ext_1_2_127_2 && wv3_hh <= fib_ext_1_2_161_8) { ObjectCreate(chart_id, wv1_txt, OBJ_TEXT, 0, wv1_hh_t, wv1_hh); ObjectSetString(chart_id, wv1_txt, OBJPROP_TEXT, "WV1"); ObjectSetInteger(chart_id, wv1_txt, OBJPROP_COLOR, clrBlue); ObjectCreate(chart_id, wv2_txt, OBJ_TEXT, 0, wv2_ll_t, wv2_ll); ObjectSetString(chart_id, wv2_txt, OBJPROP_TEXT, "WV2"); ObjectSetInteger(chart_id, wv2_txt, OBJPROP_COLOR, clrBlue); fib_ext_wv1_wv2 = StringFormat("FIBO EXTENSION WAVE 1 AND 2 %d", i); ObjectCreate(chart_id, fib_ext_wv1_wv2, OBJ_EXPANSION, 0, wv2_ll_t, wv2_ll, wv1_hh_t, wv1_hh, wv2_ll_t, wv2_ll); ObjectSetInteger(chart_id, fib_ext_wv1_wv2, OBJPROP_COLOR, clrBlue); for(int i = 0; i <= 2; i++) ObjectSetInteger(chart_id, fib_ext_wv1_wv2, OBJPROP_LEVELCOLOR, i, clrBlue); perc_70 = StringFormat("70 PERCENT %d", j); ObjectCreate(chart_id, perc_70, OBJ_TREND, 0, wv1_hh_t, wv1_hh - wv1_wv2_70p, wv2_time, wv1 - wv1_wv2_70p); fib_ext_range = StringFormat("Fibo EXPENSION RANGE%d", j); ObjectCreate(chart_id, fib_ext_range, OBJ_RECTANGLE, 0, wv1_hh_t, fib_ext_1_2_161_8, wv2_ll_t, fib_ext_1_2_127_2); ObjectCreate(chart_id, wv3_txt, OBJ_TEXT, 0, wv3_hh_t, wv3_hh); ObjectSetString(chart_id, wv3_txt, OBJPROP_TEXT, "WV3"); ObjectSetInteger(chart_id, wv3_txt, OBJPROP_COLOR, clrBlue); ObjectCreate(chart_id, wv4_txt, OBJ_TEXT, 0, wv4_time, wv4); ObjectSetString(chart_id, wv4_txt, OBJPROP_TEXT, "WV4"); ObjectSetInteger(chart_id, wv4_txt, OBJPROP_COLOR, clrBlue); } break; } }
Resultado:

Explicación:
Proponemos una nueva serie de cálculos para verificar la estructura de la onda de Wolfe y asegurarnos de que cada punto de la onda represente con precisión el máximo o mínimo más importante de su segmento. Para identificar los valores extremos (máximo más alto o mínimo más bajo) entre cada segmento de onda, primero definimos una serie de variables: la variable wv3_wv4_bars contiene el número de barras que separan las ondas 3 y 4. A continuación, se obtiene el máximo dentro de ese rango utilizando ArrayMaximum para recorrer el número de barras wv3_wv4_bars y comenzar en el índice k (donde se encuentra la onda 3). La variable wv3_highest_index almacena el resultado. Este índice se utiliza para extraer el precio máximo real (wv3_hh) y su marca de tiempo (wv3_hh_t).
wv2_wv3_bars abarca la región comprendida entre las ondas 2 y 3, aunque funciona de manera similar. Aquí utilizamos ArrayMinimum, que devuelve el índice del precio más bajo, para encontrar el mínimo más bajo. Una vez guardado este índice en wv2_lowest_index, recuperamos el precio mínimo correspondiente (wv2_ll) y la hora (wv2_ll_t). El número de barras que separan las ondas 1 y 2 viene determinado por wv1_wv2_bars. En este caso, la Onda 1 debería ser un pico dominante; por lo tanto, volvemos a utilizar ArrayMaximum para obtener el máximo más alto de esa zona. Del índice resultante, que se almacena en wv1_highest_index, extraemos el precio máximo (wv1_hh) y la fecha correspondiente (wv1_hh_t).
En wv3_wv4_bars se registra el número de barras entre las Ondas 3 y 4. Para encontrar el máximo más alto dentro de ese rango, utilizamos ArrayMaximum para recorrer el número de barras wv3_wv4_bars y comenzamos en el índice k, que es donde se encuentra la onda 3. El resultado se guarda en wv3_highest_index. Este índice se utiliza para extraer la marca de tiempo (wv3_hh_t) y el precio máximo real (wv3_hh). Al aplicar estas restricciones mediante programación, aumentamos la precisión de nuestro reconocimiento de la onda de Wolfe y reducimos la probabilidad de identificar patrones de onda débiles o incorrectos. La fidelidad del patrón a los conceptos técnicos y su idoneidad para el análisis de operaciones en el mundo real están garantizadas por esta etapa de validación adicional.
Los puntos máximos o mínimos validados se utilizarán ahora para trazar los objetos en el gráfico, en lugar de los puntos de onda que se habían elegido inicialmente. En la primera onda, sustituiremos específicamente wv1_time y wv1 por wv1_hh_t y wv1_hh. Sustituiremos «wv2_ll_t» y «wv2_ll» por «wv2_time», y «wv2» por «Wave 2». Además, para la tercera onda, sustituiremos wv3_hh_t y wv3_hh por wv3_time y wv3. Con este ajuste, nos aseguramos de que nos referimos a los máximos y mínimos estructurales reales de cada segmento, en lugar de solo a los puntos de oscilación iniciales que se detectaron. Aumentamos considerablemente la precisión y la fiabilidad de la visualización de la onda de Wolfe al trazar los elementos del gráfico en estas zonas validadas, lo que ayuda a los operadores a tomar decisiones más fundamentadas basadas en una estructura de patrones más precisa.
Solo cuando se cumplan los siguientes criterios se generarán la extensión de Fibonacci, los elementos gráficos de las ondas 1 a 4 y otros componentes gráficos:
if(wv3_wv4_size >= wv1_wv2_size && wv4 > wv2_ll && wv4 < wv3_hh && wv3_hh >= fib_ext_1_2_127_2 && wv3_hh <= fib_ext_1_2_161_8)Esta condición garantiza que se cumplen todos los requisitos de precio y estructurales para una onda de Wolfe bajista válida. Esto confirma que las ondas 3 y 4 están separadas verticalmente al menos tanto como las ondas 1 y 2, lo que mantiene la simetría. Esto confirma aún más que la onda 4 se sitúa por encima del mínimo más bajo entre las ondas 2 y 3 y por debajo del máximo más alto entre las ondas 3 y 4. Además, la Onda 3 debe estar dentro del rango de expansión de Fibonacci del 127,2 % al 200 % en comparación con las Ondas 1 y 2.
El software no nombrará las ondas, no creará la proyección de Fibonacci ni indicará las líneas de tendencia necesarias en el gráfico hasta que se hayan cumplido todos estos requisitos. Esta rigurosa validación garantiza una mayor precisión en el reconocimiento de las ondas de Wolfe y ayuda a evitar que se dibujen patrones inexactos o incompletos.
Identificar la quinta onda
Identificar la onda 5 es el siguiente paso en nuestro procedimiento de detección de ondas de Wolfe. Dado que indica el posible punto de reversión del patrón, esta onda es fundamental. La onda 5 es una referencia clave en el análisis técnico, ya que los operadores suelen recurrir a ella para predecir un cambio en la dirección del mercado. Sin embargo, antes de poder identificarla correctamente, debemos trazar tres líneas de tendencia fundamentales que servirán para confirmar la Onda 5.
La línea de tendencia inicial unirá las ondas 1 y 3. Esta línea suele representar el límite superior del patrón en una onda de Wolfe bajista. Ayuda a definir la estructura y la dirección del patrón y actúa como un nivel de resistencia dentro del cual se mantiene el precio durante la formación de la onda 4 y el desarrollo de la onda 5. La segunda línea de tendencia unirá las ondas dos y cuatro. Esta línea es importante porque aclara la estructura del canal y la simetría de la onda de Wolfe. A medida que el precio se acerca al punto de reversión, ofrece una indicación general de la trayectoria prevista de la onda 5.
La tercera línea de tendencia, que une las ondas 1 y 4, tiene una función distinta a la de las dos primeras. Por lo general, esta línea se utiliza para determinar cuándo cerrar la operación. La línea que va de la onda 1 a la onda 4 sirve como objetivo de toma de ganancias en una onda de Wolfe bajista una vez que se ha identificado la onda 5 y el precio comienza a moverse en la dirección prevista. En cuanto el mercado cruce esta línea de tendencia, se cerrará la operación, ya que esto indica que se ha producido el movimiento previsto y que el patrón se ha completado.
Ejemplo:string tline_1_3; string tline_2_4; string tline_1_4;
if(wv3_wv4_size >= wv1_wv2_size && wv4 > wv2_ll && wv4 < wv3_hh && wv3_hh >= fib_ext_1_2_127_2 && wv3_hh <= fib_ext_1_2_161_8) { ObjectCreate(chart_id, wv1_txt, OBJ_TEXT, 0, wv1_hh_t, wv1_hh); ObjectSetString(chart_id, wv1_txt, OBJPROP_TEXT, "WV1"); ObjectSetInteger(chart_id, wv1_txt, OBJPROP_COLOR, clrBlue); ObjectCreate(chart_id, wv2_txt, OBJ_TEXT, 0, wv2_ll_t, wv2_ll); ObjectSetString(chart_id, wv2_txt, OBJPROP_TEXT, "WV2"); ObjectSetInteger(chart_id, wv2_txt, OBJPROP_COLOR, clrBlue); fib_ext_wv1_wv2 = StringFormat("FIBO EXTENSION WAVE 1 AND 2 %d", i); ObjectCreate(chart_id, fib_ext_wv1_wv2, OBJ_EXPANSION, 0, wv2_ll_t, wv2_ll, wv1_hh_t, wv1_hh, wv2_ll_t, wv2_ll); ObjectSetInteger(chart_id, fib_ext_wv1_wv2, OBJPROP_COLOR, clrBlue); for(int i = 0; i <= 2; i++) { ObjectSetInteger(chart_id, fib_ext_wv1_wv2, OBJPROP_LEVELCOLOR, i, clrBlue); } perc_70 = StringFormat("70 PERCENT %d", j); ObjectCreate(chart_id, perc_70, OBJ_TREND, 0, wv1_hh_t, wv1_hh - wv1_wv2_70p, wv2_time, wv1 - wv1_wv2_70p); fib_ext_range = StringFormat("Fibo EXPENSION RANGE%d", j); ObjectCreate(chart_id, fib_ext_range, OBJ_RECTANGLE, 0, wv1_hh_t, fib_ext_1_2_161_8, wv2_ll_t, fib_ext_1_2_127_2); ObjectCreate(chart_id, wv3_txt, OBJ_TEXT, 0, wv3_hh_t, wv3_hh); ObjectSetString(chart_id, wv3_txt, OBJPROP_TEXT, "WV3"); ObjectSetInteger(chart_id, wv3_txt, OBJPROP_COLOR, clrBlue); ObjectCreate(chart_id, wv4_txt, OBJ_TEXT, 0, wv4_time, wv4); ObjectSetString(chart_id, wv4_txt, OBJPROP_TEXT, "WV4"); ObjectSetInteger(chart_id, wv4_txt, OBJPROP_COLOR, clrBlue); tline_1_3 = StringFormat("TREND LINE WAVE 1 AND 3 %d", i); ObjectCreate(chart_id, tline_1_3, OBJ_TREND, 0, wv1_hh_t, wv1_hh, wv3_hh_t, wv3_hh); ObjectSetInteger(chart_id, tline_1_3, OBJPROP_COLOR, clrBlue); tline_2_4 = StringFormat("TREND LINE WAVE 2 AND 4 %d", i); ObjectCreate(chart_id, tline_2_4, OBJ_TREND, 0, wv2_ll_t, wv2_ll, wv4_time, wv4); ObjectSetInteger(chart_id, tline_2_4, OBJPROP_COLOR, clrBlue); tline_1_4 = StringFormat("TREND LINE WAVE 1 AND 4 %d", i); ObjectCreate(chart_id, tline_1_4, OBJ_TREND, 0, wv1_hh_t, wv1_hh, wv4_time, wv4); ObjectSetInteger(chart_id, tline_1_4, OBJPROP_COLOR, clrBlue); }
Resultado:

Explicación:
El objetivo de la declaración inicial de las variables de cadena tline_1_3, tline_2_4 y tline_1_4 es identificar de forma única las líneas de tendencia en el gráfico. En tline_1_3, el límite superior del patrón bajista de la onda de Wolfe viene dado por la línea de tendencia que une las ondas 1 y 3. La función ObjectCreate() se utiliza para crearlo a partir de los puntos más altos confirmados de las ondas 1 y 3, y se colorea de azul para facilitar su visualización. La segunda línea de tendencia, que une las ondas 2 y 4, se conserva en tline_2_4. El mínimo más bajo de la onda 2 (wv2_ll_t, wv2_ll) se traza entre el punto de la onda 4 (wv4_time, wv4), que también aparece resaltado en azul. Las ondas 1 y 4 están unidas por la tercera línea de tendencia, tline_1_4.
Las líneas de tendencia solo se generan entre dos puntos de referencia preestablecidos, lo cual supone un problema con este método. Cada línea de un patrón de onda de Wolfe auténtico debe prolongarse más allá de su segundo punto de anclaje para indicar posibles interacciones futuras entre el punto de anclaje y el precio. Por ejemplo, la línea de tendencia entre las ondas 1 y 3 no es simplemente un segmento corto entre esos dos puntos. Por el contrario, a menos que el mercado suba por encima de ese nivel y luego vuelva a caer por debajo, se espera que continúe más allá de la Onda 3 y en el futuro. Esta sección ampliada ofrece una visión más clara de la relación entre el precio y el límite superior del patrón a lo largo del tiempo.
Para mantener la simetría de la onda de Wolfe y predecir la ubicación probable de la onda 5, es necesario que la línea de tendencia entre las ondas 2 y 4 tenga la misma longitud y dirección que la línea entre las ondas 1 y 3. A medida que el precio se aproxima a la línea de tendencia, que sirve como objetivo de salida de la operación e indica cuándo cerrarla, esta también debe prolongarse más allá de la onda 4 para que sea válida. En otras palabras, las tres líneas de tendencia deben prolongarse adecuadamente hacia el futuro para ofrecer una confirmación precisa de la figura y preparar la operación.
Ejemplo:
tline_1_3 = StringFormat("TREND LINE WAVE 1 AND 3 %d", i); ObjectCreate(chart_id,tline_1_3,OBJ_TREND,0,wv1_hh_t,wv1_hh,wv3_hh_t,wv3_hh); ObjectSetInteger(chart_id, tline_1_3, OBJPROP_COLOR, clrBlue); ObjectSetInteger(chart_id, tline_1_3, OBJPROP_RAY_RIGHT, true); tline_2_4 = StringFormat("TREND LINE WAVE 2 AND 4 %d", i); ObjectCreate(chart_id,tline_2_4,OBJ_TREND,0,wv2_ll_t,wv2_ll,wv4_time,wv4); ObjectSetInteger(chart_id, tline_2_4, OBJPROP_COLOR, clrBlue); ObjectSetInteger(chart_id, tline_1_3, OBJPROP_RAY_RIGHT, true); tline_1_4 = StringFormat("TREND LINE WAVE 1 AND 4 %d", i); ObjectCreate(chart_id,tline_1_4,OBJ_TREND,0,wv1_hh_t,wv1_hh,wv4_time,wv4); ObjectSetInteger(chart_id, tline_1_4, OBJPROP_COLOR, clrBlue); ObjectSetInteger(chart_id, tline_1_3, OBJPROP_RAY_RIGHT, true);

El atributo OBJPROP_RAY_RIGHT garantiza que las líneas de tendencia se extiendan más allá de sus puntos de referencia, lo cual también supone un problema. Aunque esto podría resultar útil para mantener la visibilidad de las líneas, no se ajusta al comportamiento exacto que buscamos en el análisis de la onda de Wolfe. En nuestro caso, no queremos que las líneas de tendencia se prolonguen indefinidamente. Más bien, queremos que se detengan en un momento determinado, sobre todo cuando se da una circunstancia concreta.
La línea de tendencia que une las ondas 1 y 3, por ejemplo, solo debería extenderse hasta el punto en que el mercado la supere antes de volver a situarse por debajo. De este modo, se mantiene la precisión y el gráfico queda libre de líneas de tendencia superfluas y, tal vez, irrelevantes. Tenemos un mayor control, y la estructura visual del patrón de onda de Wolfe resulta más precisa y clara cuando establecemos una hora de finalización concreta para cada línea basándonos en la interacción real de los precios.
Ejemplo:tline_1_3 = StringFormat("TREND LINE WAVE 1 AND 3 %d", i); if(ObjectCreate(chart_id,tline_1_3,OBJ_TREND,0,wv1_hh_t,wv1_hh,wv3_hh_t,wv3_hh)) { ObjectSetInteger(chart_id, tline_1_3, OBJPROP_COLOR, clrBlue); ObjectSetInteger(chart_id, tline_1_3, OBJPROP_RAY_RIGHT, true); ObjectSetInteger(chart_id, tline_1_3, OBJPROP_TIMEFRAMES, OBJ_NO_PERIODS); } tline_2_4 = StringFormat("TREND LINE WAVE 2 AND 4 %d", i); if(ObjectCreate(chart_id,tline_2_4,OBJ_TREND,0,wv2_ll_t,wv2_ll,wv4_time,wv4)) { ObjectSetInteger(chart_id, tline_2_4, OBJPROP_COLOR, clrBlue); ObjectSetInteger(chart_id, tline_2_4, OBJPROP_RAY_RIGHT, true); ObjectSetInteger(chart_id, tline_2_4, OBJPROP_TIMEFRAMES, OBJ_NO_PERIODS); } tline_1_4 = StringFormat("TREND LINE WAVE 1 AND 4 %d", i); if(ObjectCreate(chart_id,tline_1_4,OBJ_TREND,0,wv1_hh_t,wv1_hh,wv4_time,wv4)) { ObjectSetInteger(chart_id, tline_1_4, OBJPROP_COLOR, clrBlue); ObjectSetInteger(chart_id, tline_1_4, OBJPROP_RAY_RIGHT, true); ObjectSetInteger(chart_id, tline_1_4, OBJPROP_TIMEFRAMES, OBJ_NO_PERIODS); }

Explicación:
Al configurar su atributo para ocultarla en todos los intervalos de tiempo, este código genera una línea de tendencia invisible que puede utilizarse internamente sin que se vea en el gráfico. A continuación, está atento a las oscilaciones significativas de los precios, como cuando una vela se cierra por encima y luego por debajo de esta línea de tendencia de la onda 1-3.
Ejemplo:double t_1_3_values; double t_2_4_values; string tline_1_3_visible; string tline_2_4_visible;
for(int m = l; m < bars_check - 2; m++) { t_1_3_values = ObjectGetValueByTime(chart_id, tline_1_3, time[m], 0); t_2_4_values = ObjectGetValueByTime(chart_id, tline_2_4, time[m], 0); if(close[m] > open[m] && open[m] < t_1_3_values && close[m] > t_1_3_values && time[m] > time[l+4]) { tline_1_3_visible = StringFormat("TREND LINE WAVE 1 AND 3 V %d", i); ObjectCreate(chart_id,tline_1_3_visible,OBJ_TREND,0,wv1_hh_t,wv1_hh,time[m],t_1_3_values); ObjectSetInteger(chart_id, tline_1_3_visible, OBJPROP_COLOR, clrBlue); tline_2_4_visible = StringFormat("TREND LINE WAVE 2 AND 4 V %d", i); ObjectCreate(chart_id,tline_2_4_visible,OBJ_TREND,0,wv2_ll_t,wv2_ll,time[m],t_2_4_values); ObjectSetInteger(chart_id, tline_2_4_visible, OBJPROP_COLOR, clrBlue); break; } }
Resultado:

Explicación:
Esta sección del código detecta cuándo el precio supera la línea de tendencia que une las ondas 1 y 3, analizando las barras posteriores a partir de la onda 4. Utiliza variables para obtener el nivel de precio de la línea de tendencia en el momento de cada barra y busca una vela alcista que abra por debajo pero cierre por encima de la línea de tendencia, lo que indica una ruptura que debe producirse al menos cuatro barras después de la Onda 4. Al detectar la ruptura, se generan dos líneas de tendencia visibles adicionales y se les asigna un nombre de forma dinámica mediante StringFormat. A continuación, el gráfico muestra estas líneas de tendencia: una que une la Onda 1 con el punto de ruptura y otra que une la Onda 2 con la misma posición. Esto te ayuda a observar y evaluar mejor el desarrollo del patrón de la onda de Wolfe, ya que te ofrece una indicación visual clara de la barra exacta en la que el precio supera la línea de tendencia de las ondas 1 y 3.
Pero ese no es nuestro objetivo. Aunque ayudan a resaltar la ruptura, las líneas de tendencia visibles que se generan cuando el mercado cruza y cierra por encima de la línea de tendencia de las ondas 1-3 aún no completan la estructura de la onda de Wolfe. El objetivo real es seguir prolongando estas líneas hasta que el mercado cruce y cierre por debajo de la línea de tendencia de las ondas 1-3.
Ejemplo:double t_1_3_values_2;for(int m = l; m < bars_check - 2; m++) { t_1_3_values = ObjectGetValueByTime(chart_id, tline_1_3, time[m], 0); if(close[m] > open[m] && open[m] < t_1_3_values && close[m] > t_1_3_values && time[m] > time[l+4]) { for(int n = m; n < bars_check - 1; n++) { t_1_3_values_2 = ObjectGetValueByTime(chart_id, tline_1_3, time[n], 0); t_2_4_values = ObjectGetValueByTime(chart_id, tline_2_4, time[n], 0); if(close[n] < open[n] && open[n] > t_1_3_values_2 && close[n] < t_1_3_values_2) { tline_1_3_visible = StringFormat("TREND LINE WAVE 1 AND 3 V %d", i); ObjectCreate(chart_id,tline_1_3_visible,OBJ_TREND,0,wv1_hh_t,wv1_hh,time[n],t_1_3_values_2); ObjectSetInteger(chart_id, tline_1_3_visible, OBJPROP_COLOR, clrBlue); tline_2_4_visible = StringFormat("TREND LINE WAVE 2 AND 4 V %d", i); ObjectCreate(chart_id,tline_2_4_visible,OBJ_TREND,0,wv2_ll_t,wv2_ll,time[n],t_2_4_values); ObjectSetInteger(chart_id, tline_2_4_visible, OBJPROP_COLOR, clrBlue); break; } } break; } }
Resultado:

Explicación:
Pero ese no es nuestro objetivo. Aunque ayudan a resaltar la ruptura, las líneas de tendencia visibles que se generan cuando el mercado cruza y cierra por encima de la línea de tendencia de las ondas 1-3 aún no completan la estructura de la onda de Wolfe. El objetivo real es seguir prolongando estas líneas hasta que el mercado cruce y cierre por debajo de la línea de tendencia de las ondas 1-3. En concreto, el bucle «for» interior utiliza la variable `t_1_3_values_2` para almacenar el nivel de precios de la línea de tendencia de la onda 1-3 en un momento posterior. Este bucle comienza a analizar el tramo posterior a la barra en la que se observó la ruptura al alza de la línea de tendencia (m). Utiliza ObjectGetValueByTime para recuperar el valor de la línea de tendencia en ese momento para cada barra n, y lo almacena en t_1_3_values_2.
La vela bajista que abrió por encima de la línea de tendencia y cerró por debajo de ella se detecta mediante la expresión if(close[n] < open[n] && open[n] > t_1_3_values_2 && close[n] < t_1_3_values_2), lo que indica que el precio ha vuelto a cruzar por debajo de la línea de tendencia. El hecho de que este punto marque con frecuencia el final de la onda 5 y el inicio del esperado cambio de tendencia hace que sea digno de mención. En cuanto se detecta este segundo cruce, se trazan dos líneas de tendencia bien definidas: una une la Onda 1 con este nuevo punto del gráfico, y la otra une la Onda 2 con el mismo punto. Esto ofrece una visión más completa y precisa de la onda de Wolfe, desde su inicio hasta la ruptura y la reversión, sustituyendo de hecho a las líneas de tendencia anteriores. Ahora, las líneas de tendencia se extienden desde sus puntos de partida hasta el punto exacto en el que la evolución del precio confirma la totalidad del patrón.
El siguiente paso es determinar el nivel de precios de la onda 5. Para ello, debemos determinar el máximo más alto entre dos puntos significativos: la primera vez que el mercado cruza y cierra por encima de la línea de tendencia de las ondas 1 a 3, y la segunda vez que se invierte y cruza por debajo de esa misma línea de tendencia. Por lo general, este rango indica la fase de conclusión del patrón de ondas de Wolfe. Antes de que se produzca el cambio de tendencia previsto, el precio suele dar un último repunte al alza en esta zona. Encontrar el máximo más alto en este intervalo nos permitirá identificar con precisión el punto álgido de la onda 5.
Ejemplo:int cross_bars; int cross_bars_highest; string wv5_txt;
if(close[m] > open[m] && open[m] < t_1_3_values && close[m] > t_1_3_values && time[m] > time[l+4]) { for(int n = m; n < bars_check - 1; n++) { t_1_3_values_2 = ObjectGetValueByTime(chart_id, tline_1_3, time[n], 0); t_2_4_values = ObjectGetValueByTime(chart_id, tline_2_4, time[n], 0); if(close[n] < open[n] && open[n] > t_1_3_values_2 && close[n] < t_1_3_values_2) { tline_1_3_visible = StringFormat("TREND LINE WAVE 1 AND 3 V %d", i); ObjectCreate(chart_id,tline_1_3_visible,OBJ_TREND,0,wv1_hh_t,wv1_hh,time[n],t_1_3_values_2); ObjectSetInteger(chart_id, tline_1_3_visible, OBJPROP_COLOR, clrBlue); tline_2_4_visible = StringFormat("TREND LINE WAVE 2 AND 4 V %d", i); ObjectCreate(chart_id,tline_2_4_visible,OBJ_TREND,0,wv2_ll_t,wv2_ll,time[n],t_2_4_values); ObjectSetInteger(chart_id, tline_2_4_visible, OBJPROP_COLOR, clrBlue); cross_bars = Bars(_Symbol,timeframe,time[n], time[m]); cross_bars_highest = ArrayMaximum(high,m,cross_bars); wv5_txt = StringFormat("WAVE 5 %d", i); ObjectCreate(chart_id, wv5_txt, OBJ_TEXT, 0, time[cross_bars_highest], high[cross_bars_highest]); ObjectSetString(chart_id, wv5_txt, OBJPROP_TEXT, "WV5"); ObjectSetInteger(chart_id, wv5_txt, OBJPROP_COLOR, clrBlue); break; } }
Explicación:
En este fragmento de código se identifica y se etiqueta la quinta onda del patrón de ondas de Wolfe. El algoritmo calcula el número de barras que hay entre los puntos de ruptura y de reversión para determinar el momento previsto en que se producirá la onda 5, una vez que el precio supere la línea de tendencia de las ondas 1-3 y luego vuelva a situarse por debajo de ella. A continuación, el código comienza en el índice m y recorre el número de barras de cross_bars utilizando la función ArrayMaximum() para buscar en la matriz de precios high[]. Esta función devuelve el índice de máximo más alto de ese intervalo, que indica el pico de la onda 5. La variable «cross_bars_highest» es donde se almacena este índice.
Para designar este máximo reconocido como «WV5», el código genera finalmente un objeto de texto en el gráfico. La etiqueta se coloca utilizando el valor de la fecha y el precio en el índice «cross_bars_highest», y su color se establece en azul para que se asemeje a las etiquetas de las ondas anteriores. De este modo se completa gráficamente la estructura de la onda de Wolfe en el gráfico, asegurando que la onda 5 quede correctamente señalada en el punto más alto entre la ruptura y el cambio de tendencia.
Expansión de Fibonacci
Como recordarás, ya hemos establecido que la onda 5 debe situarse dentro de un rango específico de la expansión generada por las ondas 3 y 4. Entre las ondas 3 y 4, este rango suele oscilar entre el 127,2 % y el 161,8 % de la variación de precio.
Ejemplo:input ENUM_TIMEFRAMES timeframe = PERIOD_CURRENT; // TIMEFRAME input double max_fib_ext_wv12 = 161.8; // WAVE 1 AND 2 FIBO EXTENSION MAX LEVEL input double min_fib_ext_wv12 = 127.2; // WAVE 1 AND 2 FIBO EXTENSION MIN LEVEL input double max_fib_ext_wv34 = 120.0; // WAVE 3 AND 4 FIBO EXTENSION MAX LEVEL input double min_fib_ext_wv34 = 200.0; // WAVE 3 AND 4 FIBO EXTENSION MIN LEVEL string fib_ext_3_4; double fib_ext_3_4_161_8; double fib_ext_3_4_127_2; string fib_ext_3_4_168_127; string fib_ext_range_3_4; int no_bars;
for(int l = k; l < bars_check - 7; l++) { if(IsSwingLow(low, l, 7) && time[l] > wv3_time) { wv4 = low[l]; wv4_time = time[l]; wv4_txt = StringFormat("WAVE 4 %d", l); wv3_wv4_bars = Bars(_Symbol, timeframe, wv3_time, wv4_time); wv3_highest_index = ArrayMaximum(high, k, wv3_wv4_bars); wv3_hh = high[wv3_highest_index]; wv3_hh_t = time[wv3_highest_index]; wv2_wv3_bars = Bars(_Symbol, timeframe, wv2_time, wv3_time); wv2_lowest_index = ArrayMinimum(low, j, wv2_wv3_bars); wv2_ll = low[wv2_lowest_index]; wv2_ll_t = time[wv2_lowest_index]; wv1_wv2_bars = Bars(_Symbol, timeframe, wv1_time, wv2_time); wv1_highest_index = ArrayMaximum(high, i, wv1_wv2_bars); wv1_hh = high[wv1_highest_index]; wv1_hh_t = time[wv1_highest_index]; wv1_wv2_size = MathAbs(wv1_hh - wv2_ll); wv1_wv2_70p = (wv1_wv2_size / 100) * 70; fib_ext_1_2_127_2 = MathAbs((((wv1_hh - wv2_ll) / 100) * (min_fib_ext_wv12 - 100)) + wv1_hh); fib_ext_1_2_161_8 = MathAbs((((wv1_hh - wv2_ll) / 100) * (max_fib_ext_wv12 - 100)) + wv1_hh); wv3_wv4_size = MathAbs(wv3_hh - wv4); if(wv3_wv4_size >= wv1_wv2_size && wv4 > wv2_ll && wv4 < wv3_hh && wv3_hh >= fib_ext_1_2_127_2 && wv3_hh <= fib_ext_1_2_161_8) { tline_1_3 = StringFormat("TREND LINE WAVE 1 AND 3 %d", i); if(ObjectCreate(chart_id,tline_1_3,OBJ_TREND,0,wv1_hh_t,wv1_hh,wv3_hh_t,wv3_hh)) { ObjectSetInteger(chart_id, tline_1_3, OBJPROP_COLOR, clrBlue); ObjectSetInteger(chart_id, tline_1_3, OBJPROP_RAY_RIGHT, true); ObjectSetInteger(chart_id, tline_1_3, OBJPROP_TIMEFRAMES, OBJ_NO_PERIODS); } tline_2_4 = StringFormat("TREND LINE WAVE 2 AND 4 %d", i); if(ObjectCreate(chart_id,tline_2_4,OBJ_TREND,0,wv2_ll_t,wv2_ll,wv4_time,wv4)) { ObjectSetInteger(chart_id, tline_2_4, OBJPROP_COLOR, clrBlue); ObjectSetInteger(chart_id, tline_2_4, OBJPROP_RAY_RIGHT, true); ObjectSetInteger(chart_id, tline_2_4, OBJPROP_TIMEFRAMES, OBJ_NO_PERIODS); } tline_1_4 = StringFormat("TREND LINE WAVE 1 AND 4 %d", i); if(ObjectCreate(chart_id,tline_1_4,OBJ_TREND,0,wv1_hh_t,wv1_hh,wv4_time,wv4)) { ObjectSetInteger(chart_id, tline_1_4, OBJPROP_COLOR, clrBlue); ObjectSetInteger(chart_id, tline_1_4, OBJPROP_RAY_RIGHT, true); ObjectSetInteger(chart_id, tline_1_4, OBJPROP_TIMEFRAMES, OBJ_NO_PERIODS); } fib_ext_3_4 = StringFormat("FIB EXTENSION WAVE 3 AND 4 %d", i); fib_ext_3_4_127_2 = MathAbs((((wv3_hh - wv4) / 100) * (min_fib_ext_wv34 - 100)) + wv3_hh); fib_ext_3_4_161_8 = MathAbs((((wv3_hh - wv4) / 100) * (max_fib_ext_wv34 - 100)) + wv3_hh); fib_ext_3_4_168_127 = StringFormat("FIB EXTENSION wv3 wv4 %d", i); for(int m = l; m < bars_check - 2; m++) { t_1_3_values = ObjectGetValueByTime(chart_id, tline_1_3, time[m], 0); if(close[m] > open[m] && open[m] < t_1_3_values && close[m] > t_1_3_values && time[m] > time[l+4]) { for(int n = m; n < bars_check - 1; n++) { t_1_3_values_2 = ObjectGetValueByTime(chart_id, tline_1_3, time[n], 0); t_2_4_values = ObjectGetValueByTime(chart_id, tline_2_4, time[n], 0); no_bars = Bars(_Symbol, timeframe, wv3_hh_t, time[n]); cross_bars = Bars(_Symbol,timeframe,time[n], time[m]); cross_bars_highest = ArrayMaximum(high,m,cross_bars); if(close[n] < open[n] && open[n] > t_1_3_values_2 && close[n] < t_1_3_values_2 && no_bars < 100 && time[n] > time[m] && high[cross_bars_highest] >= fib_ext_3_4_127_2 && high[cross_bars_highest] <= fib_ext_3_4_161_8) { ObjectCreate(chart_id, wv1_txt, OBJ_TEXT, 0, wv1_hh_t, wv1_hh); ObjectSetString(chart_id, wv1_txt, OBJPROP_TEXT, "WV1"); ObjectSetInteger(chart_id, wv1_txt, OBJPROP_COLOR, clrBlue); ObjectCreate(chart_id, wv2_txt, OBJ_TEXT, 0, wv2_ll_t, wv2_ll); ObjectSetString(chart_id, wv2_txt, OBJPROP_TEXT, "WV2"); ObjectSetInteger(chart_id, wv2_txt, OBJPROP_COLOR, clrBlue); fib_ext_wv1_wv2 = StringFormat("FIBO EXTENSION WAVE 1 AND 2 %d", i); ObjectCreate(chart_id, fib_ext_wv1_wv2, OBJ_EXPANSION, 0, wv2_ll_t, wv2_ll, wv1_hh_t, wv1_hh, wv2_ll_t, wv2_ll); ObjectSetInteger(chart_id, fib_ext_wv1_wv2, OBJPROP_COLOR, clrBlue); for(int i = 0; i <= 2; i++) { ObjectSetInteger(chart_id, fib_ext_wv1_wv2, OBJPROP_LEVELCOLOR, i, clrBlue); } perc_70 = StringFormat("70 PERCENT %d", j); ObjectCreate(chart_id, perc_70, OBJ_TREND, 0, wv1_hh_t, wv1_hh - wv1_wv2_70p, wv2_time, wv1 - wv1_wv2_70p); fib_ext_range = StringFormat("Fibo EXPENSION RANGE%d", j); ObjectCreate(chart_id, fib_ext_range, OBJ_RECTANGLE, 0, wv1_hh_t, fib_ext_1_2_161_8, wv2_ll_t, fib_ext_1_2_127_2); ObjectCreate(chart_id, wv3_txt, OBJ_TEXT, 0, wv3_hh_t, wv3_hh); ObjectSetString(chart_id, wv3_txt, OBJPROP_TEXT, "WV3"); ObjectSetInteger(chart_id, wv3_txt, OBJPROP_COLOR, clrBlue); ObjectCreate(chart_id, wv4_txt, OBJ_TEXT, 0, wv4_time, wv4); ObjectSetString(chart_id, wv4_txt, OBJPROP_TEXT, "WV4"); ObjectSetInteger(chart_id, wv4_txt, OBJPROP_COLOR, clrBlue); tline_1_3_visible = StringFormat("TREND LINE WAVE 1 AND 3 V %d", i); ObjectCreate(chart_id,tline_1_3_visible,OBJ_TREND,0,wv1_hh_t,wv1_hh,time[n],t_1_3_values_2); ObjectSetInteger(chart_id, tline_1_3_visible, OBJPROP_COLOR, clrBlue); tline_2_4_visible = StringFormat("TREND LINE WAVE 2 AND 4 V %d", i); ObjectCreate(chart_id,tline_2_4_visible,OBJ_TREND,0,wv2_ll_t,wv2_ll,time[n],t_2_4_values); ObjectSetInteger(chart_id, tline_2_4_visible, OBJPROP_COLOR, clrBlue); wv5_txt = StringFormat("WAVE 5 %d", i); ObjectCreate(chart_id, wv5_txt, OBJ_TEXT, 0, time[cross_bars_highest], high[cross_bars_highest]); ObjectSetString(chart_id, wv5_txt, OBJPROP_TEXT, "WV5"); ObjectSetInteger(chart_id, wv5_txt, OBJPROP_COLOR, clrBlue); ObjectCreate(chart_id, fib_ext_3_4,OBJ_EXPANSION, 0,wv4_time, wv4,wv3_hh_t,wv3_hh,wv4_time,wv4); for(int i = 0; i <= 2; i++) { ObjectSetInteger(chart_id,fib_ext_3_4,OBJPROP_LEVELCOLOR,i,clrBlue); ObjectSetInteger(chart_id,fib_ext_3_4,OBJPROP_COLOR,clrBlue); } fib_ext_range_3_4 = StringFormat("Fibo EXPENSION RANGE WV3 WV4 %d", i); ObjectCreate(chart_id,fib_ext_range_3_4,OBJ_RECTANGLE,0,wv3_hh_t,fib_ext_3_4_127_2,time[cross_bars_highest],fib_ext_3_4_161_8); break; } } break; } } } break; } }
Resultado:

Explicación:
Utiliza la expansión de Fibonacci de las ondas 3 y 4. Al calcular los niveles de Fibonacci y contar las barras entre la onda 3 y el cierre del precio por debajo de la línea de tendencia de las ondas 1 y 3, se garantiza que el patrón sea estructuralmente sólido y compacto. El EA busca una vela bajista concreta dentro del bloque de condiciones que supere la línea de tendencia de las ondas 1 a 3 antes de volver a cerrar por debajo de ella. La reversión debe producirse en un número adecuado de barras (menos de 100), y el precio más alto entre la ruptura y la reversión debe situarse dentro del rango de expansión de Fibonacci permitido, de acuerdo con otros parámetros. La quinta onda podría ser válida si se cumplen todos estos requisitos.
Las ondas 3 y 4 se utilizan entonces como tramos base para trazar un objeto de expansión de Fibonacci. Para mayor claridad, los tres niveles de expansión —0, 127,2 y 161,8— aparecen en azul. Para resaltar visualmente la zona objetivo de Fibonacci, también se dibuja un rectángulo. Es fundamental destacar que este bloque de condiciones es el único que se utiliza para generar todos los objetos relevantes del gráfico, como las zonas de expansión, las etiquetas y las líneas de tendencia. Esto reduce las señales falsas y aumenta la fiabilidad de la lógica de detección de la onda de Wolfe, al garantizar que el patrón completo solo se marque una vez que se hayan cumplido todas las reglas.
Dibujar la línea de tendencia de la onda 1 a la onda 4
Antes de dejar que el EA ejecute las operaciones, debemos trazar la línea de tendencia que une la onda 1 con la onda 4. Esta línea de tendencia desempeña un papel fundamental en el patrón de la onda de Wolfe, especialmente a la hora de planificar la salida.int no_wv1_n_bars; int no_n_c_bars; string tline_1_4_visible; double t_1_4_values; string tline_1_4_visible_2; if(close[n] < open[n] && open[n] > t_1_3_values_2 && close[n] < t_1_3_values_2 && no_bars < 100 && time[n] > time[m] && high[cross_bars_highest] >= fib_ext_3_4_127_2 && high[cross_bars_highest] <= fib_ext_3_4_161_8) { ObjectCreate(chart_id, wv1_txt, OBJ_TEXT, 0, wv1_hh_t, wv1_hh); ObjectSetString(chart_id, wv1_txt, OBJPROP_TEXT, "WV1"); ObjectSetInteger(chart_id, wv1_txt, OBJPROP_COLOR, clrBlue); ObjectCreate(chart_id, wv2_txt, OBJ_TEXT, 0, wv2_ll_t, wv2_ll); ObjectSetString(chart_id, wv2_txt, OBJPROP_TEXT, "WV2"); ObjectSetInteger(chart_id, wv2_txt, OBJPROP_COLOR, clrBlue); fib_ext_wv1_wv2 = StringFormat("FIBO EXTENSION WAVE 1 AND 2 %d", i); ObjectCreate(chart_id, fib_ext_wv1_wv2, OBJ_EXPANSION, 0, wv2_ll_t, wv2_ll, wv1_hh_t, wv1_hh, wv2_ll_t, wv2_ll); ObjectSetInteger(chart_id, fib_ext_wv1_wv2, OBJPROP_COLOR, clrBlue); for(int i = 0; i <= 2; i++) { ObjectSetInteger(chart_id, fib_ext_wv1_wv2, OBJPROP_LEVELCOLOR, i, clrBlue); } perc_70 = StringFormat("70 PERCENT %d", j); ObjectCreate(chart_id, perc_70, OBJ_TREND, 0, wv1_hh_t, wv1_hh - wv1_wv2_70p, wv2_time, wv1 - wv1_wv2_70p); fib_ext_range = StringFormat("Fibo EXPENSION RANGE%d", j); ObjectCreate(chart_id, fib_ext_range, OBJ_RECTANGLE, 0, wv1_hh_t, fib_ext_1_2_161_8, wv2_ll_t, fib_ext_1_2_127_2); ObjectCreate(chart_id, wv3_txt, OBJ_TEXT, 0, wv3_hh_t, wv3_hh); ObjectSetString(chart_id, wv3_txt, OBJPROP_TEXT, "WV3"); ObjectSetInteger(chart_id, wv3_txt, OBJPROP_COLOR, clrBlue); ObjectCreate(chart_id, wv4_txt, OBJ_TEXT, 0, wv4_time, wv4); ObjectSetString(chart_id, wv4_txt, OBJPROP_TEXT, "WV4"); ObjectSetInteger(chart_id, wv4_txt, OBJPROP_COLOR, clrBlue); tline_1_3_visible = StringFormat("TREND LINE WAVE 1 AND 3 V %d", i); ObjectCreate(chart_id,tline_1_3_visible,OBJ_TREND,0,wv1_hh_t,wv1_hh,time[n],t_1_3_values_2); ObjectSetInteger(chart_id, tline_1_3_visible, OBJPROP_COLOR, clrBlue); tline_2_4_visible = StringFormat("TREND LINE WAVE 2 AND 4 V %d", i); ObjectCreate(chart_id,tline_2_4_visible,OBJ_TREND,0,wv2_ll_t,wv2_ll,time[n],t_2_4_values); ObjectSetInteger(chart_id, tline_2_4_visible, OBJPROP_COLOR, clrBlue); wv5_txt = StringFormat("WAVE 5 %d", i); ObjectCreate(chart_id, wv5_txt, OBJ_TEXT, 0, time[cross_bars_highest], high[cross_bars_highest]); ObjectSetString(chart_id, wv5_txt, OBJPROP_TEXT, "WV5"); ObjectSetInteger(chart_id, wv5_txt, OBJPROP_COLOR, clrBlue); ObjectCreate(chart_id, fib_ext_3_4,OBJ_EXPANSION, 0,wv4_time, wv4,wv3_hh_t,wv3_hh,wv4_time,wv4); for(int i = 0; i <= 2; i++) { ObjectSetInteger(chart_id,fib_ext_3_4,OBJPROP_LEVELCOLOR,i,clrBlue); ObjectSetInteger(chart_id,fib_ext_3_4,OBJPROP_COLOR,clrBlue); } fib_ext_range_3_4 = StringFormat("Fibo EXPENSION RANGE WV3 WV4 %d", i); ObjectCreate(chart_id,fib_ext_range_3_4,OBJ_RECTANGLE,0,wv3_hh_t,fib_ext_3_4_127_2,time[cross_bars_highest],fib_ext_3_4_161_8); no_wv1_n_bars = Bars(_Symbol, timeframe, wv1_hh_t, time[n]); no_n_c_bars = Bars(_Symbol, timeframe, time[n], TimeCurrent()); if(no_n_c_bars <= no_wv1_n_bars) { t_1_4_values = ObjectGetValueByTime(chart_id, tline_1_4, TimeCurrent(), 0); tline_1_4_visible = "TL WAVE 1 AND 4 Visible"; ObjectCreate(chart_id,tline_1_4_visible,OBJ_TREND,0,wv1_hh_t,wv1_hh,TimeCurrent(),t_1_4_values); ObjectSetInteger(chart_id,tline_1_4_visible,OBJPROP_STYLE,STYLE_DASH); ObjectSetInteger(chart_id,tline_1_4_visible,OBJPROP_COLOR,clrBlue); } if(no_n_c_bars > no_wv1_n_bars) { ObjectDelete(chart_id,tline_1_4_visible); t_1_4_values = ObjectGetValueByTime(chart_id, tline_1_4, time[n + no_wv1_n_bars], 0); tline_1_4_visible_2 = StringFormat("TL WAVE 1 AND 4 DISPLAY %d", i); ObjectCreate(chart_id,tline_1_4_visible_2,OBJ_TREND,0,wv1_hh_t,wv1_hh,time[n+no_wv1_n_bars],t_1_4_values); ObjectSetInteger(chart_id,tline_1_4_visible_2,OBJPROP_STYLE,STYLE_DASH); ObjectSetInteger(chart_id,tline_1_4_visible_2,OBJPROP_COLOR,clrBlue); } break; }
Explicación:
El número de barras entre dos puntos importantes se determina mediante las variables «no_wv1_n_bars» y «no_n_c_bars». El número de barras entre la marca de tiempo de la Onda 1 y la marca de tiempo en la que el mercado cambió de tendencia, al volver a cruzar por debajo de la línea de tendencia, viene determinado específicamente por la función no_wv1_n_bars. Por el contrario, «no_n_c_bars» cuenta el número de barras que separan la barra actual del gráfico del punto de reversión (Onda 5). Esta comparación ayuda a determinar si la línea de tendencia que va de la onda 1 a la 4 debería alcanzar una barra futura concreta o el mercado actual.
Se traza una línea de tendencia con la etiqueta «TL WAVE 1 AND 4 Visible» entre la Onda 1 y hasta el momento actual del mercado si la barra actual se encuentra todavía dentro del rango que definen la Onda 1 y el punto de reversión (no_n_c_bars <= no_wv1_n_bars). La función `ObjectGetValueByTime` se utiliza para recuperar el valor actual de la línea de tendencia y, para facilitar su visualización, la línea se muestra en azul y con trazo discontinuo.
La línea trazada anteriormente se elimina mediante ObjectDelete, aunque si el número de barras tras el punto de reversión es mayor que el intervalo entre la Onda 1 y la reversión. Para garantizar que cubra la misma distancia que la proyección inicial, en este caso se traza una nueva línea de tendencia, que se extiende desde la Onda 1 hasta un punto determinado en el futuro (tiempo[n + no_wv1_n_bars]). Esta nueva línea tiene una etiqueta dinámica y presenta un diseño en azul con una línea discontinua. Aunque se adapta visiblemente a las actualizaciones en tiempo real del gráfico, este algoritmo garantiza que la línea de tendencia de la Onda 1 a la Onda 4 se mantenga constante y clara.
Ejecución de operaciones
A día de hoy, hemos identificado correctamente las cinco ondas del patrón de onda de Wolfe, de la 1 a la 5, junto con las tres líneas de tendencia clave que conectan la onda 1 con la 3, la onda 2 con la 4 y la onda 1 con la 4. Además de ofrecer una confirmación visual del patrón, estas líneas de tendencia también sirven de referencia para nuestras decisiones a la hora de ejecutar operaciones.
El siguiente paso es llevar a cabo la operación de acuerdo con la estructura previamente establecida. La condición de entrada para un patrón bajista de onda de Wolfe está estrechamente relacionada con la forma en que el precio se mueve alrededor de la línea de tendencia que une la onda 1 y la onda 3. En concreto, la vela debe cruzar primero por encima de esta línea de tendencia, lo que sugiere que la subida podría estar llegando a su fin, y luego volver a cruzar por debajo de ella. Este segundo movimiento es un buen momento para abrir una posición de venta, ya que confirma que el mercado podría empezar a revertir su tendencia a la baja. El EA no debe iniciar una operación hasta que se haya completado esta confirmación en dos pasos.
Ejemplo:
#include <Trade/Trade.mqh> CTrade trade; input int MagicNumber = 6160; input double lot_size = 0.01; input ENUM_TIMEFRAMES timeframe = PERIOD_CURRENT; // TIMEFRAME input double max_fib_ext_wv12 = 161.8; // WAVE 1 AND 2 FIBO EXTENSION MAX LEVEL input double min_fib_ext_wv12 = 127.2; // WAVE 1 AND 2 FIBO EXTENSION MIN LEVEL input double max_fib_ext_wv34 = 200.0; // WAVE 3 AND 4 FIBO EXTENSION MAX LEVEL input double min_fib_ext_wv34 = 120.0; // WAVE 3 AND 4 FIBO EXTENSION MIN LEVEL
datetime time_exe[]; datetime lastTradeBarTime = 0; double ask_price; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- trade.SetExpertMagicNumber(MagicNumber); ArraySetAsSeries(time_exe,true); //--- return(INIT_SUCCEEDED); }
//+------------------------------------------------------------------+ //| 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); CopyTime(_Symbol, timeframe, 0, 2, time_exe); datetime currentBarTime = iTime(_Symbol, timeframe, 0); ask_price = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
if(time[n] == time_exe[1] && currentBarTime != lastTradeBarTime) { trade.Sell(lot_size,_Symbol,ask_price, high[cross_bars_highest],wv2_ll); lastTradeBarTime = currentBarTime; }
Resultado:

Explicación:
La biblioteca de operaciones MQL5 integrada se importa en la primera línea, #include, lo que permite a la clase CTrade acceder a las funciones de gestión de operaciones. Tras incluir esta biblioteca, se crea un objeto de CTrade denominado «trade». Este objeto se encarga de ejecutar operaciones como la compra, la venta, el establecimiento de órdenes de take-profit y stop-loss, y la gestión de las órdenes. MagicNumber y lot_size son las dos siguientes variables de entrada definidas. Las operaciones de este EA se identifican de forma única mediante su «MagicNumber», lo que facilita su distinción de otras operaciones que puedan realizarse en la misma cuenta. El tamaño de la operación (lot_size), que en este caso es de 0,01 lotes, indica el volumen o la magnitud de la operación que se va a realizar.
A continuación, se declaran algunas variables: time_exe[], lastTradeBarTime y ask_price. La matriz «time_exe» almacenará los datos temporales de las barras más recientes. La variable `lastTradeBarTime` se inicializa en cero y se utiliza para evitar que el EA ejecute varias operaciones en la misma barra. «ask_price» se utiliza para almacenar el precio Ask actual del valor, que es el precio al que se puede ejecutar una operación de venta. La línea `trade.SetExpertMagicNumber(MagicNumber);` asigna el «número mágico» al objeto de operación, de modo que todas las operaciones que realice puedan identificarse posteriormente. ArraySetAsSeries(time_exe, true); establece que la matriz time_exe se trate como una serie temporal, lo que significa que el índice 0 corresponde a la barra más reciente.
A continuación, se utiliza CopyTime(_Symbol, timeframe, 0, 2, time_exe); para copiar los valores de tiempo de las dos últimas barras en la matriz time_exe. A continuación, la instrucción `datetime currentBarTime = iTime(_Symbol, timeframe, 0);` obtiene la hora de apertura de la barra que se está formando en ese momento. La línea `ask_price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);` obtiene el precio Ask actual del instrumento de negociación, lo cual es necesario para abrir una posición de venta.
Ahora bien, la condición if (time[n] == time_exe[1] && currentBarTime != lastTradeBarTime) comprueba si la hora almacenada en time[n] coincide con la hora de apertura de la segunda barra más reciente (time_exe[1]) y garantiza que aún no se haya ejecutado ninguna operación en la barra actual mediante la comparación con lastTradeBarTime. Si esta condición se cumple, el EA procede a realizar una operación de venta mediante trade.Sell(). La operación se abre al precio Ask actual, con el stop loss fijado en un nivel demasiado alto [cross_bars_highest] (que probablemente represente el máximo de la onda 5) y el take profit fijado en wv2_ll (el mínimo de la onda 2, que podría ser el nivel objetivo). Por último, la variable «lastTradeBarTime» se actualiza con la hora de la barra actual para evitar que se realicen varias entradas dentro de la misma vela.
Ten en cuenta el último punto fundamental de nuestra lista: garantizar que las salidas de las operaciones sean adecuadas. Tras ejecutar una operación basada en el patrón de la Onda de Wolfe, debemos implementar una lógica que cierre automáticamente la operación cuando el mercado toque la línea de tendencia que une la Onda 1 y la Onda 4. Esta línea nos sirve como objetivo de salida porque, en teoría, se espera que el precio cambie de tendencia en esa zona. Además, debemos prever medidas de protección para evitar mantener las posiciones abiertas durante demasiado tiempo. Si el precio no alcanza la línea de tendencia en un número razonable de barras (velas), el EA debería cerrar la operación de todos modos. Esto nos ayuda a evitar riesgos y exposiciones innecesarios en situaciones en las que el patrón falla o cambian las condiciones del mercado.
Ejemplo:double low_m[]; double high_m[]; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- trade.SetExpertMagicNumber(MagicNumber); ArraySetAsSeries(time_exe,true); ArraySetAsSeries(low_m,true); ArraySetAsSeries(high_m,true); //--- return(INIT_SUCCEEDED); }
CopyLow(_Symbol, timeframe, 0, 3, low_m); CopyHigh(_Symbol, timeframe, 0, 3, high_m);
if(no_n_c_bars <= no_wv1_n_bars) { t_1_4_values = ObjectGetValueByTime(chart_id, tline_1_4, TimeCurrent(), 0); tline_1_4_visible = "TL WAVE 1 AND 4 Visible"; ObjectCreate(chart_id,tline_1_4_visible,OBJ_TREND,0,wv1_hh_t,wv1_hh,TimeCurrent(),t_1_4_values); ObjectSetInteger(chart_id,tline_1_4_visible,OBJPROP_STYLE,STYLE_DASH); ObjectSetInteger(chart_id,tline_1_4_visible,OBJPROP_COLOR,clrBlue); if(time[n] == time_exe[1] && currentBarTime != lastTradeBarTime) { trade.Sell(lot_size,_Symbol,ask_price, high[cross_bars_highest],wv2_ll); lastTradeBarTime = currentBarTime; } for(int i = 0; i < PositionsTotal(); i++) { ulong ticket = PositionGetTicket(i); datetime positionTime = 0; if(PositionSelectByTicket(ticket)) { if(PositionGetInteger(POSITION_MAGIC) == MagicNumber && PositionGetString(POSITION_SYMBOL) == ChartSymbol(chart_id)) { positionTime = (datetime)PositionGetInteger(POSITION_TIME); if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) { double pos_bars = Bars(_Symbol, timeframe, positionTime, TimeCurrent()); if((ask_price < t_1_4_values || low_m[1] < t_1_4_values || no_n_c_bars == no_wv1_n_bars) && no_n_c_bars == pos_bars+1) { trade.PositionClose(ticket); } } } } } } if(no_n_c_bars > no_wv1_n_bars) { ObjectDelete(chart_id,tline_1_4_visible); t_1_4_values = ObjectGetValueByTime(chart_id, tline_1_4, time[n + no_wv1_n_bars], 0); tline_1_4_visible_2 = StringFormat("TL WAVE 1 AND 4 DISPLAY %d", i); ObjectCreate(chart_id,tline_1_4_visible_2,OBJ_TREND,0,wv1_hh_t,wv1_hh,time[n+no_wv1_n_bars],t_1_4_values); ObjectSetInteger(chart_id,tline_1_4_visible_2,OBJPROP_STYLE,STYLE_DASH); ObjectSetInteger(chart_id,tline_1_4_visible_2,OBJPROP_COLOR,clrBlue); }
Resultado:

Explicación:
En la primera sección del código se declaran dos matrices: double low_m[]; y double high_m[];. En estas matrices se guardan los precios mínimos y máximos más recientes del gráfico. Al igual que ocurre con el comportamiento habitual de los gráficos en MetaTrader 5, las líneas `ArraySetAsSeries(low_m, true);` y `ArraySetAsSeries(high_m, true);` invierten la indexación de las matrices, de modo que el índice 0 siempre se corresponda con la barra más reciente. Para ello es necesario comparar los niveles de precios actuales o recientes con los valores de las líneas de tendencia más relevantes.
A continuación, los tres últimos precios mínimos y máximos del gráfico se añaden a las matrices low_m y high_m, respectivamente, utilizando los métodos CopyLow(_Symbol, timeframe, 0, 3, low_m); y CopyHigh(_Symbol, timeframe, 0, 3, high_m);. En estos puntos, se analiza el precio para determinar si ha tocado o ha cruzado por debajo de una línea de tendencia concreta, como la línea de tendencia de la Onda 1 a la 4.
Si la posición es una operación de venta, que es lo que indica el patrón de onda de Wolfe en un escenario bajista, el código calcula cuántas barras han transcurrido desde que se abrió la operación utilizando Bars(_Symbol, timeframe, positionTime, TimeCurrent()). Por último, una condición comprueba si el mercado ha alcanzado el punto de salida. En concreto, evalúa si:
- El precio Ask actual se encuentra por debajo de la línea de tendencia de las ondas 1 a 4 (t_1_4_values), o
- El mínimo de la vela anterior (low_m[1]) ha atravesado esa línea de tendencia, o
- El número de barras desde la entrada es igual al número de barras que se necesitarían para alcanzar la línea de tendencia de la Onda 1 a la 4 (no_n_c_bars == no_wv1_n_bars), y
- La posición ha estado abierta exactamente ese número de barras (no_n_c_bars == pos_bars + 1)
El EA lo utiliza para cerrar la posición si se cumplen todos estos criterios, ya que esto indica que la operación ha alcanzado su punto de salida previsto o se ha mantenido abierta durante un tiempo excesivo. Ticket; PositionClose. Para garantizar que el EA asocie correctamente una operación abierta con el patrón de onda de Wolfe más reciente, se utiliza la condición no_n_c_bars == pos_bars + 1. En la lógica de este asesor experto, el bot busca varios patrones de onda de Wolfe a lo largo de un número predeterminado de barras. Sin embargo, solo realiza una operación cuando time[n] == time_exe[1]. Esto garantiza que la operación se realice en el mismo momento en que se haya confirmado la última formación.
El número de barras transcurridas desde que se abrió la operación viene representado por la variable `pos_bars`, que se calcula para mantener esta correspondencia entre la señal y la ejecución. Por el contrario, «no_n_c_bars» determina el número de barras transcurridas entre el momento actual y el punto de confirmación de la onda de Wolfe (tiempo[n]). Se indica al EA que la operación se inició a partir de este patrón concreto y no de uno anterior si estos dos valores coinciden, ya que no_n_c_bars == pos_bars + 1.
Esto es fundamental porque, aunque el EA pueda detectar varias «ondas de Wolfe» en el gráfico, solo debe gestionar y cerrar la operación que coincida con la más reciente. Si no se cumple este requisito, el bot podría detener o interrumpir involuntariamente las operaciones derivadas de señales anteriores. El EA garantiza un procesamiento preciso de las transacciones, evita conflictos entre señales y asegura un comportamiento coherente en la ejecución y la gestión de riesgos al verificar esta alineación.
Identificación de los patrones alcistas de la onda de Wolfe
El patrón alcista de la onda de Wolfe es simplemente lo contrario del patrón bajista de la onda de Wolfe que hemos comentado anteriormente. Dado que la estructura y la lógica son muy similares, no nos detendremos demasiado en volver a explicar cada detalle. En su lugar, solo resaltaremos las partes que están invertidas o son diferentes. En este caso, buscamos una estructura de cinco ondas que apunte a una posible oportunidad de compra, más que a una de venta.
La onda 1, que constituye la primera base de una onda de Wolfe alcista, debe ser un mínimo de oscilación. Si no se rompe a la baja la Onda 1, la Onda 3 debería marcar otro mínimo de oscilación tras la Onda 2, que debe ser un máximo de oscilación. Para que se complete la configuración alcista, la onda 5 debe marcar un mínimo de oscilación final y la onda 4 debe ser un máximo oscilatorio, normalmente inferior al de la onda 2.
Las ondas 1 a 3 deben ser los puntos más bajos o más altos entre las ondas adyacentes, mientras que la onda 5 debe situarse entre el 127,2 % y el 161,8 % de la expansión de Fibonacci de las ondas 3 y 4. Los usuarios pueden ajustar la sensibilidad de la detección de patrones modificando estos rangos. Para mejorar la fiabilidad de la entrada, el precio debe primero situarse por debajo y luego superar la línea de tendencia entre las ondas 1 y 3. La línea de las ondas 1 a 4 se utiliza con frecuencia como objetivo de cierre de ganancias. Se trazan automáticamente líneas de tendencia importantes que unen las ondas 1-3, 2-4 y 1-4 para facilitar el reconocimiento de patrones y la planificación de la salida de la operación.

Conclusión
En este artículo se describe cómo hemos creado un asesor experto en MQL5 capaz de reconocer formaciones de la onda de Wolfe tanto alcistas como bajistas. Hemos visto cómo utilizar los máximos y mínimos de oscilación para identificar la estructura de cinco ondas, aplicar los niveles de expansión de Fibonacci, trazar líneas de tendencia importantes y entrar en operaciones solo cuando se cumplan todos los requisitos. Aunque el rango típico de Fibonacci se sitúa entre el 127,2 % y el 161,8 %, cada uno puede modificar estas cifras para adaptarlas a sus propios planes. Este proyecto ofrece una base sólida para desarrollar sistemas de negociación más sofisticados basados en patrones, además de automatizar un patrón gráfico complejo.
Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/18884
Advertencia: todos los derechos de estos materiales pertenecen a MetaQuotes Ltd. Queda totalmente prohibido el copiado total o parcial.
Este artículo ha sido escrito por un usuario del sitio web y refleja su punto de vista personal. MetaQuotes Ltd. no se responsabiliza de la exactitud de la información ofrecida, ni de las posibles consecuencias del uso de las soluciones, estrategias o recomendaciones descritas.
De novato a experto: Noticias animadas utilizando MQL5 (VII) Estrategia para el trading de noticias tras el impacto
Simulación de mercado: Position View (VIII)
Redes neuronales en el trading: Modelo multivariado de extremo a extremo para la predicción de series temporales (GinAR)
Optimización Extrema — Extremal Optimization (EO)
- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso