La Configuración
Para utilizar el indicador ZigZag basado en Fibonacci, necesitaremos lo siguiente:
- 1 gráfico de zigzag
- 2 buffers de datos para los máximos y mínimos
- parámetros de entrada
- un conjunto de variables del sistema que se reinician cada vez que el indicador recalcula
El array upWaves almacenará los máximos y el array dwWaves almacenará los mínimos.
Variables del sistema:
Debemos conocer el último tipo de ola, dónde comenzó, dónde terminó, la distancia en barras desde el inicio hasta el final.
También necesitaremos una variable de máximo local, una de mínimo local, así como distancias en barras desde cada punto.
//--- llevamos un registro del zigzag int wave_type=0; // tipo de ola [0] ninguna [1] arriba [2] abajo double wave_start_price=0.0; // precio de inicio de la ola double wave_end_price=0.0; // precio final de la ola int wave_start_distance=0; // distancia en barras desde el precio de inicio int wave_end_distance=0; // distancia en barras desde el precio final //--- seguimiento de precios máximos double high_mem=0.0; int distance_from_high=0; //--- seguimiento de precios mínimos double low_mem=0.0; int distance_from_low=0; //--- cálculo del ATR móvil double rollingAtr=0.0; int rollingAtrs=0;
Finalmente, el ATR móvil y cuántos se han calculado.
Luego creamos una función para reiniciar el sistema:
void resetSystem(){
ArrayFill(upWaves,0,ArraySize(upWaves),0.0);
ArrayFill(dwWaves,0,ArraySize(dwWaves),0.0);
wave_type=0;
wave_start_price=0.0;
wave_end_price=0.0;
wave_start_distance=0;
wave_end_distance=0;
high_mem=0.0;
low_mem=0.0;
distance_from_high=0;
distance_from_low=0;
rollingAtr=0.0;
rollingAtrs=0;
}
Esto es lo estándar: llenar los arrays con ceros y reiniciar las variables del sistema.
En OnInit configuramos los buffers, el gráfico y llamamos a reset por primera vez:
SetIndexBuffer(0,upWaves,INDICATOR_DATA); SetIndexBuffer(1,dwWaves,INDICATOR_DATA); PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0); PlotIndexSetInteger(0,PLOT_DRAW_TYPE,DRAW_ZIGZAG); PlotIndexSetInteger(0,PLOT_LINE_COLOR,0,Color); PlotIndexSetInteger(0,PLOT_LINE_WIDTH,Width); PlotIndexSetInteger(0,PLOT_LINE_STYLE,Style); resetSystem();
Ahora, ¡vamos al cálculo!
Lo primero que debemos cuidar es el ATR móvil.
Hasta que hayamos recolectado más barras que el período del ATR, no haremos nada más.
La parte que maneja el ATR móvil es la siguiente:
- si no hemos recolectado más que el período, seguimos sumando el rango de las barras encontradas
- una vez que alcanzamos el período, realizamos la primera división (promedio)
- después, recortamos una porción del ATR móvil, que es ATR/período, y luego añadimos una nueva porción que es rango de la barra/período
//--- gestionar el ATR
rollingAtrs++;
if(rollingAtrs>rollingAtrPeriod){
double new_portion=((high[i]-low[i])/_Point)/((double)rollingAtrPeriod);
//--- eliminamos una porción antigua y añadimos una nueva
rollingAtr=(rollingAtr)-(rollingAtr/((double)rollingAtrPeriod))+new_portion;
}
else if(rollingAtrs<=rollingAtrPeriod){
rollingAtr+=(high[i]-low[i])/_Point;
if(rollingAtrs==rollingAtrPeriod){
rollingAtr/=((double)rollingAtrs);
//--- iniciamos la memoria para altos y bajos y el sistema
high_mem=high[i];
low_mem=low[i];
distance_from_high=0;
distance_from_low=0;
}
}
¡Genial! Ahora hay otro asunto.
La base de este zigzag es un retroceso.
Pero para que ocurra un retroceso, debe haber al menos una ola.
¿Pero de qué se va a retroceder la primera ola?
Por eso haremos lo siguiente:
- tan pronto como el ATR se llene (ATR recolectado = período), tomaremos el máximo y el mínimo en nuestras variables del sistema
- cualquiera de los lados que logre formar una ola que tenga un tamaño válido en unidades de ATR y forme un nuevo máximo (ola ascendente) o un nuevo mínimo (ola descendente) ganará
De este modo, no tenemos un retroceso como ola inicial, pero debemos comenzar la secuencia de alguna manera.
Esto es lo que hacemos mientras no tengamos una ola:
//--- si aún no tenemos un tipo de ola
else{
//--- si rompimos el máximo y no el mínimo
if(high[i]>high_mem&&low[i]>=low_mem){
double new_wave_size_in_atr_units=((high[i]-low_mem)/_Point)/rollingAtr;
//--- si el nuevo tamaño de ola es válido
if(new_wave_size_in_atr_units>=minSizeInAtrUnits){
//--- iniciamos una nueva ola ascendente
wave_type=1;
wave_start_price=low_mem;
wave_start_distance=distance_from_low;
wave_end_price=high[i];
wave_end_distance=0;
upWaves[i]=high[i];
high_mem=high[i];
distance_from_high=0;
low_mem=low[i];
distance_from_low=0;
}
}
//--- si rompimos el mínimo y no el máximo
else if(low[i]=minSizeInAtrUnits){
//--- iniciamos una nueva ola descendente
wave_type=-1;
wave_start_price=high_mem;
wave_start_distance=distance_from_high;
wave_end_price=low[i];
wave_end_distance=0;
dwWaves[i]=low[i];
low_mem=low[i];
distance_from_low=0;
}
}
}
¡Fantástico! Ahora, la pieza final.
- Si tenemos una ola ascendente:
- si se hace un nuevo máximo, movemos el zigzag desde la posición anterior del máximo a la nueva posición del máximo, lo que podemos hacer ya que retenemos las distancias en barras. También actualizamos el mínimo y la distancia desde el mínimo. Hacemos esto para poder capturar el mínimo más bajo desde el pico y verificar si retrocede lo suficiente como para iniciar un nuevo mínimo.
- si se hace un nuevo mínimo o se establece un nuevo mínimo, calculamos la distancia desde el pico hasta el mínimo y la dividimos por el tamaño de la ola. También lo multiplicamos por 100 para coincidir con la escala del parámetro de entrada. Entonces, si el tamaño de la nueva "sería" ola que retrocede la anterior también es válida contra las unidades de ATR, iniciamos una nueva ola descendente, establecemos los nuevos máximos y mínimos locales y las distancias en barras.
Aquí está el código relevante para lo anterior:
//--- si tenemos una ola ascendente
if(wave_type==1){
//--- si la ola se expande hacia arriba
if(high[i]>wave_end_price){
upWaves[i-wave_end_distance]=0.0; // eliminamos el precio final anterior de su posición en el array
upWaves[i]=high[i];
wave_end_price=high[i];
wave_end_distance=0;
high_mem=high[i];
distance_from_high=0;
low_mem=low[i];
distance_from_low=0;
}
//--- verificamos el retroceso
if(low[i]0.0){
double retraced=(size_of_retracement/size_of_wave)*100.0;
double new_wave_size_in_atr_units=((wave_end_price-low_mem)/_Point)/rollingAtr;
//--- si el nuevo tamaño de ola es válido
if(new_wave_size_in_atr_units>=minSizeInAtrUnits){
//--- si el retroceso es significativo, iniciamos una ola descendente
if(retraced>=retracement){
wave_type=-1;
wave_start_price=high[i-distance_from_high];
wave_start_distance=distance_from_high;
wave_end_price=low[i];
wave_end_distance=0;
upWaves[i-wave_start_distance]=high_mem;
dwWaves[i]=low[i];
high_mem=high[i];
distance_from_high=0;
low_mem=low[i];
distance_from_low=0;
}
}
}
}
}
Hacemos lo opuesto cuando tenemos una ola descendente.
Y hemos terminado, nuestro zigzag de retroceso está listo.
Aquí está el zigzag con 23.6% de retroceso y 0.0 de tamaño mínimo de olas en unidades de ATR.

Y aquí está el mismo zigzag con 3 de tamaño mínimo de olas en unidades de ATR.

Publicaciones relacionadas
- ID Lite Info MA: Tu Nuevo Aliado en MetaTrader 5
- Alertas de Señales con el Indicador Iin_MA para MetaTrader 5
- iStochKomposterAlert: El Indicador de Señales para MetaTrader 5 con Alertas
- PPO_SignAlert: Tu nuevo aliado de señales en MetaTrader 5
- Gráfico de Equity: Mejora del Indicador para MetaTrader 4