Home Technical Indicator Post

Mastering the Fibonacci ZigZag Indicator for MetaTrader 5

Attachments
56619.zip (2.54 KB, Download 0 times)

Getting Started with the Fibonacci ZigZag Indicator

To set up the Fibonacci ZigZag indicator in MetaTrader 5, you'll need the following components:

  • 1 zigzag plot
  • 2 data buffers for tracking highs and lows
  • Input parameters for customization
  • A set of system variables that reset during recalculations

Here’s a snippet of the code you’ll be working with:

#property indicator_buffers 2
#property indicator_plots 1
input double retracement=23.6;// Retracement amount
input double minSizeInAtrUnits=0.0;// Minimum 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
//+------------------------------------------------------------------+

In this setup, the upWaves array will hold the highs, while the dwWaves array captures the lows.

Next, let's define our system variables. We need to track the last wave type, where it began and ended, and the bar distances from each point:

//--- Managing the zigzag
  //--- Wave types: [0] None, [1] Up, [2] Down
    int wave_type=0;
  //--- Starting price of the wave
    double wave_start_price=0.0;
  //--- Ending price of the wave
    double wave_end_price=0.0;
  //--- Distance in bars from starting price
    int wave_start_distance=0;
  //--- Distance in bars from ending 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;

This sets up the rolling ATR unit and keeps track of how many have been calculated.

Next, we’ll create a system reset function to clear out old data:

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

Here we simply fill the arrays with zeroes and reset the system variables.

During initialization, we set up the buffers, the plot, and 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();

Now, let’s dive into the calculations. First on our list is managing the rolling ATR.

We won’t proceed until we have more bars than the ATR period:

  • If we haven't collected enough bars, we keep adding the range of the found bars to a summation.
  • Once we have enough bars, we perform our first division (averaging).
  • After that, we clip one portion of the rolling ATR and add a new portion based on the current bar's range.

We do this first to minimize accessing multiple conditions.

     //--- Manage the ATR
       rollingAtrs++;
       if(rollingAtrs>rollingAtrPeriod){
       double new_portion=((high[i]-low[i])/_Point)/((double)rollingAtrPeriod);
       //--- Remove an old portion and add a new one
       rollingAtr=(rollingAtr)-(rollingAtr/((double)rollingAtrPeriod))+new_portion;
       }
       else if(rollingAtrs<=rollingAtrPeriod){
         rollingAtr+=(high[i]-low[i])/_Point;
         if(rollingAtrs==rollingAtrPeriod){
           rollingAtr/=((double)rollingAtrs);
           //--- Initialize memory for highs and lows
             high_mem=high[i];
             low_mem=low[i];
             distance_from_high=0;
             distance_from_low=0;
         }
       }

Now, there's an important point to consider. For a retracement to take place, we need at least one wave. But how do we define that first wave? Here’s how:

  • Once the ATR fills up (i.e., we’ve collected the period), we’ll capture the high and low in our system variables.
  • Whichever side forms a wave with a valid size in ATR units, forming a new high (upwave) or a new low (downwave), is the winner!

This way, we avoid having a retracement as the initial wave, but it’s still a necessary step to kick things off.

Here’s how we handle things when there’s no wave yet:

   //--- If there's no wave type yet
     else{
       //--- If we break the high but 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;
         //--- Check if the new wave size is valid
         if(new_wave_size_in_atr_units>=minSizeInAtrUnits){
             //--- Start a new up wave
               wave_type=1;
               wave_start_price=low_mem;
               wave_start_distance=distance_from_low;
               wave_end_price=high[i];
               wave_end_distance=0;
               //--- Draw the wave
               dwWaves[i-wave_start_distance]=low_mem;
               upWaves[i]=high[i];
               //--- Update the high
               high_mem=high[i];
               distance_from_high=0;
               //--- Update the low
               low_mem=low[i];
               distance_from_low=0;
           }
       }
       //--- If we break the low but 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;
             wave_start_price=high_mem;
             wave_start_distance=distance_from_high;
             wave_end_price=low[i];
             wave_end_distance=0;
             //--- Draw the wave
             upWaves[i-wave_start_distance]=high_mem;
             dwWaves[i]=low[i];
             //--- Update the high
             high_mem=high[i];
             distance_from_high=0;
             //--- Update the low
             low_mem=low[i];
             distance_from_low=0;
       }
       }
       //--- If we break both high and low
         else if(low[i]<low_mem&&high[i]>high_mem){
         //--- Update both values
         high_mem=high[i];
         low_mem=low[i];
         distance_from_high=0;
         distance_from_low=0;
       }
     }

Now, let’s wrap things up. If we have an upwave:

  1. If a new high is made, move the zigzag from the previous high position to the new one. This allows us to retain bar distances and capture the lowest low since the peak for potential retracement.
  2. If a new low is made, we calculate the distance from the peak to the low, divide it by the wave size, and scale it to match the input parameter. If the new wave size meets the ATR criteria, we start a new downwave, updating local highs and lows as well as distances.

Here’s the relevant code:

       //--- If we have an up wave
         if(wave_type==1){
           //--- If the wave expands upwards
             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;
               //--- Update the high
               high_mem=high[i];
               distance_from_high=0;
               //--- Update 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
                  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;
                 //--- Draw the wave
                upWaves[i-wave_start_distance]=high_mem;
                dwWaves[i]=low[i];
                 //--- Update the high
                high_mem=high[i];
                distance_from_high=0;
                 //--- Update the low
                low_mem=low[i];
                distance_from_low=0;
         }
         }
       }
       }
       }
       }

We’ll do the opposite for a down wave.

And just like that, our retracement zigzag is set up and ready to roll!

Take a look at the zigzag with 23.6% retracement and 0.0 min size of waves in ATR units:


And here's the same zigzag with 3 min size of waves in ATR units:


Happy trading!

Related Posts

Comments (0)