//+------------------------------------------------------------------+
//|                                                  ZigzagColor.mq5 |
//|                   Copyright 2009-2017, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2009-2017, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
//--- indicator settings
#property indicator_chart_window
#property indicator_buffers 5
#property indicator_plots   1
#property indicator_type1   DRAW_COLOR_ZIGZAG
#property indicator_color1  DodgerBlue,Red
//--- input parameters
input int ExtDepth=12;
input int ExtDeviation=5;
input int ExtBackstep=3;
int level=3; // recounting's depth 
//--- indicator buffers
double ZigzagPeakBuffer[];
double ZigzagLawnBuffer[];
double HighMapBuffer[];
double LowMapBuffer[];
double ColorBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
void OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,ZigzagPeakBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,ZigzagLawnBuffer,INDICATOR_DATA);
   SetIndexBuffer(2,ColorBuffer,INDICATOR_COLOR_INDEX);
   SetIndexBuffer(3,HighMapBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(4,LowMapBuffer,INDICATOR_CALCULATIONS);
//--- set accuracy
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
//--- name for DataWindow and indicator subwindow label
   IndicatorSetString(INDICATOR_SHORTNAME,"ZigZag("+(string)ExtDepth+","+(string)ExtDeviation+","+(string)ExtBackstep+")");
   PlotIndexSetString(0,PLOT_LABEL,"ZigzagColor");
//--- set drawing line empty value
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
  }
//+------------------------------------------------------------------+
//| get highest value for range                                      |
//+------------------------------------------------------------------+
double Highest(const double&array[],int range,int fromIndex)
  {
   double res;
//---
   res=array[fromIndex];
   for(int i=fromIndex;i>fromIndex-range && i>=0;i--)
     {
      if(res<array[i]) res=array[i];
     }
//---
   return(res);
  }
//+------------------------------------------------------------------+
//| get lowest value for range                                       |
//+------------------------------------------------------------------+
double Lowest(const double&array[],int range,int fromIndex)
  {
   double res;
//---
   res=array[fromIndex];
   for(int i=fromIndex;i>fromIndex-range && i>=0;i--)
     {
      if(res>array[i]) res=array[i];
     }
//---
   return(res);
  }
//+------------------------------------------------------------------+
//| Detrended Price Oscillator                                       |
//+------------------------------------------------------------------+
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[])
  {
   int i,limit=0;
//--- check for rates count
   if(rates_total<100)
     {
      //--- clean up arrays
      ArrayInitialize(ZigzagPeakBuffer,0.0);
      ArrayInitialize(ZigzagLawnBuffer,0.0);
      ArrayInitialize(HighMapBuffer,0.0);
      ArrayInitialize(LowMapBuffer,0.0);
      ArrayInitialize(ColorBuffer,0.0);
      //--- exit with zero result
      return(0);
     }
//--- preliminary calculations
   int counterZ=0,whatlookfor=0;
   int shift,back=0,lasthighpos=0,lastlowpos=0;
   double val=0,res=0;
   double curlow=0,curhigh=0,lasthigh=0,lastlow=0;
//--- set empty values
   if(prev_calculated==0)
     {
      ArrayInitialize(ZigzagPeakBuffer,0.0);
      ArrayInitialize(ZigzagLawnBuffer,0.0);
      ArrayInitialize(HighMapBuffer,0.0);
      ArrayInitialize(LowMapBuffer,0.0);
      //--- start calculation from bar number ExtDepth
      limit=ExtDepth-1;
     }
//---
   if(prev_calculated>0)
     {
      i=rates_total-1;
      while(counterZ<level && i>rates_total -100)
        {
         res=(ZigzagPeakBuffer[i]+ZigzagLawnBuffer[i]);
         //---
         if(res!=0) counterZ++;
         i--;
        }
      i++;
      limit=i;
      //---
      if(LowMapBuffer[i]!=0)
        {
         curlow=LowMapBuffer[i];
         whatlookfor=1;
        }
      else
        {
         curhigh=HighMapBuffer[i];
         whatlookfor=-1;
        }
      //---
      for(i=limit+1;i<rates_total && !IsStopped();i++)
        {
         ZigzagPeakBuffer[i]=0.0;
         ZigzagLawnBuffer[i]=0.0;
         LowMapBuffer[i]=0.0;
         HighMapBuffer[i]=0.0;
        }
     }
//----
   for(shift=limit;shift<rates_total && !IsStopped();shift++)
     {

      val=Lowest(low,ExtDepth,shift);
      //---
      if(val==lastlow) val=0.0;
      else
        {
         lastlow=val;
         //---
         if((low[shift]-val)>(ExtDeviation*_Point)) val=0.0;
         else
           {
            //---
            for(back=ExtBackstep;back>=1;back--)
              {
               res=LowMapBuffer[shift-back];
               //---
               if((res!=0) && (res>val)) LowMapBuffer[shift-back]=0.0;
              }
           }
        }
      //---
      if(low[shift]==val) LowMapBuffer[shift]=val;
      else
         LowMapBuffer[shift]=0.0;
      //--- high
      val=Highest(high,ExtDepth,shift);
      //---
      if(val==lasthigh) val=0.0;
      else
        {
         lasthigh=val;
         //---
         if((val-high[shift])>(ExtDeviation*_Point)) val=0.0;
         else
           {
            //---
            for(back=ExtBackstep;back>=1;back--)
              {
               res=HighMapBuffer[shift-back];
               //---
               if((res!=0) && (res<val)) HighMapBuffer[shift-back]=0.0;
              }
           }
        }
      //---
      if(high[shift]==val) HighMapBuffer[shift]=val;
      else  HighMapBuffer[shift]=0.0;
     }
// final cutting 
   if(whatlookfor==0)
     {
      lastlow=0;
      lasthigh=0;
     }
   else
     {
      lastlow=curlow;
      lasthigh=curhigh;
     }
//----
   for(shift=limit;shift<rates_total && !IsStopped();shift++)
     {
      res=0.0;
      switch(whatlookfor)
        {
         // look for peak or lawn 
         case 0: if(lastlow==0 && lasthigh==0)
           {
            if(HighMapBuffer[shift]!=0)
              {
               lasthigh=high[shift];
               lasthighpos=shift;
               whatlookfor=-1;
               ZigzagPeakBuffer[shift]=lasthigh;
               ColorBuffer[shift]=0;
               res=1;
              }
            if(LowMapBuffer[shift]!=0)
              {
               lastlow=low[shift];
               lastlowpos=shift;
               whatlookfor=1;
               ZigzagLawnBuffer[shift]=lastlow;
               ColorBuffer[shift]=1;
               res=1;
              }
           }
         break;
         // look for peak
         case 1: if(LowMapBuffer[shift]!=0.0 && LowMapBuffer[shift]<lastlow && 
                    HighMapBuffer[shift]==0.0)
           {
            ZigzagLawnBuffer[lastlowpos]=0.0;
            lastlowpos=shift;
            lastlow=LowMapBuffer[shift];
            ZigzagLawnBuffer[shift]=lastlow;
            ColorBuffer[shift]=1;
            res=1;
           }
         if(HighMapBuffer[shift]!=0.0 && LowMapBuffer[shift]==0.0)
           {
            lasthigh=HighMapBuffer[shift];
            lasthighpos=shift;
            ZigzagPeakBuffer[shift]=lasthigh;
            ColorBuffer[shift]=0;
            whatlookfor=-1;
            res=1;
           }
         break;
         // look for lawn
         case -1:  if(HighMapBuffer[shift]!=0.0 && 
                      HighMapBuffer[shift]>lasthigh && 
                      LowMapBuffer[shift]==0.0)
           {
            ZigzagPeakBuffer[lasthighpos]=0.0;
            lasthighpos=shift;
            lasthigh=HighMapBuffer[shift];
            ZigzagPeakBuffer[shift]=lasthigh;
            ColorBuffer[shift]=0;
           }
         if(LowMapBuffer[shift]!=0.0 && HighMapBuffer[shift]==0.0)
           {
            lastlow=LowMapBuffer[shift];
            lastlowpos=shift;
            ZigzagLawnBuffer[shift]=lastlow;
            ColorBuffer[shift]=1;
            whatlookfor=1;
           }
         break;
         default: return(rates_total);
        }
     }

//--- OnCalculate done. Return new prev_calculated.
   return(rates_total);
  }
//+------------------------------------------------------------------+
