/*
https://www.mql5.com/en/forum/175037/page177
*/
//+------------------------------------------------------------------+
//|                                                          macd HL |
//|                                                           mladen |
//|                                                                  |
//| forex-tsd elite section only indicator                           |
//+------------------------------------------------------------------+
#property copyright "mladen"
#property link      "mladenfx@gmail.com"


#property indicator_separate_window
#property indicator_height  120 
#property indicator_buffers 7
#property indicator_color1  DeepSkyBlue
#property indicator_color2  Magenta
#property indicator_color3  LimeGreen
#property indicator_color4  LimeGreen
#property indicator_color5  Red
#property indicator_color6  Red
#property indicator_color7  DimGray
#property indicator_style4  STYLE_DOT
#property indicator_style5  STYLE_DOT
#property indicator_style7  STYLE_DOT
#property indicator_width1  2

//
//
//
//
//

extern string TimeFrame        = "Current time frame";
extern int    FastLength       = 19;
extern int    SlowLength       = 39;
extern int    SignalLength     =  9;
extern int    ApplyTo          = PRICE_WEIGHTED;
extern int    LookBackLength   = 50;
extern double UpEarlyLevel     = 0.25;
extern double DownEarlyLevel   = 0.25;
extern bool   ShowArrows       = true;
extern string ArrowsIdentifier = "macd HL";
extern color  ArrowUpColor     = Green;
extern color  ArrowDownColor   = Red;
extern bool   Interpolate      = true;

//
//
//
//
//

double macd[];
double macds[];
double macdhh[];
double macdhe[];
double macdll[];
double macdle[];
double macdzl[];
double trend[];

//
//
//
//
//

string indicatorFileName;
bool   calculateValue;
bool   returnBars;
int    timeFrame;

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int init()
{
   IndicatorBuffers(8);
   SetIndexBuffer(0,macd);   SetIndexLabel(0,"macd");
   SetIndexBuffer(1,macds);  SetIndexLabel(1,"macd signal line");
   SetIndexBuffer(2,macdhh); SetIndexLabel(2,"macd high");
   SetIndexBuffer(3,macdhe); SetIndexLabel(3,"macd upper early");
   SetIndexBuffer(4,macdle); SetIndexLabel(4,"macd lower early");
   SetIndexBuffer(5,macdll); SetIndexLabel(5,"macd low");
   SetIndexBuffer(6,macdzl); SetIndexLabel(6,"macd zero line");
   SetIndexBuffer(7,trend);
   
      indicatorFileName = WindowExpertName();
      calculateValue    = (TimeFrame=="CalculateValue"); if (calculateValue) return(0);
      returnBars        = (TimeFrame=="returnBars");     if (returnBars)     return(0);
      timeFrame         = stringToTimeFrame(TimeFrame);
   
   //
   //
   //
   //
   //

   IndicatorShortName(timeFrameToString(timeFrame)+" macd HL ("+FastLength+","+SlowLength+","+SignalLength+","+LookBackLength+","+DoubleToStr(UpEarlyLevel,3)+","+DoubleToStr(DownEarlyLevel,3)+")");
   return(0);
}

//
//
//
//
//

int deinit()
{
   if (ShowArrows)
   {
      int compareLength = StringLen(ArrowsIdentifier);
      for (int i=ObjectsTotal(); i>= 0; i--)
      {
         string name = ObjectName(i);
            if (StringSubstr(name,0,compareLength) == ArrowsIdentifier)
                ObjectDelete(name);  
      }
   }
   return(0);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int start()
{
   int i,limit;
   int counted_bars=IndicatorCounted();
   if (counted_bars>0) counted_bars--;
            limit=MathMin(Bars-counted_bars,Bars-1);
            if (returnBars)  { macd[0] = limit+1; return(0); }

   //
   //
   //
   //
   //
 
   if (calculateValue || timeFrame == Period())
   {
      double alpha = 2.0 / (1.0+SignalLength);
      for(i=limit; i>=0; i--)
      {
         macd[i] = iMA(NULL,0,FastLength,0,MODE_EMA,ApplyTo,i)-iMA(NULL,0,SlowLength,0,MODE_EMA,ApplyTo,i);
         if (i==(Bars-1))
               macds[i] = macd[i];
         else  macds[i] = macds[i+1]+alpha*(macd[i]-macds[i+1]);
      
         //
         //
         //
         //
         //
      
         double macdMax=macd[i];
         double macdMin=macd[i];
            for (int k=1; (i+k)<Bars && k<LookBackLength; k++)
            {
               macdMax = MathMax(macd[i+k],macdMax);
               macdMin = MathMin(macd[i+k],macdMin);
            }
         macdhh[i] =  macdMax;
         macdll[i] =  macdMin;
         macdzl[i] = (macdMax+macdMin)/2.0;
         macdhe[i] = macdzl[i]+(macdhh[i]-macdzl[i])*UpEarlyLevel;
         macdle[i] = macdzl[i]-(macdzl[i]-macdll[i])*DownEarlyLevel;
         
         //
         //
         //
         //
         //

         manageArrow(i);      
      }                  
      return(0);
   }
   
   //
   //
   //
   //
   //
   
   limit = MathMax(limit,MathMin(Bars,iCustom(NULL,timeFrame,indicatorFileName,"returnBars",0,0)*timeFrame/Period()));
   for (i=limit;i>=0;i--)
   {
      int y = iBarShift(NULL,timeFrame,Time[i]);
         macd[i]   = iCustom(NULL,timeFrame,indicatorFileName,"CalculateAlfr",FastLength,SlowLength,SignalLength,ApplyTo,LookBackLength,UpEarlyLevel,DownEarlyLevel,0,y);
         macds[i]  = iCustom(NULL,timeFrame,indicatorFileName,"CalculateAlfr",FastLength,SlowLength,SignalLength,ApplyTo,LookBackLength,UpEarlyLevel,DownEarlyLevel,1,y);
         macdhh[i] = iCustom(NULL,timeFrame,indicatorFileName,"CalculateAlfr",FastLength,SlowLength,SignalLength,ApplyTo,LookBackLength,UpEarlyLevel,DownEarlyLevel,2,y);
         macdhe[i] = iCustom(NULL,timeFrame,indicatorFileName,"CalculateAlfr",FastLength,SlowLength,SignalLength,ApplyTo,LookBackLength,UpEarlyLevel,DownEarlyLevel,3,y);
         macdle[i] = iCustom(NULL,timeFrame,indicatorFileName,"CalculateAlfr",FastLength,SlowLength,SignalLength,ApplyTo,LookBackLength,UpEarlyLevel,DownEarlyLevel,4,y);
         macdll[i] = iCustom(NULL,timeFrame,indicatorFileName,"CalculateAlfr",FastLength,SlowLength,SignalLength,ApplyTo,LookBackLength,UpEarlyLevel,DownEarlyLevel,5,y);
         macdzl[i] = iCustom(NULL,timeFrame,indicatorFileName,"CalculateAlfr",FastLength,SlowLength,SignalLength,ApplyTo,LookBackLength,UpEarlyLevel,DownEarlyLevel,6,y);
         manageArrow(i);      

         //
         //
         //
         //
         //
      
         if (timeFrame <= Period() || y==iBarShift(NULL,timeFrame,Time[i-1])) continue;
         if (!Interpolate) continue;

         //
         //
         //
         //
         //

         datetime time = iTime(NULL,timeFrame,y);
            for(int n = 1; i+n < Bars && Time[i+n] >= time; n++) continue;	
            for(k = 1; k < n; k++)
            {
               macd[i+k]   = macd[i]  +(macd[i+n]  -macd[i])  *k/n;
               macds[i+k]  = macds[i] +(macds[i+n] -macds[i]) *k/n;
               macdhh[i+k] = macdhh[i]+(macdhh[i+n]-macdhh[i])*k/n;
               macdhe[i+k] = macdhe[i]+(macdhe[i+n]-macdhe[i])*k/n;
               macdle[i+k] = macdle[i]+(macdle[i+n]-macdle[i])*k/n;
               macdll[i+k] = macdll[i]+(macdll[i+n]-macdll[i])*k/n;
               macdzl[i+k] = macdzl[i]+(macdzl[i+n]-macdzl[i])*k/n;
            }               
   }
   
   //
   //
   //
   //
   //
   
   return(0);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//


void manageArrow(int i)
{
   if (ShowArrows && !calculateValue)
   {
      double dist = iATR(NULL,0,20,i)/2.0;
      ObjectDelete(ArrowsIdentifier+Time[0]);         
            
      //
      //
      //
      //
      //
           
      trend[i] = trend[i+1];
         if (macd[i]>macds[i]) trend[i] =  1;
         if (macd[i]<macds[i]) trend[i] = -1;
         if (trend[i] !=trend[i+1])
         {
            string name = ArrowsIdentifier+Time[i];
            if (trend[i] == 1)
            {
               ObjectCreate(name,OBJ_ARROW,0, Time[i],Low[i]-dist );
                  ObjectSet(name,OBJPROP_ARROWCODE,241);
                  ObjectSet(name,OBJPROP_COLOR,ArrowUpColor);
            }
            else
            {
               ObjectCreate(name,OBJ_ARROW,0, Time[i],High[i]+dist );
                  ObjectSet(name,OBJPROP_ARROWCODE,242);
                  ObjectSet(name,OBJPROP_COLOR,ArrowDownColor);
            }
         }
   }
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

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 char = StringGetChar(s, length);
         if((char > 96 && char < 123) || (char > 223 && char < 256))
                     s = StringSetChar(s, length, char - 32);
         else if(char > -33 && char < 0)
                     s = StringSetChar(s, length, char + 224);
   }
   return(s);
}