//+------------------------------------------------------------------+
//|                                                    ma ZigZag.mq4 |
//|                 Copyright © 2005-2007, MetaQuotes Software Corp. |
//|                                       http://www.metaquotes.net/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2007, MetaQuotes Software Corp."
#property link      "http://www.metaquotes.net/"
//Modified MetaQuotes ZigZag by cja and 
//ZZLegRange indicator by Stephen Ambatoding - sangmane@forexfactory.com
//combined into a single MA ZigZag.

#property indicator_chart_window
#property indicator_buffers 2
#property indicator_color1 Red
#property indicator_color2 Gold
#property indicator_width1 2
#property indicator_width2 1

extern int MA.Period       = 23;
extern int MA.Shift        = 0;
extern int MA.Method       = 2;
extern int MA.Price        = 0;
 
extern int ExtDepth=12;
extern double ExtDeviation = 1;
extern int ExtBackstep     = 3;

extern color LabelColor    = White;
extern int   LabelSize     = 10;
extern string LabelFont    = "Arial Black";
//---- indicator buffers
double ZigzagBuffer[];
double ma[];
double HighMapBuffer[];
double LowMapBuffer[];
int level=3; // recounting's depth 
bool downloadhistory=false;
double Pip;
extern int History = 1000;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
   IndicatorBuffers(4);
//---- drawing settings
   SetIndexStyle(1,DRAW_SECTION);
//---- indicator buffers mapping
   SetIndexBuffer(0,ma);
   SetIndexShift(0,MA.Shift);
   SetIndexBuffer(1,ZigzagBuffer);
   SetIndexShift(1,MA.Shift);
   SetIndexBuffer(2,HighMapBuffer);
   SetIndexShift(2,MA.Shift);
   SetIndexBuffer(3,LowMapBuffer);
   SetIndexShift(3,MA.Shift);
   SetIndexEmptyValue(1,0.0);

//---- indicator short name
   IndicatorShortName("ma ZigZag ("+ExtDepth+","+DoubleToStr(ExtDeviation,1)+","+ExtBackstep+")");
   
    if(Digits==3 || Digits==5) Pip = 10*Point;
    else Pip = Point;
    IndicatorDigits(Digits+1);  
//---- initialization done
   return(0);
  }
  
  int deinit()
  {
   string ObjName;
   for(int i=ObjectsTotal()-1; i>=0; i--)
   {
     ObjName = ObjectName(i);
     if(StringFind(ObjName,"ZZLabel",0)>=0)
       ObjectDelete(ObjName);
   }
   return(0);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int start()
  {
   int i, counted_bars = IndicatorCounted();
   int limit,counterZ,whatlookfor;
   int shift,back,lasthighpos,lastlowpos;
   double val,res;
   double curlow,curhigh,lasthigh,lastlow;

   if (counted_bars==0 && downloadhistory) // history was downloaded
     {
      ArrayInitialize(ZigzagBuffer,0.0);
      ArrayInitialize(HighMapBuffer,0.0);
      ArrayInitialize(LowMapBuffer,0.0);
     }
   if (counted_bars==0) 
     {
      limit=Bars-ExtDepth;
      downloadhistory=true;
     }
   if (counted_bars>0) 
     {
      while (counterZ<level && i<100)
        {
         res=ZigzagBuffer[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>=0;i--)  
        {
         ZigzagBuffer[i]=0.0;  
         LowMapBuffer[i]=0.0;
         HighMapBuffer[i]=0.0;
        }
     }
   
   for(shift=limit; shift>=0; shift--)
     {
      ma[shift] = iMA(Symbol(),0,MA.Period,MA.Shift,MA.Method,MA.Price,shift);
      val=ma[ArrayMinimum(ma,ExtDepth,shift)];
      if(val==lastlow) val=0.0;
      else 
        { 
         lastlow=val; 
         if((ma[shift]-val)>(ExtDeviation*Point)) val=0.0;
         else
           {
            for(back=1; back<=ExtBackstep; back++)
              {
               res=LowMapBuffer[shift+back];
               if((res!=0)&&(res>val)) LowMapBuffer[shift+back]=0.0; 
              }
           }
        } 
      if (ma[shift]==val) LowMapBuffer[shift]=val; else LowMapBuffer[shift]=0.0;
      //--- high
      val=ma[ArrayMaximum(ma,ExtDepth,shift)];
      if(val==lasthigh) val=0.0;
      else 
        {
         lasthigh=val;
         if((val-ma[shift])>(ExtDeviation*Point)) val=0.0;
         
         else
           {
            for(back=1; back<=ExtBackstep; back++)
              {
               res=HighMapBuffer[shift+back];
               if((res!=0)&&(res<val)) HighMapBuffer[shift+back]=0.0; 
              } 
           }
        }
      if (ma[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>=0;shift--)
     {
      res=0.0;
      switch(whatlookfor)
        {
         case 0: // look for peak or lawn 
            if (lastlow==0 && lasthigh==0)
              {
               if (HighMapBuffer[shift]!=0)
                 {
                  lasthigh=ma[shift];
                  lasthighpos=shift;
                  whatlookfor=-1;
                  ZigzagBuffer[shift]=lasthigh;
                  res=1;
                 }
               if (LowMapBuffer[shift]!=0)
                 {
                  lastlow=ma[shift];
                  lastlowpos=shift;
                  whatlookfor=1;
                  ZigzagBuffer[shift]=lastlow;
                  res=1;
                 }
              }
             break;  
         case 1: // look for peak
            if (LowMapBuffer[shift]!=0.0 && LowMapBuffer[shift]<lastlow && HighMapBuffer[shift]==0.0)
              {
               ZigzagBuffer[lastlowpos]=0.0;
               lastlowpos=shift;
               lastlow=LowMapBuffer[shift];
               ZigzagBuffer[shift]=lastlow;
               res=1;
              }
            if (HighMapBuffer[shift]!=0.0 && LowMapBuffer[shift]==0.0)
              {
               lasthigh=HighMapBuffer[shift];
               lasthighpos=shift;
               ZigzagBuffer[shift]=lasthigh;
               whatlookfor=-1;
               res=1;
              }   
            break;               
         case -1: // look for lawn
            if (HighMapBuffer[shift]!=0.0 && HighMapBuffer[shift]>lasthigh && LowMapBuffer[shift]==0.0)
              {
               ZigzagBuffer[lasthighpos]=0.0;
               lasthighpos=shift;
               lasthigh=HighMapBuffer[shift];
               ZigzagBuffer[shift]=lasthigh;
              }
            if (LowMapBuffer[shift]!=0.0 && HighMapBuffer[shift]==0.0)
              {
               lastlow=LowMapBuffer[shift];
               lastlowpos=shift;
               ZigzagBuffer[shift]=lastlow;
               whatlookfor=1;
              }   
            break;               
         default: return; 
        }
     }
     
  int k;
  int limit2 = MathMin(History,Bars-counted_bars-1);
   double zz;
   color ObjColor;

   for(i=limit2; i>=0; i--)
   {
     k = i;
     double d1=0,d2=0,d3=0;
     datetime t1=0,t2=0,t3=0;
     
     while(k<Bars-2)
    
     {
       zz = ZigzagBuffer[k];
       if(zz!=0)
       {         
         d1 = d2; d2 = d3; d3 = zz;
         t1 = t2; t2 = t3; t3 = Time[k];
       }
       if(d1>0) break;
       k++;  
     }
     if(d1==0) continue;
     double LabelPos;
     int ib = iBarShift(NULL,0,t2);
     if(d2>d3) LabelPos = NormalizeDouble(High[ib]+0.8*iATR(NULL,0,10,ib)/MA.Period*Pip,Digits);
     else LabelPos = NormalizeDouble(Low[ib]-0.2*iATR(NULL,0,10,ib)/MA.Period*Pip,Digits);
     string ObjName = "ZZLabel"+t1;
     if(ObjectFind(ObjName)<0)
     {
       ObjectCreate(ObjName,OBJ_TEXT,0,t2,LabelPos);
       ObjectSetText(ObjName,DoubleToStr(MathAbs(d3-d2)/Pip,2),LabelSize,LabelFont,LabelColor);
       ObjectSet(ObjName,OBJPROP_BACK,false);
     }
   }

   return(0);
  }
//+------------------------------------------------------------------+