//+------------------------------------------------------------------+
//|                                             Zigzag with Fibo.mq4 |
//+------------------------------------------------------------------+
//|                 Copyright © 2005-2007, MetaQuotes Software Corp. |
//|                                       http://www.metaquotes.net/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2007, MetaQuotes Software Corp."
#property link      "http://www.metaquotes.net/"

#include <hanover --- function header (np).mqh>

#property indicator_chart_window
#property indicator_buffers 1
#property indicator_color1 White
#property indicator_width1 2
//---- indicator parameters
extern int       ExtDepth          = 12;
extern int       ExtDeviation      = 5;
extern int       ExtBackstep       = 3;
extern color     FiboLineColor     = White;
extern int       FiboLineWidth     = 1;
extern int       FiboLineStyle     = 2;
extern string    FiboLevels        = "0,0.382,0.5,0.618,1";
extern string    FiboMask          = "T5.1' = %$'";
extern bool      Reverse100and0    = false;

//---- indicator buffers
double ZigzagBuffer[];
double HighMapBuffer[];
double LowMapBuffer[];
int level=3; // recounting's depth 
bool downloadhistory=false;

double   FibLevels[20];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
   IndicatorBuffers(3);
//---- drawing settings
   SetIndexStyle(0,DRAW_SECTION);
//---- indicator buffers mapping
   SetIndexBuffer(0,ZigzagBuffer);
   SetIndexBuffer(1,HighMapBuffer);
   SetIndexBuffer(2,LowMapBuffer);
   SetIndexEmptyValue(0,0.0);

//---- indicator short name
   IndicatorShortName("ZigZag("+ExtDepth+","+ExtDeviation+","+ExtBackstep+")");
//---- initialization done
   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--)
     {
      val=Low[iLowest(NULL,0,MODE_LOW,ExtDepth,shift)];
      if(val==lastlow) val=0.0;
      else 
        { 
         lastlow=val; 
         if((Low[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 (Low[shift]==val) LowMapBuffer[shift]=val; else LowMapBuffer[shift]=0.0;
      //--- high
      val=High[iHighest(NULL,0,MODE_HIGH,ExtDepth,shift)];
      if(val==lasthigh) val=0.0;
      else 
        {
         lasthigh=val;
         if((val-High[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 (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>=0;shift--)
     {
      res=0.0;
      switch(whatlookfor)
        {
         case 0: // look for peak or lawn 
            if (lastlow==0 && lasthigh==0)
              {
               if (HighMapBuffer[shift]!=0)
                 {
                  lasthigh=High[shift];
                  lasthighpos=shift;
                  whatlookfor=-1;
                  ZigzagBuffer[shift]=lasthigh;
                  res=1;
                 }
               if (LowMapBuffer[shift]!=0)
                 {
                  lastlow=Low[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; 
        }
     }
   PlotFibo();
   return(0);
  }


//+------------------------------------------------------------------+
int deinit()    {
//+------------------------------------------------------------------+
  ObjectDelete("#zzfibo");
  return(0);
}

//+------------------------------------------------------------------+
int PlotFibo()    {
//+------------------------------------------------------------------+
  datetime t0=0, t1=0, t2=0, ta=0, tb=0;
  double   z0=0, z1=0, z2=0, za=0, zb=0;  
  for (int ii=0; ii<99; ii++)   {
//    d(ii,DateToStr(Time[ii]),NumberToStr(ZigzagBuffer[ii],"3.5"),NumberToStr(High[ii],"3.5"),NumberToStr(Low[ii],"3.5"));
    if (ZigzagBuffer[ii] == 0)               continue;
    if (ZigzagBuffer[ii] == EMPTY_VALUE)     continue;
    if (t1>0)   { t2=Time[ii];  z2=ZigzagBuffer[ii];  break;      }
    if (t0>0)   { t1=Time[ii];  z1=ZigzagBuffer[ii];  continue;   }
    t0=Time[ii];  z0=ZigzagBuffer[ii];
  }
  double zmax = MathMax(z0,MathMax(z1,z2));  
  double zmin = MathMin(z0,MathMin(z1,z2));  
  
  if (z0==zmax && z1==zmin)   { ta=t0; tb=t1; za=z0; zb=z1; }    else
  if (z0==zmax && z2==zmin)   { ta=t0; tb=t2; za=z0; zb=z2; }    else
  if (z1==zmax && z2==zmin)   { ta=t1; tb=t2; za=z1; zb=z2; }    else
  if (z1==zmax && z0==zmin)   { ta=t1; tb=t0; za=z1; zb=z0; }    else
  if (z2==zmax && z0==zmin)   { ta=t2; tb=t0; za=z2; zb=z0; }    else
  if (z2==zmax && z1==zmin)   { ta=t2; tb=t1; za=z2; zb=z1; }

  int levels = StrToDoubleArray(FiboLevels,FibLevels);
  string ObjName = "#zzfibo";
  if (Reverse100and0)
    ObjectCreate(ObjName,OBJ_FIBO,0,tb,zb,ta,za);
  else
    ObjectCreate(ObjName,OBJ_FIBO,0,tb,za,ta,zb);
  ObjectSet(ObjName,OBJPROP_RAY,false);
  ObjectSet(ObjName,OBJPROP_COLOR,CLR_NONE);
  ObjectSet(ObjName,OBJPROP_FIBOLEVELS,levels);
  ObjectSet(ObjName,OBJPROP_LEVELCOLOR,FiboLineColor);
  ObjectSet(ObjName,OBJPROP_LEVELSTYLE,FiboLineStyle);
  ObjectSet(ObjName,OBJPROP_LEVELWIDTH,FiboLineWidth);
  if (levels >  0)   { ObjectSet(ObjName,OBJPROP_FIRSTLEVEL,   FibLevels[0]);    ObjectSetFiboDescription(ObjName,0, NumberToStr(StrToNumber(100*FibLevels[0]), FiboMask));  }  
  if (levels >  1)   { ObjectSet(ObjName,OBJPROP_FIRSTLEVEL+1, FibLevels[1]);    ObjectSetFiboDescription(ObjName,1, NumberToStr(StrToNumber(100*FibLevels[1]), FiboMask));  }  
  if (levels >  2)   { ObjectSet(ObjName,OBJPROP_FIRSTLEVEL+2, FibLevels[2]);    ObjectSetFiboDescription(ObjName,2, NumberToStr(StrToNumber(100*FibLevels[2]), FiboMask));  }  
  if (levels >  3)   { ObjectSet(ObjName,OBJPROP_FIRSTLEVEL+3, FibLevels[3]);    ObjectSetFiboDescription(ObjName,3, NumberToStr(StrToNumber(100*FibLevels[3]), FiboMask));  }  
  if (levels >  4)   { ObjectSet(ObjName,OBJPROP_FIRSTLEVEL+4, FibLevels[4]);    ObjectSetFiboDescription(ObjName,4, NumberToStr(StrToNumber(100*FibLevels[4]), FiboMask));  }  
  if (levels >  5)   { ObjectSet(ObjName,OBJPROP_FIRSTLEVEL+5, FibLevels[5]);    ObjectSetFiboDescription(ObjName,5, NumberToStr(StrToNumber(100*FibLevels[5]), FiboMask));  }  
  if (levels >  6)   { ObjectSet(ObjName,OBJPROP_FIRSTLEVEL+6, FibLevels[6]);    ObjectSetFiboDescription(ObjName,6, NumberToStr(StrToNumber(100*FibLevels[6]), FiboMask));  }  
  if (levels >  7)   { ObjectSet(ObjName,OBJPROP_FIRSTLEVEL+7, FibLevels[7]);    ObjectSetFiboDescription(ObjName,7, NumberToStr(StrToNumber(100*FibLevels[7]), FiboMask));  }  
  if (levels >  8)   { ObjectSet(ObjName,OBJPROP_FIRSTLEVEL+8, FibLevels[8]);    ObjectSetFiboDescription(ObjName,8, NumberToStr(StrToNumber(100*FibLevels[8]), FiboMask));  }  
  if (levels >  9)   { ObjectSet(ObjName,OBJPROP_FIRSTLEVEL+9, FibLevels[9]);    ObjectSetFiboDescription(ObjName,9, NumberToStr(StrToNumber(100*FibLevels[9]), FiboMask));  }  
  if (levels > 10)   { ObjectSet(ObjName,OBJPROP_FIRSTLEVEL+10,FibLevels[10]);   ObjectSetFiboDescription(ObjName,10,NumberToStr(StrToNumber(100*FibLevels[10]),FiboMask));  }  
  if (levels > 11)   { ObjectSet(ObjName,OBJPROP_FIRSTLEVEL+11,FibLevels[11]);   ObjectSetFiboDescription(ObjName,11,NumberToStr(StrToNumber(100*FibLevels[11]),FiboMask));  }  
  if (levels > 12)   { ObjectSet(ObjName,OBJPROP_FIRSTLEVEL+12,FibLevels[12]);   ObjectSetFiboDescription(ObjName,12,NumberToStr(StrToNumber(100*FibLevels[12]),FiboMask));  }  
  if (levels > 13)   { ObjectSet(ObjName,OBJPROP_FIRSTLEVEL+13,FibLevels[13]);   ObjectSetFiboDescription(ObjName,13,NumberToStr(StrToNumber(100*FibLevels[13]),FiboMask));  }  
  if (levels > 14)   { ObjectSet(ObjName,OBJPROP_FIRSTLEVEL+14,FibLevels[14]);   ObjectSetFiboDescription(ObjName,14,NumberToStr(StrToNumber(100*FibLevels[14]),FiboMask));  }  
  if (levels > 15)   { ObjectSet(ObjName,OBJPROP_FIRSTLEVEL+15,FibLevels[15]);   ObjectSetFiboDescription(ObjName,15,NumberToStr(StrToNumber(100*FibLevels[15]),FiboMask));  }  
  if (levels > 16)   { ObjectSet(ObjName,OBJPROP_FIRSTLEVEL+16,FibLevels[16]);   ObjectSetFiboDescription(ObjName,16,NumberToStr(StrToNumber(100*FibLevels[16]),FiboMask));  }  
  if (levels > 17)   { ObjectSet(ObjName,OBJPROP_FIRSTLEVEL+17,FibLevels[17]);   ObjectSetFiboDescription(ObjName,17,NumberToStr(StrToNumber(100*FibLevels[17]),FiboMask));  }  
  if (levels > 18)   { ObjectSet(ObjName,OBJPROP_FIRSTLEVEL+18,FibLevels[18]);   ObjectSetFiboDescription(ObjName,18,NumberToStr(StrToNumber(100*FibLevels[18]),FiboMask));  }  
  if (levels > 19)   { ObjectSet(ObjName,OBJPROP_FIRSTLEVEL+19,FibLevels[19]);   ObjectSetFiboDescription(ObjName,19,NumberToStr(StrToNumber(100*FibLevels[19]),FiboMask));  }  
  return(0);
}  

//+------------------------------------------------------------------+
#include <hanover --- extensible functions (np).mqh>

