Watch how to download trading robots for free
Find us on Twitter!
Join our fan page
Interesting script?
So post a link to it -
let others appraise it
You liked the script? Try it in the MetaTrader 5 terminal
Indicators

Fibonacci ZigZag - indicator for MetaTrader 5

Views:
5200
Rating:
(3)
Published:
2025.03.02 23:57
fiboZigZag.mq5 (13.54 KB) view
MQL5 Freelance Need a robot or indicator based on this code? Order it on Freelance Go to Freelance

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


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






Autoscaling Zigzag Autoscaling Zigzag

A zigzag indicator that uses a single input to adjust the step size for detecting wave direction changes

Telegram integration made easy. Telegram integration made easy.

The goal is to make the function readily available for any Telegram integration task in MQL5 development. By adding this file to your CodeBase, you can simply include it in your Expert Advisors and call the function directly from the included module. This eliminates the need to redevelop the code from scratch repeatedly, ensuring reusability across multiple projects.

BreakRevertPro EA Adaptive Trading Edge for Breakout Mean Reversion BreakRevertPro EA Adaptive Trading Edge for Breakout Mean Reversion

BreakRevertPro EA merges breakout and mean reversion strategies with adaptive SL/TP and multi-timeframe ATR trailing stops for flexible trading in volatile markets.

Daily Vertical Lines Daily Vertical Lines

Draw daily vertical lines plus the day of week labels on the chart.