//+------------------------------------------------------------------+ 
//|                                        WM_Pattern.mq4    | 
//+------------------------------------------------------------------+ 
//| created from 3_Level_ZZ_Semafor_TRO_MODIFIED_VERSION             |
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//   Version 0.1 
//   Author: t1minator 
//    This version was created from 3_Level_ZZ_Semafor_TRO_MODIFIED_VERSION
//    Thanks to squalou for the initial FILE
//   - Edits
//     Started removing irrelevant code to this indicator
//     Crated a drawing section to trace a W or M depending on the current ZZ final 5
//
 
#property copyright "t1minator" 
#property link      "t1minator@yahoo.com" 

#property indicator_chart_window 
#property indicator_buffers 2
#property indicator_color1 Chocolate 
#property indicator_color2 Chocolate 
#property indicator_color3 Red
#property indicator_color4 MediumVioletRed
#property indicator_color5 Blue
#property indicator_color6 Blue
extern string LineName="MyLine1";
extern color LineColor=AliceBlue; 
extern int LineStyle=STYLE_SOLID;
//+--------- TRO MODIFICATION ---------------------------------------+ 

extern bool   ShowTrendlines  = true; 

extern string myUpperTrendLineName  = "UpperTrendLine001";
extern color  myUpperTrendLineColor = Gray; 
extern int    myUpperTrendLineStyle = STYLE_SOLID;
extern int    myUpperTrendLineWidth = 2;
extern string myUpperSoundFile      = "ahooga.wav";

extern string myLowerTrendLineName  = "LowerTrendLine001";
extern color  myLowerTrendLineColor = Gray; 
extern int    myLowerTrendLineStyle = STYLE_SOLID;
extern int    myLowerTrendLineWidth = 2;
extern string myLowerSoundFile      = "siren.wav";


extern int    myThreshold      = 1;

extern bool   SoundAlert    = false ;
extern bool   ShowComment   = false ; 
extern int    myBars         = 100 ;
extern int    NumComments    = 5 ;

//---- input parameters 
extern double Period1=10; 
extern string   Dev_Step_1="1,3";
extern int Symbol_1_Code=140;

extern int Symbol_1_Size=1;
extern int BarsBack = 5000;//max number of bars in the past; added by Squalou to cut CPU...

//---- buffers 
double BufferUp1[];
double BufferDn1[]; 
//double ZZ[]; 
double BufferUp2[];
double BufferDn2[]; 
double BufferUp3[];
double BufferDn3[]; 
int currentIndex=0;

int F_Period;
int N_Period;
int H_Period;
int Dev1;
int Stp1;
int Dev2;
int Stp2;
int Dev3;
int Stp3;
//+--------- TRO MODIFICATION ---------------------------------------+ 
string symbol, tChartPeriod,  tShortName ;  
int    digits, period  ; 

int OldBars = -1 ;

color tColor = Gray ;

int i, j, k, tltop, tlbot;
 
string Messages[26], theMessage, space ;

bool roll ;

double point ;
double upperTL[3], lowerTL[3];
double UpperTrendLinePrice, LowerTrendLinePrice, UpperLimit, LowerLimit, xThreshold;


datetime upperTLtime[3], lowerTLtime[3];
 
string TAG = "3lzz", OBJ001, OBJ002, OBJ003, OBJ004 ;  
 
 
//+------------------------------------------------------------------+ 
int init() 
  { 
//+--------- TRO MODIFICATION ---------------------------------------+  
   period       = Period() ;     
   tChartPeriod =  TimeFrameToString(period) ;
   symbol       =  Symbol() ;
   digits       =  Digits ;
   point        =  Point ;   
   
   if(digits == 5 || digits == 3) { digits = digits - 1 ; point = point * 10 ; }   
   
   
   tShortName = "tbb"+ symbol + tChartPeriod  ;
    
   xThreshold   = myThreshold * point ;   
  
 
   OBJ001       = TAG + "001";
   OBJ002       = TAG + "002";  
   OBJ003       = TAG + "003";
   OBJ004       = TAG + "004";  
  
// --------- Корректируем периоды для построения ЗигЗагов
  
  
   if (Period1>0) F_Period=MathCeil(Period1*Period()); else F_Period=0; 
   
//---- Обрабатываем 1 буфер 
   if (Period1>0)
   {
   SetIndexStyle(0,DRAW_ARROW,0,Symbol_1_Size); 
   SetIndexArrow(0,Symbol_1_Code); 
   SetIndexBuffer(0,BufferUp1); 
   SetIndexEmptyValue(0,0.0); 
   
   SetIndexStyle(1,DRAW_ARROW,0,Symbol_1_Size); 
   SetIndexArrow(1,Symbol_1_Code); 
   SetIndexBuffer(1,BufferDn1); 
   SetIndexEmptyValue(1,0.0); 

   }
   
// Обрабатываем значения девиаций и шагов
   int CDev=0;
   int CSt=0;
   int Mass[]; 
   int C=0;  
   if (IntFromStr(Dev_Step_1,C, Mass)==1) 
      {
        Stp1=Mass[1];
        Dev1=Mass[0];
      }
    
   return(0); 
  } 

//+------------------------------------------------------------------+

void ObDeleteObjectsByPrefix(string Prefix)
{
   int L = StringLen(Prefix);
   int i = 0; 
   while(i < ObjectsTotal())
     {
       string ObjName = ObjectName(i);
       if(StringSubstr(ObjName, 0, L) != Prefix) 
         { 
           i++; 
           continue;
         }
       ObjectDelete(ObjName);
     }
}
    
//+------------------------------------------------------------------+
int deinit()
{
   Comment("") ;
       
   ObDeleteObjectsByPrefix(TAG);  
   
   //TRO() ;
   
   return(0);
}

//+------------------------------------------------------------------+ 
int start() 
  { 
  int    counted_bars=IndicatorCounted();
  int NumOfBars = 0;
  if(NumOfBars==0)NumOfBars=Bars;
  //+--------------------+
 
  if (Period1>0) ZigZag(BufferUp1,BufferDn1,Period1,Dev1,Stp2);

//  if(Show.Trendlines)
  {
     tltop = 0 ; 
     tlbot = 0 ;

    for( j=0; j<1000; j++ )
    {   
       while(true)
       {
          // Grab the last valid time and price points on the CHART
          // for top and bottom zigz
          if( BufferUp1[j] != 0 && tlbot < 3 ) 
          {
             lowerTLtime[tlbot] = Time[j] ; 
             lowerTL[tlbot] = BufferUp1[j] ; 
             tlbot = tlbot + 1 ; 
             break ; 
          }
          if( BufferDn1[j] != 0 && tltop < 3 ) 
          {
             upperTLtime[tltop] = Time[j] ; 
             upperTL[tltop] = BufferDn1[j] ; 
             tltop = tltop + 1 ; 
             currentIndex = j;
             break ; 
          }
          break ;
       } // while

       if( tlbot >=3 && tltop >= 3 ) { break ;  }
    } // for j   

    double trendMA = iMA(NULL,0,35,0,MODE_EMA,PRICE_CLOSE,0);

    // DRAW THE W OR M LINES
    // DRAW_LINE
    if (lowerTLtime[0] > upperTLtime[0])
    {
         //-----------------------------------------------------------+         
         // Draw first leg of M formation
         //-----------------------------------------------------------+
         DrawPriceTrendLines(OBJ003, lowerTLtime[0], upperTLtime[0], lowerTL[0], 
                           upperTL[0], myUpperTrendLineColor, myUpperTrendLineStyle, myUpperTrendLineWidth) ;
         //-----------------------------------------------------------+
         // Draw Second leg of M formation
         //-----------------------------------------------------------+
         DrawPriceTrendLines(OBJ001, lowerTLtime[1], upperTLtime[0],lowerTL[1], upperTL[0], 
                            myUpperTrendLineColor, myUpperTrendLineStyle, myUpperTrendLineWidth) ;
         //-----------------------------------------------------------+
         // Draw Third leg of M formation
         //-----------------------------------------------------------+
         DrawPriceTrendLines(OBJ004, lowerTLtime[1], upperTLtime[1], lowerTL[1], 
                           upperTL[1], myUpperTrendLineColor, myUpperTrendLineStyle, myUpperTrendLineWidth) ;
         //-----------------------------------------------------------+ 
         // Draw Forth leg of M formation
         //-----------------------------------------------------------+
         DrawPriceTrendLines(OBJ002, lowerTLtime[2], upperTLtime[1], lowerTL[2], 
                           upperTL[1], myLowerTrendLineColor, myLowerTrendLineStyle, myLowerTrendLineWidth) ;
         //-----------------------------------------------------------+
         double topDiff = MathAbs(upperTL[0]-upperTL[1]) ;
         double threshold = 0.001*upperTL[0];
         //-----------------------------------------------------------+         
         if (upperTL[0] > trendMA) // check for uptrend ** REPLACE WITH GENERIC UPTREND FOR USER SELECTION **
         if ( topDiff < threshold) // Check humps for proximity if within x% consider it valid ** ALLOW USER INPUT **                              
         {
            //-----------------------------------------------------------+
            // Indicate Potential M formation
            //-----------------------------------------------------------+
            if (lowerTL[0] < lowerTL[1]) // current dip is less than the dip between the humps
               Messages[1] = "Confirmed M FORMATION " + topDiff + " " + threshold;
            else // not yet confirmed or not complete  
               Messages[1] = "Possible M FORMATION " + topDiff + " " + threshold;
         }
         //-----------------------------------------------------------+             
         if (upperTL[0] < trendMA) // check for downtrend 
         //-----------------------------------------------------------+
         // start looking for a W formation
         //-----------------------------------------------------------+
         {
            double botDiff = MathAbs(lowerTL[0]-lowerTL[1]) ;
            threshold = 0.001*lowerTL[0];
            if ( botDiff < threshold)
               Messages[1] = "POSSIBLE W FORMING";
         }
         //-----------------------------------------------------------+         
         Comment(Messages[1]);
    }                                         
    if (lowerTLtime[0] < upperTLtime[0])
    {
         //-----------------------------------------------------------+         
         // Draw first leg of W formation
         //-----------------------------------------------------------+
         DrawPriceTrendLines(OBJ003, lowerTLtime[0], upperTLtime[0], lowerTL[0], 
                           upperTL[0], myUpperTrendLineColor, myUpperTrendLineStyle, myUpperTrendLineWidth) ;
         //-----------------------------------------------------------+
         // Draw Second leg of W formation
         //-----------------------------------------------------------+
         DrawPriceTrendLines(OBJ001, lowerTLtime[0], upperTLtime[1],lowerTL[0], upperTL[1], 
                            myUpperTrendLineColor, myUpperTrendLineStyle, myUpperTrendLineWidth) ;
         //-----------------------------------------------------------+  
         // Draw Third leg of W formation
         //-----------------------------------------------------------+
         DrawPriceTrendLines(OBJ004, lowerTLtime[1], upperTLtime[1], lowerTL[1], 
                           upperTL[1], myUpperTrendLineColor, myUpperTrendLineStyle, myUpperTrendLineWidth) ;
         //-----------------------------------------------------------+
         // Draw Forth leg of W formation
         //-----------------------------------------------------------+
         DrawPriceTrendLines(OBJ002, lowerTLtime[1], upperTLtime[2], lowerTL[1], 
                           upperTL[2], myLowerTrendLineColor, myLowerTrendLineStyle, myLowerTrendLineWidth) ;

         botDiff = MathAbs(lowerTL[0]-lowerTL[1]) ;
         threshold = 0.001*upperTL[0];
         
    
         if (upperTL[0] < trendMA) // check for downtrend ** REPLACE WITH GENERIC UPTREND FOR USER SELECTION **
         if ( topDiff < threshold) // Check humps for proximity if within x% consider it valid ** ALLOW USER INPUT **
                                   // noticed the threshold should be different on diff time frames 
         {
            //-----------------------------------------------------------+
            // Indicate Potential W formation
            //-----------------------------------------------------------+
            if (upperTL[0] > upperTL[1]) // current run is greater than the run between the W lows
               Messages[1] = "Confirmed W FORMATION " + topDiff + " " + threshold;
            else // not yet confirmed or not complete  
               Messages[1] = "Possible W FORMATION " + topDiff + " " + threshold;
         }
    
         if (upperTL[0] > trendMA) // check for uptrend 
         // start looking for a M formation
         {
            topDiff = MathAbs(upperTL[0]-upperTL[1]) ;
            threshold = 0.001*upperTL[0];
            if ( topDiff < threshold)
               Messages[1] = "POSSIBLE M FORMING";
         }
         Comment(Messages[1]);
    }                                         

 
   } // if(Show.Trendlines)
    
   OldBars = Bars ;   

   return(0);
}

//+--------- TRO MODIFICATION ---------------------------------------+  

string TimeFrameToString(int tf)
{
   string tfs;
   switch(tf) {
      case PERIOD_M1:  tfs="M1"  ; break;
      case PERIOD_M5:  tfs="M5"  ; break;
      case PERIOD_M15: tfs="M15" ; break;
      case PERIOD_M30: tfs="M30" ; break;
      case PERIOD_H1:  tfs="H1"  ; break;
      case PERIOD_H4:  tfs="H4"  ; break;
      case PERIOD_D1:  tfs="D1"  ; break;
      case PERIOD_W1:  tfs="W1"  ; break;
      case PERIOD_MN1: tfs="MN";
   }
   return(tfs);
}


//+------------------------------------------------------------------+  
int ZigZag( double& BufferUP[], double& BufferDN[], int Depth, int Dev, int Backstep )
//+------------------------------------------------------------------+ 
{
   int    shift, back,lasthighpos,lastlowpos;
   double val,res;
   double curlow,curhigh,lasthigh,lastlow;

   int bars = MathMin(Bars,BarsBack);
   
   for(shift=bars-Depth; shift>=0; shift--)
     {
      val=Close[Lowest(NULL,0,MODE_CLOSE,Depth,shift)];
      if(val==lastlow) val=0.0;
      else 
      { 
       lastlow=val; 
       if((Close[shift]-val)>(Dev*Point)) val=0.0;
       else
       {
        for(back=1; back<=Backstep; back++)
          {
           res=BufferUP[shift+back];
           if((res!=0)&&(res>val)) BufferUP[shift+back]=0.0; 
          }
       }
      } 
        
      BufferUP[shift]=val;
      //--- high
      val=Close[Highest(NULL,0,MODE_CLOSE,Depth,shift)];
      if(val==lasthigh) val=0.0;
      else 
      {
       lasthigh=val;
       if((val-Close[shift])>(Dev*Point)) val=0.0;
       else
       {
        for(back=1; back<=Backstep; back++)
          {
           res=BufferDN[shift+back];
           if((res!=0)&&(res<val)) BufferDN[shift+back]=0.0; 
          } 
       }
      }
      BufferDN[shift]=val;
     }
   // final cutting 
   lasthigh=-1; lasthighpos=-1;
   lastlow=-1;  lastlowpos=-1;

   for(shift=bars-Depth; shift>=0; shift--)
   {
    curlow=BufferUP[shift];
    curhigh=BufferDN[shift];
    if((curlow==0)&&(curhigh==0)) continue;
    //---
    if(curhigh!=0)
    {
     if(lasthigh>0) 
       {
        if(lasthigh<curhigh) BufferDN[lasthighpos]=0;
        else BufferDN[shift]=0;
       }
     //---
     if(lasthigh<curhigh || lasthigh<0)
       {
        lasthigh=curhigh;
        lasthighpos=shift;
       }
     lastlow=-1;
    }
    //----
    if(curlow!=0)
    {
     if(lastlow>0)
       {
        if(lastlow>curlow) BufferUP[lastlowpos]=0;
        else BufferUP[shift]=0;
       }
     //---
     if((curlow<lastlow)||(lastlow<0))
       {
        lastlow=curlow;
        lastlowpos=shift;
       } 
     lasthigh=-1;
    }
   }
  
   for(shift=bars-1; shift>=0; shift--)
   {
     if(shift>=bars-Depth) BufferUP[shift]=0.0;
     else
     {
      res=BufferDN[shift];
      if(res!=0.0) BufferDN[shift]=res;
     }
   }
}

//+------------------------------------------------------------------+   
int Str2Massive(string VStr, int& M_Count, int& VMass[])
  {
    int val=StrToInteger( VStr);
    if (val>0)
       {
         M_Count++;
         int mc=ArrayResize(VMass,M_Count);
         if (mc==0)return(-1);
          VMass[M_Count-1]=val;
         return(1);
       }
    else return(0);    
  } 
  

//+------------------------------------------------------------------+   
int IntFromStr(string ValStr,int& M_Count, int& VMass[])
  {
    
    if (StringLen(ValStr)==0) return(-1);
    string SS=ValStr;
    int NP=0; 
    string CS;
    M_Count=0;
    ArrayResize(VMass,M_Count);
    while (StringLen(SS)>0)
      {
            NP=StringFind(SS,",");
            if (NP>0)
               {
                 CS=StringSubstr(SS,0,NP);
                 SS=StringSubstr(SS,NP+1,StringLen(SS));  
               }
               else
               {
                 if (StringLen(SS)>0)
                    {
                      CS=SS;
                      SS="";
                    }
               }
            if (Str2Massive(CS,M_Count,VMass)==0) 
               {
                 return(-2);
               }
      }
    return(1);    
  }
  

//+------------------------------------------------------------------+
 

void DrawPriceTrendLines(string objname, datetime x1, datetime x2, double y1, 
                        double y2, color lineColor, int style, int width)
  {
    
   ObjectDelete(objname);
   ObjectCreate(objname, OBJ_TREND, 0, x1, y1, x2, y2, 0, 0);
   ObjectSet(objname, OBJPROP_RAY, false);
 
   ObjectSet(objname, OBJPROP_COLOR, lineColor);
   ObjectSet(objname, OBJPROP_STYLE, style);
   ObjectSet(objname, OBJPROP_WIDTH, width);

  }
 

