//+------------------------------------------------------------------+
//|                                        PriceChannelZigZag_v2.mq4 |
//|                                Copyright © 2008, TrendLaboratory |
//|            http://finance.groups.yahoo.com/group/TrendLaboratory |
//|                                   E-mail: igorad2003@yahoo.co.uk |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2008, TrendLaboratory"
#property link      "http://finance.groups.yahoo.com/group/TrendLaboratory"


#property indicator_chart_window
#property indicator_buffers 1
#property indicator_color1 Gold
#property indicator_width1 2

//---- input parameters
extern int     ChannelPeriod        =  12;     //Price Channel Period
extern double  Risk                 =   0;     //Price Channel narrowing factor
extern int     PriceMode            =   0;     //Price Mode: 0-High/Low, 1-Close
extern int     BreakoutMode         =   0;     //Breakout by:0-Close,1-High/Low   
extern int     ShowPeriodsAndPips   =   1;     //0-off,1-on 
extern int     ShowPeriodsMode      =   0;     //0-off,1-full cycle,2-half cycle  
extern int     ShowPipsMode         =   0;     //0-off,1-on
extern int     TextDistance         =   3;     //in pips 
extern int     TextSize             =   8;     
extern color   TextColor            = Aqua;  
extern color   TextColorCurrUp      = Magenta;
extern color   TextColorCurrDown    = Orange; 

double ZZBuffer[];
double Hi[];
double Lo[];
double trend[];

int    ilow, ihigh, nlow, nhigh, prevnhigh,prevnlow, BarsBack, Length, loper, hiper;  
datetime lotime,hitime;
bool ftime=true;
string setup; 
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
{
   Length = ChannelPeriod;
   IndicatorBuffers(4);
   SetIndexStyle(0,DRAW_SECTION);
   SetIndexBuffer(0,ZZBuffer);
   SetIndexBuffer(1,Hi);
   SetIndexBuffer(2,Lo);
   SetIndexBuffer(3,trend);
   
   string short_name;
//---- indicator line
   
   IndicatorDigits(MarketInfo(Symbol(),MODE_DIGITS));
//---- name for DataWindow and indicator subwindow label
   short_name="PriceChannelZigZag_v2("+ChannelPeriod+","+DoubleToStr(Risk,3)+")";
   IndicatorShortName(short_name);
   SetIndexLabel(0,"PriceChannelZigZag");
//----
   SetIndexEmptyValue(0,0.0);   
   setup = StringConcatenate(Length,Risk,PriceMode,ShowPeriodsAndPips,ShowPeriodsMode,ShowPipsMode," ");
   
   return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
{
//----
   ObjDel();
//----
   return(0);
}
//+------------------------------------------------------------------+
//| PriceChannelZigZag_v2                                            |
//+------------------------------------------------------------------+
int start()
{
   int    i,shift, counted_bars=IndicatorCounted(),limit;
   double smin,smax;
   string ZZdn, ZZup;
         
   if ( counted_bars > 0 )  limit=Bars-counted_bars;
   if ( counted_bars < 0 )  return(0);
   if ( counted_bars ==0 )  limit=Bars-1; 
   if ( counted_bars < 1 ) 
   {
   for(i=0;i<Bars-1;i++) 
   ZZBuffer[i]=0;
   }
   
   for(shift=limit;shift>=0;shift--) 
   {	
   smax = High[iHighest(NULL,0,MODE_HIGH,Length,shift)];
   smin = Low[iLowest(NULL,0,MODE_LOW,Length,shift)];
   
   Hi[shift]=smax-(smax-smin)*Risk;	
   Lo[shift]=smin+(smax-smin)*Risk;      
    
      if(BreakoutMode == 0) 
      {
      double hi = Close[shift]; 
      double lo = Close[shift];
      }
      else 
      {
      hi = High[shift]; 
      lo = Low[shift];
      }  
   
   trend[shift] = trend[shift+1];
   if (hi > Hi[shift+1] && trend[shift+1] <= 0) trend[shift]= 1;   
   if (lo < Lo[shift+1] && trend[shift+1] >= 0) trend[shift]=-1;
   
      if(trend[shift]>0)
      {
         if(trend[shift]!=trend[shift+1]) 
         {
         ilow = LowestBar(iBarShift(NULL,0,hitime,FALSE)-shift,shift);
         lotime = Time[ilow];
         loper = iBarShift(NULL,0,hitime,FALSE)-ilow;
         
            if(PriceMode==0) ZZBuffer[ilow] = Low[ilow];
            else 
            ZZBuffer[ilow] = MathMin(Close[ilow],Open[ilow]); 
            
            if(ShowPeriodsAndPips > 0 && (ShowPeriodsMode > 0 || ShowPipsMode > 0) && shift!=0)
            {
            ObjectDelete("LTZZdn"+setup);
            ObjectCreate("LTZZdn"+setup+TimeToStr(Time[ilow]),OBJ_TEXT,0,Time[ilow],Low[ilow]-TextDistance*Point);
               if(ShowPeriodsMode == 0 && ShowPipsMode == 1)  
               ZZdn = " "+DoubleToStr((ZZBuffer[ilow+loper]-ZZBuffer[ilow])/Point,0);
               else
               if(ShowPeriodsMode == 1)
               {
                  if(ShowPipsMode == 1) ZZdn = " "+(hiper+loper)+" / "+DoubleToStr((ZZBuffer[ilow+loper]-ZZBuffer[ilow])/Point,0);
                  if(ShowPipsMode == 0) ZZdn = " "+(hiper+loper);
               }
               else
               if(ShowPeriodsMode == 2)
               {
                  if(ShowPipsMode == 1) ZZdn = " "+loper+" / "+DoubleToStr((ZZBuffer[ilow+loper]-ZZBuffer[ilow])/Point,0);
                  if(ShowPipsMode == 0) ZZdn = " "+loper;
               }
               
            ObjectSetText("LTZZdn"+setup+TimeToStr(Time[ilow]),ZZdn,TextSize,"Arial",TextColor);
            }
         }
         else {ZZBuffer[shift]=0;ObjectDelete("LTZZdn"+setup);}
         
         if (shift==0) 
         {
         int hilen = iBarShift(NULL,0,lotime,FALSE);
         nhigh = HighestBar(hilen,0);
         
            if(PriceMode==0) ZZBuffer[nhigh] = High[nhigh];
            else   
            ZZBuffer[nhigh]=MathMax(Close[nhigh],Open[nhigh]);
         
         if (nhigh== 0) for (i=hilen-1;i>=1;i--) ZZBuffer[i]=0; 
         if (nhigh > 0) for (i=nhigh-1;i>=0;i--) ZZBuffer[i]=0; 
            
            if(ShowPeriodsAndPips > 0 && (ShowPeriodsMode > 0 || ShowPipsMode > 0))
            {
            ObjectDelete("LTZZup"+setup);
            ObjectCreate("LTZZup"+setup,OBJ_TEXT,0,Time[nhigh],High[nhigh] + 2*TextDistance*Point);
               if(ShowPeriodsMode == 0 && ShowPipsMode == 1)  
               ZZup = " "+DoubleToStr((ZZBuffer[nhigh]-ZZBuffer[hilen])/Point,0);
               else
               if(ShowPeriodsMode == 1)
               {
                  if(ShowPipsMode == 1) ZZup = " "+(hilen-nhigh+loper)+" / "+DoubleToStr((ZZBuffer[nhigh]-ZZBuffer[hilen])/Point,0);
                  if(ShowPipsMode == 0) ZZup = " "+(hilen-nhigh+loper);
               }
               else
               if(ShowPeriodsMode == 2)
               {
                  if(ShowPipsMode == 1) ZZup = " "+(hilen-nhigh)+" / "+DoubleToStr((ZZBuffer[nhigh]-ZZBuffer[hilen])/Point,0);
                  if(ShowPipsMode == 0) ZZup = " "+(hilen-nhigh);
               }
            
            ObjectSetText("LTZZup"+setup,ZZup,TextSize,"Arial",TextColorCurrUp);
            }
         }
      }
                 
      if (trend[shift]<0)
      { 
         if( trend[shift]!=trend[shift+1]) 
         {
         ihigh = HighestBar(iBarShift(NULL,0,lotime,FALSE)-shift,shift);
         hitime=Time[ihigh];
         hiper = iBarShift(NULL,0,lotime,FALSE)-ihigh;
         
            if(PriceMode==0) ZZBuffer[ihigh] = High[ihigh];
            else   
            ZZBuffer[ihigh] = MathMax(Close[ihigh],Open[ihigh]);
            
            if(ShowPeriodsAndPips > 0 && (ShowPeriodsMode > 0 || ShowPipsMode > 0) && shift!=0)
            {
            ObjectDelete("LTZZup"+setup);
            ObjectCreate("LTZZup"+setup+TimeToStr(Time[ihigh]),OBJ_TEXT,0,Time[ihigh],High[ihigh]+2*TextDistance*Point);
               
               if(ShowPeriodsMode == 0 && ShowPipsMode == 1)  
               ZZup = " "+DoubleToStr((ZZBuffer[ihigh]-ZZBuffer[ihigh+hiper])/Point,0);
               else
               if(ShowPeriodsMode == 1)
               {
                  if(ShowPipsMode == 1) ZZup = " "+(hiper+loper)+" / "+DoubleToStr((ZZBuffer[ihigh]-ZZBuffer[ihigh+hiper])/Point,0);
                  if(ShowPipsMode == 0) ZZup = " "+(hiper+loper);
               }
               else
               if(ShowPeriodsMode == 2)
               {
                  if(ShowPipsMode == 1) ZZup = " "+hiper+" / "+DoubleToStr((ZZBuffer[ihigh]-ZZBuffer[ihigh+hiper])/Point,0);
                  if(ShowPipsMode == 0) ZZup = " "+hiper;
               }
            
            ObjectSetText("LTZZup"+setup+TimeToStr(Time[ihigh]),ZZup,TextSize,"Arial",TextColor);
            }
         }
         else {ZZBuffer[shift]=0; ObjectDelete("LTZZup"+setup);}
         
         if (shift==0)
         {
         int lolen = iBarShift(NULL,0,hitime,FALSE);
         nlow = LowestBar(lolen,0);
           
            if(PriceMode==0) ZZBuffer[nlow] = Low[nlow];
            else 
            ZZBuffer[nlow] = MathMin(Close[nlow],Open[nlow]);
         
         if (nlow==0) for (i=lolen-1;i>=1;i--) ZZBuffer[i]=0; 
         if (nlow >0) for (i=nlow-1;i>=0;i--) ZZBuffer[i]=0; 
         
            if(ShowPeriodsAndPips > 0 && (ShowPeriodsMode > 0 || ShowPipsMode > 0))
            {
            ObjectDelete("LTZZdn"+setup); 
            ObjectCreate("LTZZdn"+setup,OBJ_TEXT,0,Time[nlow],Low[nlow] - TextDistance*Point);
               if(ShowPeriodsMode == 0 && ShowPipsMode == 1)  
               ZZdn = " "+DoubleToStr((ZZBuffer[lolen]-ZZBuffer[nlow])/Point,0);
               else
               if(ShowPeriodsMode == 1)
               {
                  if(ShowPipsMode == 1) ZZdn = " "+(lolen-nlow+hiper)+" / "+DoubleToStr((ZZBuffer[lolen]-ZZBuffer[nlow])/Point,0);
                  if(ShowPipsMode == 0) ZZdn = " "+(lolen-nlow+hiper);
               }
               else
               if(ShowPeriodsMode == 2)
               {
                  if(ShowPipsMode == 1) ZZdn = " "+(lolen-nlow)+" / "+DoubleToStr((ZZBuffer[lolen]-ZZBuffer[nlow])/Point,0);
                  if(ShowPipsMode == 0) ZZdn = " "+(lolen-nlow);
               }
            ObjectSetText("LTZZdn"+setup,ZZdn,TextSize,"Arial",TextColorCurrDown); 
            }
         }
      }
      
      if(shift==0)
      {
      ObjectDelete("LTZZup"+setup+TimeToStr(Time[shift]));
      ObjectDelete("LTZZdn"+setup+TimeToStr(Time[shift]));
      }
   }
   return(0);	
}

int LowestBar(int len,int k)
{
   double min = 10000000;   
   int lobar;
   
   for (int i=k+len-1;i>=k;i--)
   {
      if(PriceMode==0)
      {
         if(i==0)
         { 
            if(Low[i] < min) 
            {
            min = Low[i]; 
            lobar = i;
            }
         }
         else
         {
            if(Low[i] < min && Low[i] < Low[i-1]) 
            {
            min = Low[i]; 
            lobar = i;
            }
         }   
      }      
      else
      {
         if(i==0)
         { 
            if(MathMin(Close[i],Open[i]) < min) 
            {
            min = MathMin(Close[i],Open[i]); 
            lobar = i;
            }
         }
         else
         {
            if(MathMin(Close[i],Open[i]) < min && MathMin(Close[i],Open[i]) < MathMin(Close[i-1],Open[i-1])) 
            {
            min = MathMin(Close[i],Open[i]); 
            lobar = i;
            }
         }   
      }         
   }
   
   if(len<=0) lobar=k;
   
   return(lobar);
} 

int HighestBar(int len,int k)
{
   double max = -10000000;   
   int hibar;
   
   for (int i=k+len-1;i>=k;i--)
   {
      if(PriceMode==0)
      {
         if(i==0)
         {    
            if(High[i] > max) 
            {
            max = High[i]; 
            hibar = i;
            }
         }
         else
         {
            if(High[i] > max && High[i] > High[i-1]) 
            {
            max = High[i]; 
            hibar = i;
            }
         }
      }   
      else
      {
         if(i==0)
         {       
            if(MathMax(Close[i],Open[i]) > max && MathMax(Close[i],Open[i]) > MathMax(Close[i-1],Open[i-1])) 
            {
            max = MathMax(Close[i],Open[i]); 
            hibar = i;
            }
         }
         else
         {
            if(MathMax(Close[i],Open[i]) > max) 
            {
            max = MathMax(Close[i],Open[i]); 
            hibar = i;
            }
         }
      }
   }
   
   if(len<=0) hibar=k;
  
   return(hibar);
} 
//----
bool ObjDel()
{
   int _GetLastError = 0;
     
   while(ObjFind("LTZZdn"+setup,0,0) > 0)
   {
      int obtotal = ObjectsTotal();
      //Print("ob=",obtotal);
      for (int i = 0; i < obtotal;i++)
      {
      //Print("Name=",ObjectName(i)," Find=",StringFind(ObjectName(i),"LTZZdn"+setup,0));
         if (StringFind(ObjectName(i),"LTZZdn"+setup,0) >= 0)
         {
            if (!ObjectDelete(ObjectName(i)))
            {
            _GetLastError = GetLastError();
            Print( "ObjectDelete( \"",ObjectName(i),"\" ) - Error #", _GetLastError );
            }
         }
      }
   }      
   
   while(ObjFind("LTZZup"+setup,0,0) > 0)
   {   
      obtotal = ObjectsTotal();
      for ( i = 0; i < obtotal;i++)
      {   
         if (StringFind(ObjectName(i),"LTZZup"+setup,0) >= 0)
         {   
            if (!ObjectDelete(ObjectName(i)))
            {
            _GetLastError = GetLastError();
            Print( "ObjectDelete( \"", ObjectName(i),"\" ) - Error #", _GetLastError );
            }
         }   
      }
   }
   if(_GetLastError > 0) return(false);
   else
   return (true);
}
//-----
int ObjFind(string name,int start, int num)
{
   int cnt = 0;
   
   for (int i = 0; i < ObjectsTotal();i++)
      if (StringFind(ObjectName(i),name,start) == num) cnt+=1;
   
   return(cnt);
}         