Expert Advisors • Indicators • Scripts • Libraries

MQL.RobotFX.org is the biggest collection of MetaTrader expert advisors (MT5 & MT4), indicators, scripts and libraries that can be used to improve trading results, minimize risks or simply automate trading tasks

MetaTrader 5 Indicator | Fibonacci ZigZag

The setup 

We will need :

  • 1 zigzag plot
  • 2 data buffers for the highs and the lows
  • input parameters
  • an ongoing set of system variables which reset whenever the indicator recalculates
#property indicator_buffers 2 #property indicator_plots 1 input double retracement=23.6;//retracement amount input double minSizeInAtrUnits=0.0;//min size of waves in atr units input int rollingAtrPeriod=14;//rolling atr period input color Color=clrDodgerBlue;//wave color input int Width=3;//wave width input ENUM_LINE_STYLE Style=STYLE_SOLID;//wave style //+------------------------------------------------------------------+     //| Custom indicator initialization function                         | //+------------------------------------------------------------------+ //--- up waves and the downwaves   double upWaves[],dwWaves[];

The upWaves array will store the highs and the dwWaves array will store the lows

System variables :

we need to know the last wave type , where it started , where it ended , the distance in bars from the start and the end.

Then we need a local high and local low variable as well as distances in bars from each point.

//--- keeping track of the zigzag   //--- the type of wave we have [0] none [1] up [2] down     int wave_type=0;   //--- the price from of the wave (starting price)      double wave_start_price=0.0;   //--- the price to of the wave (ending price)     double wave_end_price=0.0;   //--- the distance in bars from the start price     int wave_start_distance=0;   //--- the distance in bars from the end price     int wave_end_distance=0;   //--- high price tracking     double high_mem=0.0;     int distance_from_high=0;   //--- low price tracking     double low_mem=0.0;     int distance_from_low=0;   //--- rolling atr     double rollingAtr=0.0;        int rollingAtrs=0;

Finally the rolling atr unit and how many have been calculated 

We then create a system reset function :

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; }

Standard stuff , fill the arrays with zeroes and reset the system variables.

Oninit we setup the buffers , the plot , and we call reset for the first time :

  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();

So let's jump right in the calculation.

The first thing we need to take care of is the rolling atr.

Until we have collected more bars that the atr period we will not do anything else.

The portion that manages the rolling atr is as follows :

  • if we have not collected more than the period keep adding the range of the bars found to a summation
  • once we hit the period we perform the first division (average)
  • after that we clip one portion of the rolling atr off , which is atr/period , and then add a new portion which is range of bar / period
we place the last part first  because it will happen more often and we wont need to be accessing 2 if statements
     //--- manage the atr        rollingAtrs++;        if(rollingAtrs>rollingAtrPeriod){        double new_portion=((high[i]-low[i])/_Point)/((double)rollingAtrPeriod);        //--- we remove an old portion and add a new portion        rollingAtr=(rollingAtr)-(rollingAtr/((double)rollingAtrPeriod))+new_portion;        }        else if(rollingAtrs<=rollingAtrPeriod){          rollingAtr+=(high[i]-low[i])/_Point;          if(rollingAtrs==rollingAtrPeriod){            rollingAtr/=((double)rollingAtrs);            //--- start the memory for highs and lows and the system              high_mem=high[i];              low_mem=low[i];              distance_from_high=0;              distance_from_low=0;            }          }

Awesome , now , there is another issue.

The foundation of this zig zag is a retracement . 

But for a retracement to occur there must be at least one wave.

But what will the first wave retrace ? xD

For that reason we will do the following :

  • as soon as the atr fills up (atr collected = period) , we will grab the high and the low in our system variables
  • whichever side manages to form a wave that has a valid size in atr units , and forms a new high (upwave) or a new low (down wave) wins

this way we dont have a retracement as an initial wave , but , we gotta start the sequence somehow.

Note we could have also opted in to have a classic fractal approach here for the first wave only and then continue onwards with retracements.

This is what we do as long as we don't have a wave :

   //--- if we don't have a wave type yet      else{        //--- if we broke the high and not the low          if(high[i]>high_mem&&low[i]>=low_mem){          double new_wave_size_in_atr_units=((high[i]-low_mem)/_Point)/rollingAtr;          //--- if the new wave size is valid          if(new_wave_size_in_atr_units>=minSizeInAtrUnits){            //--- start a new up wave               wave_type=1;            //--- start price is the low mem               wave_start_price=low_mem;              wave_start_distance=distance_from_low;            //--- end price is the new high              wave_end_price=high[i];              wave_end_distance=0;            //--- draw the wave               dwWaves[i-wave_start_distance]=low_mem;              upWaves[i]=high[i];            //--- change the high              high_mem=high[i];              distance_from_high=0;            //--- change the low               low_mem=low[i];              distance_from_low=0;            }            }         //--- if we broke the low and not the high          else if(low[i]<low_mem&&high[i]<=high_mem){          double new_wave_size_in_atr_units=((high_mem-low[i])/_Point)/rollingAtr;          //--- if the new wave size is valid          if(new_wave_size_in_atr_units>=minSizeInAtrUnits){                     //--- start a new down wave               wave_type=-1;            //--- start price is the high mem               wave_start_price=high_mem;              wave_start_distance=distance_from_high;            //--- end price is the new low              wave_end_price=low[i];              wave_end_distance=0;            //--- draw the wave               upWaves[i-wave_start_distance]=high_mem;              dwWaves[i]=low[i];            //--- change the high              high_mem=high[i];              distance_from_high=0;            //--- change the low               low_mem=low[i];              distance_from_low=0;            }            }        //--- if we broke both          else if(low[i]<low_mem&&high[i]>high_mem){            //--- change them              high_mem=high[i];              low_mem=low[i];              distance_from_high=0;              distance_from_low=0;            }        }

Great . Now the final piece.

  • If we have an upwave :
  1. if a new high is made , move the zigzag from the previous high position to the new high position which we can do since we retain bar distances.Also update the low and the distance from the low.We do that so we can catch the lowest low since the peak and check if it retraces enough in order to start a new low
  2. if a new low is made , or , a new low is set , we calculate the distance from the peak to the low and divide it by the wave size . And also multiply it with 100 to match the input parameter scale.So if the wave size is 100 points and the retracement is 24 points we get 24/100 0.24 , then x 100 24% . If the size of the new "would be" wave that retraces the previous one is also valid against the atr units we start a new down wave, set the new local highs and lows , set the bar distances. 

here is the relevant code for the above :

       //--- if we have an up wave           if(wave_type==1){            //--- if the wave expands up               if(high[i]>wave_end_price){                //--- remove the previous end price from its array position (0.0=empty)                 upWaves[i-wave_end_distance]=0.0;                //--- place it on the new position                 upWaves[i]=high[i];                 wave_end_price=high[i];                 wave_end_distance=0;                //--- change the high                 high_mem=high[i];                 distance_from_high=0;                //--- change the low                  low_mem=low[i];                 distance_from_low=0;                }            //--- check for retracement              if(low[i]<low_mem||distance_from_low==0){                low_mem=low[i];                distance_from_low=0;                double size_of_wave=(wave_end_price-wave_start_price)/_Point;                double size_of_retracement=(wave_end_price-low_mem)/_Point;                if(size_of_wave>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;                //--- if the new wave size is valid                if(new_wave_size_in_atr_units>=minSizeInAtrUnits){                  //--- if the retracement is significant , start a down wave                    if(retraced>=retracement){                     //--- start a new down wave                        wave_type=-1;                     //--- start price is the high mem                        wave_start_price=high[i-distance_from_high];                       wave_start_distance=distance_from_high;                     //--- end price is the new low                       wave_end_price=low[i];                       wave_end_distance=0;                     //--- draw the wave                        upWaves[i-wave_start_distance]=high_mem;                       dwWaves[i]=low[i];                     //--- change the high                       high_mem=high[i];                       distance_from_high=0;                     //--- change the low                        low_mem=low[i];                       distance_from_low=0;                                           }                    }                  }                }            }

We do the opposite when we have a down wave.

And we are done , our retracement zig zag is ready.

Here is the zigzag with 23.6% retracement and 0.0 min size of waves in atr units

MetaTrader Experts, Indicators, Scripts and Libraries

and here is the same zig zag with 3 min size of waves in atr units

MetaTrader Experts, Indicators, Scripts and Libraries

56619