Indicators: RatioZigZag

 

RatioZigZag:

A modification of the ZigZag indicator, where the reversal moment is determined by a specified coefficient.

RatioZigZag

Author: Evgeniy Chumakov

 
Is there similare MT5 version?
 
Alberto Tortella #:
Is there similare MT5 version?


No. There is no version for MT5.

 
Alberto Tortella #:
Is there similare MT5 version?
version for mt5:

#property copyright "Evgeniy Chumakov | © Copyright 2026"
#property description "A modification of the ZigZag indicator, where the reversal moment is determined not by a fixed percentage, but by reaching a specified ratio of the current price to the last local extremum."
#property version "1.0"
#property link "https://www.mql5.com/ru/users/jack857752"

#property indicator_chart_window
#property indicator_buffers 7
#property indicator_plots 2

#property indicator_label1  "High Extremum"
#property indicator_type1   DRAW_ZIGZAG
#property indicator_color1  clrYellow
#property indicator_width1  2
#property indicator_label2  "Low Extremum"
#property indicator_type2   DRAW_ZIGZAG
#property indicator_color2  clrYellow
#property indicator_width2  2

input double StepRatio = 1.005; // Step Ratio
input int LineWidth = 2; // Line Width
input color LineColor = clrYellow; // Color

double ArrayHighZZ[]; // High Extremum ZZ
double ArrayLowZZ[];  // Low Extremum ZZ
double ArrayTypeZZ[]; // ZigZag direction buffer
double ArrayHighBarZZ[]; // ZigZag maximum bar location
double ArrayLowBarZZ[];  // ZigZag minimum bar location
double ArrayHighLast[]; // Last maximum value
double ArrayLowLast[]; // Last minimum value

//+------------------------------------------------------------------+
int OnInit()
{
   ArraySetAsSeries(ArrayHighZZ, true);
   ArraySetAsSeries(ArrayLowZZ, true);
   ArraySetAsSeries(ArrayTypeZZ, true);
   ArraySetAsSeries(ArrayHighBarZZ, true);
   ArraySetAsSeries(ArrayLowBarZZ, true);
   ArraySetAsSeries(ArrayHighLast, true);
   ArraySetAsSeries(ArrayLowLast, true);

   // Set buffers for drawing
   SetIndexBuffer(0, ArrayHighZZ, INDICATOR_DATA);
   SetIndexBuffer(1, ArrayLowZZ, INDICATOR_DATA);
   
   // Set buffers for calculations
   SetIndexBuffer(2, ArrayTypeZZ, INDICATOR_CALCULATIONS);
   SetIndexBuffer(3, ArrayHighBarZZ, INDICATOR_CALCULATIONS);
   SetIndexBuffer(4, ArrayLowBarZZ, INDICATOR_CALCULATIONS);
   SetIndexBuffer(5, ArrayHighLast, INDICATOR_CALCULATIONS);
   SetIndexBuffer(6, ArrayLowLast, INDICATOR_CALCULATIONS);

   // Initialize plot properties
   PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_ZIGZAG);
   PlotIndexSetInteger(0, PLOT_LINE_STYLE, STYLE_SOLID);
   PlotIndexSetInteger(0, PLOT_LINE_WIDTH, LineWidth);
   PlotIndexSetInteger(0, PLOT_LINE_COLOR, LineColor);
   PlotIndexSetInteger(0, PLOT_SHOW_DATA, true);
   
   PlotIndexSetInteger(1, PLOT_DRAW_TYPE, DRAW_ZIGZAG);
   PlotIndexSetInteger(1, PLOT_LINE_STYLE, STYLE_SOLID);
   PlotIndexSetInteger(1, PLOT_LINE_WIDTH, LineWidth);
   PlotIndexSetInteger(1, PLOT_LINE_COLOR, LineColor);
   PlotIndexSetInteger(1, PLOT_SHOW_DATA, true);

   IndicatorSetInteger(INDICATOR_DIGITS, _Digits);
   IndicatorSetString(INDICATOR_SHORTNAME, "RatioZigZag");

   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
   // Checking for the minimum number of bars to calculate
   if(rates_total < 3) return(0);

   // Set arrays as timeseries
   ArraySetAsSeries(high, true);
   ArraySetAsSeries(low, true);

   int start;
   if(prev_calculated == 0)
   {
      // Full recalculation
      ArrayInitialize(ArrayHighZZ, EMPTY_VALUE);
      ArrayInitialize(ArrayLowZZ, EMPTY_VALUE);
      ArrayInitialize(ArrayTypeZZ, EMPTY_VALUE);
      ArrayInitialize(ArrayHighBarZZ, 0);
      ArrayInitialize(ArrayLowBarZZ, 0);
      ArrayInitialize(ArrayHighLast, 0.0);
      ArrayInitialize(ArrayLowLast, 0.0);
      
      start = rates_total - 3;
      
      // Calculate starting extremes
      int init_index = CalcStartingExtremes(rates_total - 1, high, low);
      if(init_index > 0)
         start = init_index - 1;
   }
   else
   {
      // Calculate only new bars
      start = prev_calculated - 1;
      if(start < 0) start = 0;
   }

   // Calculating the indicator
   for(int i = start; i >= 0; i--)
   {
      if(i + 1 >= rates_total) continue;
      
      if(ArrayTypeZZ[i + 1] != EMPTY_VALUE)
      {
         if(ArrayTypeZZ[i + 1] > 0)
            Calculate_High_Extremum(i, high, low);
         else if(ArrayTypeZZ[i + 1] < 0)
            Calculate_Low_Extremum(i, high, low);
      }
   }

   return(rates_total);
}
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Calculation High Extremum                                        |
//+------------------------------------------------------------------+
void Calculate_High_Extremum(const int index, const double &high[], const double &low[])
{
   double PriceHigh = high[index]; // Current maximum price value
   double PriceLow = low[index]; // Current minimum price value

   bool EventHigh = false; // High point ZZ update event
   bool EventLow = false; // Low point ZZ update event

   double MinZZParametr = MathLog(PriceLow) - MathLog(ArrayHighLast[index + 1]);

   // Updating and redrawing the maximum extremum
   if(PriceHigh > ArrayHighLast[index + 1])
   {
      EventHigh = true;

      ArrayTypeZZ[index] = 1;

      // Clear previous high point
      if(ArrayHighBarZZ[index + 1] < ArraySize(ArrayHighZZ))
         ArrayHighZZ[(int)ArrayHighBarZZ[index + 1]] = EMPTY_VALUE;
      
      // Set new high point
      ArrayHighZZ[index] = PriceHigh;

      ArrayHighBarZZ[index] = index;
      ArrayLowBarZZ[index] = ArrayLowBarZZ[index + 1];

      ArrayHighLast[index] = PriceHigh;
      ArrayLowLast[index] = ArrayLowLast[index + 1];
   }

   // Creating and drawing the minimum extremum
   if(MinZZParametr <= -MathLog(StepRatio) && !EventHigh)
   {
      EventLow = true;

      ArrayTypeZZ[index] = -1;

      // Set low point
      ArrayLowZZ[index] = PriceLow;

      ArrayLowLast[index] = PriceLow;
      ArrayHighLast[index] = ArrayHighLast[index + 1];

      ArrayHighBarZZ[index] = ArrayHighBarZZ[index + 1];
      ArrayLowBarZZ[index] = index;
   }

   // No events for forming extremes. Copying past data.
   if(!EventHigh && !EventLow)
   {
      ArrayTypeZZ[index] = ArrayTypeZZ[index + 1];

      ArrayHighBarZZ[index] = ArrayHighBarZZ[index + 1];
      ArrayLowBarZZ[index] = ArrayLowBarZZ[index + 1];

      ArrayHighLast[index] = ArrayHighLast[index + 1];
      ArrayLowLast[index] = ArrayLowLast[index + 1];
   }
}
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Calculation Low Extremum                                         |
//+------------------------------------------------------------------+
void Calculate_Low_Extremum(const int index, const double &high[], const double &low[])
{
   double PriceHigh = high[index]; // Current maximum price value
   double PriceLow = low[index]; // Current minimum price value
  
   bool EventLow = false; // Low point ZZ update event
   bool EventHigh = false; // High point ZZ update event

   double MaxZZParametr = MathLog(PriceHigh) - MathLog(ArrayLowLast[index + 1]);

   // Updating and redrawing the minimum extremum
   if(PriceLow < ArrayLowLast[index + 1])
   {
      EventLow = true;

      ArrayTypeZZ[index] = -1;

      // Clear previous low point
      if(ArrayLowBarZZ[index + 1] < ArraySize(ArrayLowZZ))
         ArrayLowZZ[(int)ArrayLowBarZZ[index + 1]] = EMPTY_VALUE;
      
      // Set new low point
      ArrayLowZZ[index] = PriceLow;

      ArrayLowBarZZ[index] = index;
      ArrayHighBarZZ[index] = ArrayHighBarZZ[index + 1];

      ArrayHighLast[index] = ArrayHighLast[index + 1];
      ArrayLowLast[index] = PriceLow;
   }

   // Creating and drawing the maximum extremum
   if(MaxZZParametr >= MathLog(StepRatio) && !EventLow)
   {
      EventHigh = true;

      ArrayTypeZZ[index] = 1;

      // Set high point
      ArrayHighZZ[index] = PriceHigh;

      ArrayHighLast[index] = PriceHigh;
      ArrayLowLast[index] = ArrayLowLast[index + 1];

      ArrayHighBarZZ[index] = index;
      ArrayLowBarZZ[index] = ArrayLowBarZZ[index + 1];
   }

   // No events for forming extremes. Copying past data.
   if(!EventHigh && !EventLow)
   {
      ArrayTypeZZ[index] = ArrayTypeZZ[index + 1];

      ArrayHighBarZZ[index] = ArrayHighBarZZ[index + 1];
      ArrayLowBarZZ[index] = ArrayLowBarZZ[index + 1];

      ArrayHighLast[index] = ArrayHighLast[index + 1];
      ArrayLowLast[index] = ArrayLowLast[index + 1];
   }
}
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Calculation Of Starting Extremes                                 |
//+------------------------------------------------------------------+
int CalcStartingExtremes(const int index, const double &high[], const double &low[])
{
   int init_index = 0;

   for(int period = 2; period < index; period++)
   {
      int period_start = index - period; // Measurement start position

      int MaxBar = -1;
      double max_val = -DBL_MAX;
      for(int j = period_start; j < period_start + period; j++)
      {
         if(high[j] > max_val)
         {
            max_val = high[j];
            MaxBar = j;
         }
      }
      
      int MinBar = -1;
      double min_val = DBL_MAX;
      for(int j = period_start; j < period_start + period; j++)
      {
         if(low[j] < min_val)
         {
            min_val = low[j];
            MinBar = j;
         }
      }

      double Max_Price = high[MaxBar]; // The value of the maximum price on the measured interval.
      double Min_Price = low[MinBar]; // The value of the minimum price on the measured interval.

      double MaxZZParametr = MathLog(Max_Price) - MathLog(Min_Price);
      double MinZZParametr = MathLog(Min_Price) - MathLog(Max_Price);

      // Formation of the maximum extremum
      if(MaxBar != MinBar && MaxBar < MinBar && MaxZZParametr >= MathLog(StepRatio))
      {
         ArrayTypeZZ[period_start] = 1;

         ArrayHighZZ[MaxBar] = Max_Price;
         ArrayLowZZ[MinBar] = Min_Price;

         ArrayHighBarZZ[period_start] = MaxBar;
         ArrayLowBarZZ[period_start] = MinBar;

         ArrayHighLast[period_start] = Max_Price;
         ArrayLowLast[period_start] = Min_Price;

         init_index = period_start;
         
         break;
      }

      // Formation of a minimum extremum
      if(MaxBar != MinBar && MinBar < MaxBar && MinZZParametr <= -MathLog(StepRatio))
      {
         ArrayTypeZZ[period_start] = -1;

         ArrayHighZZ[MaxBar] = Max_Price;
         ArrayLowZZ[MinBar] = Min_Price;

         ArrayHighBarZZ[period_start] = MaxBar;
         ArrayLowBarZZ[period_start] = MinBar;

         ArrayHighLast[period_start] = Max_Price;
         ArrayLowLast[period_start] = Min_Price;

         init_index = period_start;
         
         break;
      }
   }

   return(init_index);
}
//+------------------------------------------------------------------+
 

Thank you very much!

I just tried the indicator but when I loaded it on a graph the plaform crashed...

 
Alberto Tortella #:

Thank you very much!

I just tried the indicator but when I loaded it on a graph the plaform crashed...

It works without any problems for me...
 
What does this indicator do different to normal ZigZag? I can spot the difference in plotting, I just don't see any use-case and why should it be used over common zigzag? Is it a baseline for some specific strategy?
 
Shadoba #:
What does this indicator do different to normal ZigZag? I can spot the difference in plotting, I just don't see any use-case and why should it be used over common zigzag? Is it a baseline for some specific strategy?
It differs from a regular zigzag in that it uses a different calculation. The indicator is similar to other indicators in terms of how to use it.
 
Thank you very much!