//+------------------------------------------------------------------+
//|                                           High Low Wave.mq4 
//|                                           Modified By: K.Trim                     
//+------------------------------------------------------------------+


#property indicator_separate_window
#property indicator_buffers    6
#property indicator_color1     DarkGray
#property indicator_color2     DodgerBlue
#property indicator_color3     LimeGreen
#property indicator_color4     LimeGreen
#property indicator_color5     Red
#property indicator_color6     Red
#property indicator_style1     STYLE_DOT
#property indicator_width1     1
#property indicator_width2     1
#property indicator_width3     2
#property indicator_width4     2
#property indicator_width5     2
#property indicator_width6     2
#property indicator_minimum    -5
#property indicator_maximum    105
#property indicator_levelcolor DarkSlateGray
#property indicator_levelstyle 2

//
//
//

extern string TimeFrame             = "current time frame";
int    KPeriod               =   2;
int    DPeriod               =   1;
int    Slowing               =   1;
int    MAMethod              =   1;
int    PriceField            =   1;
int    overBought            =  80;
int    overSold              =  20;
extern bool   showLevels            = false;
extern bool   showText              = true;

extern string Identifier            = "HighLowWaveArrows";
extern color  OBColor               = Green;
extern color  OSColor               = FireBrick;

extern double UpperGap              = 0.0;
extern double LowerGap              = 0.5;

extern color  LabelColor1           = LimeGreen;
extern color  LabelColor2           = Red;
extern int    Labeldistance         = 2;

extern bool   alertsOn              = false;
extern bool   alertsOnCurrent       = true;
extern bool   alertsMessage         = true;
extern bool   alertsSound           = true;
extern bool   alertsEmail           = false;

extern int    History               = 5000;

extern string BuyAlert              = "  -  BUY  -  ";
extern string SellAlert             = "  -  SELL  -  ";


//
//


double KFull[];
double DFull[];
double Uppera[];
double Upperb[];
double Lowera[];
double Lowerb[];
double trend[];
double HighMapBuffer[];
double LowMapBuffer[];

//
//
//
//
//

int    timeFrame;
string IndicatorFileName;
bool   ReturningBars;

//+-------------------------------------------------------------------
//|                                                                  
//+-------------------------------------------------------------------

int init()
{
   IndicatorBuffers(9);
      SetIndexBuffer(0,DFull);  SetIndexLabel(1,"HL Wave");
      SetIndexBuffer(1,KFull);  
      SetIndexBuffer(2,Uppera); SetIndexLabel(2,NULL);
      SetIndexBuffer(3,Upperb); SetIndexLabel(3,NULL);
      SetIndexBuffer(4,Lowera); SetIndexLabel(4,NULL);
      SetIndexBuffer(5,Lowerb); SetIndexLabel(5,NULL);
      SetIndexBuffer(6,trend);
      SetIndexBuffer(7,HighMapBuffer);
      SetIndexBuffer(8,LowMapBuffer);

      //
      //
         
         IndicatorFileName = WindowExpertName();
         ReturningBars     = (TimeFrame=="returnBars");   if (ReturningBars)  { showText=False; return(0); }
         timeFrame         = stringToTimeFrame(TimeFrame);
      
      //
      //
         
      DPeriod = MathMax(DPeriod,1);
      if (DPeriod==1) {
            SetIndexStyle(0,DRAW_NONE);
            SetIndexLabel(0,NULL);
          }
      else {
            SetIndexStyle(0,DRAW_LINE); 
            SetIndexLabel(0,"Signal");
         }               
      if (showLevels)
           { SetLevelValue(0,overBought);  SetLevelValue(1,overSold);    }
      else { SetLevelValue(0,EMPTY_VALUE); SetLevelValue(1,EMPTY_VALUE); }
         
   //
   //
   //
   //
   //

   string shortName = "HighLow Wave ("+timeFrameToString(timeFrame)+")";

   IndicatorShortName(shortName);
   return(0);
}

//
//
//
//
//

int deinit()
{
   string lookFor       = Identifier+":";
   int    lookForLength = StringLen(lookFor);
   for (int i=ObjectsTotal()-1; i>=0; i--)
   {
      string objectName = ObjectName(i);
         if (StringSubstr(objectName,0,lookForLength) == lookFor) ObjectDelete(objectName);
   }
   return(0);
}

//+-------------------------------------------------------------------
//|                                                                  
//+-------------------------------------------------------------------
//
//
//
//
//

int start()
{
   int counted_bars=IndicatorCounted();
   int i,limit;

   if(counted_bars < 0)   return(-1);
   if(counted_bars > 0)   counted_bars--;
           limit = MathMin(Bars-counted_bars,Bars-1);
           if (limit>History) limit = History;
           if (ReturningBars)  { KFull[0] = limit+1; return(0); }
           if (timeFrame > Period()) limit = MathMax(limit,MathMin(History,iCustom(NULL,timeFrame,IndicatorFileName,"returnBars",0,0)*timeFrame/Period()));

   //
   //
   //
   //
   //
  
   if (trend[limit]== 1) CleanPoint(limit,Uppera,Upperb);
   if (trend[limit]==-1) CleanPoint(limit,Lowera,Lowerb);
   for(i=limit; i>=0; i--)
   {
      int y = iBarShift(NULL,timeFrame,Time[i]);
         KFull[i] = iStochastic(NULL,timeFrame,KPeriod,DPeriod,Slowing,MAMethod,PriceField,MODE_MAIN,y);
         DFull[i] = iStochastic(NULL,timeFrame,KPeriod,DPeriod,Slowing,MAMethod,PriceField,MODE_SIGNAL,y);
         trend[i] = trend[i+1];
         
            if (KFull[i] < overBought && KFull[i] > overSold) trend[i] =  0;
            
            if (KFull[i] > overBought) trend[i] =  1;
            if (trend[i] == 1) LowMapBuffer[i]  = 1;
            
            if (KFull[i] < overSold  ) trend[i] = -1;
            if (trend[i] ==-1) HighMapBuffer[i] = 1;

   }
   
   //
   //
   
   for(i=limit; i>=0; i--)
   {
      Uppera[i] = EMPTY_VALUE;
      Upperb[i] = EMPTY_VALUE;
      Lowera[i] = EMPTY_VALUE;
      Lowerb[i] = EMPTY_VALUE;
         if (trend[i]== 1) PlotPoint(i,Uppera,Upperb,KFull);
         if (trend[i]==-1) PlotPoint(i,Lowera,Lowerb,KFull);

      //
      //
            
      if (showText)
      {
         deleteText(Time[i]);
         if (trend[i]!=trend[i+1])
         {
            if (trend[i] ==-1) DrawHighLabel(i,OBColor);
            if (trend[i] == 1) DrawLowLabel (i,OSColor);

         }
      }               
   }      
   
   //
   //
   
   if (alertsOn)
   {
      if (alertsOnCurrent)
           int whichBar = 0;
      else     whichBar = 1; whichBar = iBarShift(NULL,0,iTime(NULL,timeFrame,whichBar));
      if (trend[whichBar] != trend[whichBar+1])
      {
         if (trend[whichBar]   == 1) doAlert(whichBar,BuyAlert);
         if (trend[whichBar]   ==-1) doAlert(whichBar,SellAlert);
      }         
   }
   return(0);
}


//+-------------------------------------------------------------------
//|LOWER LOW, HIGHER LOW TEXT                                                                   
//+-------------------------------------------------------------------

void DrawLowLabel(int i,color theColor)
{
   string name = Identifier+":"+Time[i];
   double gap  = 3.0*iATR(NULL,0,20,i)/4.0;  
   
   double currentLow  = LowMapBuffer[i]*Point;
   double previousLow;

   for (int x=i; x<i; x++)
   {
      if (LowMapBuffer[x] == 1)
      {
         previousLow = LowMapBuffer[x]*Point;
         break;
      }
   }  
   
      if (currentLow > previousLow)
         {   
         ObjectCreate (name,OBJ_TEXT,0,Time[i],0);
         ObjectSetText(name,"HL",10,"Arial",LabelColor2);
         ObjectSet    (name,OBJPROP_PRICE1,Low[i] - UpperGap * gap); 
         }        
else   
      if (currentLow < previousLow)
         {   
         ObjectCreate (name,OBJ_TEXT,0,Time[i],0);
         ObjectSetText(name,"LL",10,"Arial",LabelColor2);
         ObjectSet    (name,OBJPROP_PRICE1,Low[i] - UpperGap * gap);
         }    
}




//+-------------------------------------------------------------------
//|HIGHER HIGH, LOWER HIGH TEXT                                                                   
//+-------------------------------------------------------------------

void DrawHighLabel(int i,color theColor)
{
   string name = Identifier+":"+Time[i];
   double gap  = 3.0*iATR(NULL,0,20,i)/4.0;  
   
   double currentHigh = HighMapBuffer[i]*Point;
   double previousHigh;  
   
   for (int x=i; x<i; x++)
   {
      if (HighMapBuffer[x] == 1)
      {
         previousHigh = HighMapBuffer[x]*Point;
         break;
      }
   }  
   

      if (currentHigh > previousHigh)
         {
         ObjectCreate (name,OBJ_TEXT,0,Time[i],0);
         ObjectSetText(name,"HH",10,"Arial",LabelColor1);
         ObjectSet    (name,OBJPROP_PRICE1,High[i] + LowerGap * gap);
         }            
else         
      if (currentHigh < previousHigh)
         {
         ObjectCreate (name,OBJ_TEXT,0,Time[i],0);
         ObjectSetText(name,"LH",10,"Arial",LabelColor1);
         ObjectSet    (name,OBJPROP_PRICE1,High[i] + LowerGap * gap);
         }             
}

//-----------------------------------------------------------------------------------------//

void deleteText(datetime time)
{
   string lookFor = Identifier+":"+time; ObjectDelete(lookFor);
}





//+-------------------------------------------------------------------
//|ALERTS                                                                  
//+-------------------------------------------------------------------

void doAlert(int forBar, string doWhat)
{
   static string   previousAlert="nothing";
   static datetime previousTime;
   string message;
   
   if (previousAlert != doWhat || previousTime != Time[forBar]) {
       previousAlert  = doWhat;
       previousTime   = Time[forBar];


       message =  StringConcatenate(Symbol(),doWhat,"@ ",Bid," -  ",timeFrameToString(timeFrame)," - HL Wave");
          if (alertsMessage) Alert(message);
          if (alertsEmail)   SendMail(StringConcatenate(Symbol(),"HL Wave "),message);
          if (alertsSound)   PlaySound("alert2.wav");
   }
}





//+-------------------------------------------------------------------
//|                                                                  
//+-------------------------------------------------------------------

void CleanPoint(int i,double& first[],double& second[])
{
   if ((second[i]  != EMPTY_VALUE) && (second[i+1] != EMPTY_VALUE))
        second[i+1] = EMPTY_VALUE;
   else
      if ((first[i] != EMPTY_VALUE) && (first[i+1] != EMPTY_VALUE) && (first[i+2] == EMPTY_VALUE))
          first[i+1] = EMPTY_VALUE;
}

//
//

void PlotPoint(int i,double& first[],double& second[],double& from[])
{
   if (first[i+1] == EMPTY_VALUE)
      {
         if (first[i+2] == EMPTY_VALUE) {
                first[i]   = from[i];
                first[i+1] = from[i+1];
                second[i]  = EMPTY_VALUE;
            }
         else {
                second[i]   =  from[i];
                second[i+1] =  from[i+1];
                first[i]    = EMPTY_VALUE;
            }
      }
   else
      {
         first[i]  = from[i];
         second[i] = EMPTY_VALUE;
      }
}





//+-------------------------------------------------------------------
//|                                                                  
//+-------------------------------------------------------------------

string priceDescription(int mode)
{
   string answer;
   switch(mode)
   {
      case 0:  answer = "Low/High"    ; break; 
      case 1:  answer = "Close/Close" ; break;
      default: answer = "Invalid price field requested";
                                    Alert(answer);
   }
   return(answer);
}
string maDescription(int mode)
{
   string answer;
   switch(mode)
   {
      case MODE_SMA:  answer = "SMA"  ; break; 
      case MODE_EMA:  answer = "EMA"  ; break;
      case MODE_SMMA: answer = "SMMA" ; break;
      case MODE_LWMA: answer = "LWMA" ; break;
      default:        answer = "Invalid MA mode requested";
                                    Alert(answer);
   }
   return(answer);
}





//+-------------------------------------------------------------------
//|                                                                  
//+-------------------------------------------------------------------

string sTfTable[] = {"M1","M5","M15","M30","H1","H4","D1","W1","MN"};
int    iTfTable[] = {1,5,15,30,60,240,1440,10080,43200};

//
//

int stringToTimeFrame(string tfs)
{
   tfs = StringUpperCase(tfs);
   for (int i=ArraySize(iTfTable)-1; i>=0; i--)
         if (tfs==sTfTable[i] || tfs==""+iTfTable[i]) return(MathMax(iTfTable[i],Period()));
                                                      return(Period());
}
string timeFrameToString(int tf)
{
   for (int i=ArraySize(iTfTable)-1; i>=0; i--) 
         if (tf==iTfTable[i]) return(sTfTable[i]);
                              return("");
}

//
//

string StringUpperCase(string str)
{
   string   s = str;

   for (int length=StringLen(str)-1; length>=0; length--)
   {
      int char1 = StringGetChar(s, length);
         if((char1 > 96 && char1 < 123) || (char1 > 223 && char1 < 256))
                     s = StringSetChar(s, length, char1 - 32);
         else if(char1 > -33 && char1 < 0)
                     s = StringSetChar(s, length, char1 + 224);
   }
   return(s);
}