Join our fan page
- Views:
- 5200
- Rating:
- Published:
- 2025.03.02 23:57
-
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
//--- 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 :
- 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
- 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

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

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 merges breakout and mean reversion strategies with adaptive SL/TP and multi-timeframe ATR trailing stops for flexible trading in volatile markets.

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