//------------------------------------------------------------------
#property copyright "mladen"
#property link      "www.forex-station.com"
//------------------------------------------------------------------
#property indicator_separate_window
#property indicator_buffers 7
#property indicator_color1  C'216,234,243'
#property indicator_color2  MistyRose
#property indicator_color3  DarkGray
#property indicator_color4  DeepSkyBlue
#property indicator_color5  PaleVioletRed
#property indicator_color6  PaleVioletRed
#property indicator_color7  DarkGray
#property indicator_width1  2
#property indicator_width2  2
#property indicator_width4  2
#property indicator_width5  2
#property indicator_width6  2
#property indicator_style7  STYLE_DOT

//
//
//
//
//

extern string TimeFrame    = "current time frame";
extern int    FastEMA      = 12;
extern int    SlowEMA      = 26;
extern int    SignalEMA    =  9;
extern int    Price             = PRICE_CLOSE;
extern int    macdShift         = 0;
extern int    signalShift       = 0;
extern bool   ColorOnSlope      = false;
extern bool   alertsOn          = false;
extern bool   alertsOnZeroCross = true;
extern bool   alertsOnCurrent   = true;
extern bool   alertsMessage     = true;
extern bool   alertsSound       = true;
extern bool   alertsEmail       = false;
extern bool   ShowArrows        = false;
extern string ArrowsIdentifier  = "macdArrows1";
extern double ArrowsGap         = 0.75;
extern color  ArrowUpColor      = DeepSkyBlue;
extern int    ArrowUpWidth      = 1;
extern color  ArrowDownColor    = Red; 
extern int    ArrowDownWidth    = 1; 
extern bool   Interpolate       = true;

//
//
//
//
//

double macd[];
double macdda[];
double macddb[];
double leader[];
double leaderhu[];
double leaderhd[];
double signal[];
double trend[];

string indicatorFileName;
bool   calculateValue;
bool   returnBars;
int    timeFrame;

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

int init()
{
   IndicatorBuffers(8);
   SetIndexBuffer(0,leaderhu); SetIndexStyle(0,DRAW_HISTOGRAM);
   SetIndexBuffer(1,leaderhd); SetIndexStyle(1,DRAW_HISTOGRAM);
   SetIndexBuffer(2,leader);
   SetIndexBuffer(3,macd);
   SetIndexBuffer(4,macdda);
   SetIndexBuffer(5,macddb);
   SetIndexBuffer(6,signal);
   SetIndexBuffer(7,trend);
   
   for(int i=0;i<6;i++)
    SetIndexShift(i,  macdShift);
    SetIndexShift(6,signalShift);

         //
         //
         //
         //
         //
                  
         indicatorFileName = WindowExpertName();
         calculateValue    = (TimeFrame=="calculateValue"); if (calculateValue) return(0);
         returnBars        = (TimeFrame=="returnBars");     if (returnBars)     return(0);
         timeFrame         = stringToTimeFrame(TimeFrame);
         
         //
         //
         //
         //
         //
   
      IndicatorShortName(timeFrameToString(timeFrame)+" Leader of the MACD ("+FastEMA+","+SlowEMA+","+SignalEMA+")");
   return(0);
}
int deinit() 
{ 
   int lookForLength = StringLen(ArrowsIdentifier);
      for (int i=ObjectsTotal(); i>= 0; i--)
      {
         string name = ObjectName(i); if (StringSubstr(name,0,lookForLength) == ArrowsIdentifier) ObjectDelete(name);  
      }
   return(0);
}


//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

double work[][5];
#define _ema10 0
#define _ema11 1
#define _ema20 2
#define _ema21 3
#define _color 4

int start()
{
   int i,r,counted_bars=IndicatorCounted();
   if (counted_bars>0) counted_bars--;
            int limit=MathMin(Bars-counted_bars,Bars-1);
            if (returnBars) { leaderhu[0] = limit+1; return(0); }
            if (ArrayRange(work,0) != Bars) ArrayResize(work,Bars);
 
   //
   //
   //
   //
   //
 
   if (calculateValue || timeFrame==Period())
   {
      if (work[Bars-limit-1][_color]==-1) CleanPoint(limit,macdda,macddb);
      double fastAlpha   = 2.0/(1.0+FastEMA);
      double slowAlpha   = 2.0/(1.0+SlowEMA);
      double signalAlpha = 2.0/(1.0+SignalEMA);

      //
      //
      //
      //
      //
         
      for(i=limit, r=Bars-i-1; i>=0; i--,r++)
      {
         double price = iMA(NULL,0,1,0,MODE_SMA,Price,i);
            work[r][_color] = work[r-1][_color];
            work[r][_ema10] = work[r-1][_ema10]+fastAlpha*(price                -work[r-1][_ema10]);
            work[r][_ema11] = work[r-1][_ema11]+fastAlpha*(price-work[r][_ema10]-work[r-1][_ema11]);
            work[r][_ema20] = work[r-1][_ema20]+slowAlpha*(price                -work[r-1][_ema20]);
            work[r][_ema21] = work[r-1][_ema21]+slowAlpha*(price-work[r][_ema20]-work[r-1][_ema21]);
            macd[i]         = work[r][_ema10]-work[r][_ema20];
            leader[i]       = work[r][_ema11]-work[r][_ema21]+macd[i];
            signal[i]       = signal[i+1]+signalAlpha*(macd[i]-signal[i+1]);
            
            //
            //
            //
            //
            //
            
            leaderhu[i] = EMPTY_VALUE;
            leaderhd[i] = EMPTY_VALUE;
            macdda[i]   = EMPTY_VALUE;
            macddb[i]   = EMPTY_VALUE;
               if (leader[i] > 0) leaderhu[i] = leader[i];
               if (leader[i] < 0) leaderhd[i] = leader[i];
               if (ColorOnSlope)
               {
                  if (macd[i]>macd[i+1]) work[r][_color] =  1;
                  if (macd[i]<macd[i+1]) work[r][_color] = -1;
               }
               else
               {
                  if (macd[i]>signal[i]) work[r][_color] =  1;
                  if (macd[i]<signal[i]) work[r][_color] = -1;
               }
               if (work[r][_color]==-1) PlotPoint(i,macdda,macddb,macd);
               trend[i] = work[r][_color];
               manageArrow(i);  
      }
      manageAlerts();
      return(0);
   }
   
   //
   //
   //
   //
   //
   
   limit = MathMax(limit,MathMin(Bars,iCustom(NULL,timeFrame,indicatorFileName,"returnBars",0,0)*timeFrame/Period()));
   if (work[Bars-limit-1][_color]==-1) CleanPoint(limit,macdda,macddb);
   for (i=limit, r=Bars-i-1;i>=0;i--,r++)
   {
      int y = iBarShift(NULL,timeFrame,Time[i]);
         leader[i]  = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",FastEMA,SlowEMA,SignalEMA,Price,macdShift,signalShift,ColorOnSlope,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,2,y);
         macd[i]    = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",FastEMA,SlowEMA,SignalEMA,Price,macdShift,signalShift,ColorOnSlope,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,3,y);
         signal[i]  = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",FastEMA,SlowEMA,SignalEMA,Price,macdShift,signalShift,ColorOnSlope,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,6,y);
         trend[i]   = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",FastEMA,SlowEMA,SignalEMA,Price,macdShift,signalShift,ColorOnSlope,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,7,y);
         manageArrow(i);

         //
         //
         //
         //
         //
            
            work[r][_color] = work[r-1][_color];
               leaderhu[i] = EMPTY_VALUE;
               leaderhd[i] = EMPTY_VALUE;
               macdda[i]   = EMPTY_VALUE;
               macddb[i]   = EMPTY_VALUE;
                  if (leader[i] > 0) leaderhu[i] = leader[i];
                  if (leader[i] < 0) leaderhd[i] = leader[i];
                  if (ColorOnSlope)
                  {
                     if (macd[i]>macd[i+1]) work[r][_color] =  1;
                     if (macd[i]<macd[i+1]) work[r][_color] = -1;
                  }
                  else
                  {
                     if (macd[i]>signal[i]) work[r][_color] =  1;
                     if (macd[i]<signal[i]) work[r][_color] = -1;
                  }

            //
            //
            //
            //
            //
      
            if (!Interpolate || y==iBarShift(NULL,timeFrame,Time[i-1])) continue;

         //
         //
         //
         //
         //

         datetime time = iTime(NULL,timeFrame,y);
            for(int n = 1; i+n < Bars && Time[i+n] >= time; n++) continue;	
            for(int k = 1; k < n; k++)
            {
               leader[i+k] = leader[i] + (leader[i+n]-leader[i])*k/n;
               macd[i+k]   = macd[i]   + (macd[i+n]  -macd[i]  )*k/n;
               signal[i+k] = signal[i] + (signal[i+n]-signal[i])*k/n;
                  if (leaderhu[i] != EMPTY_VALUE) leaderhu[i+k] = leader[i+k];
                  if (leaderhd[i] != EMPTY_VALUE) leaderhd[i+k] = leader[i+k];
            }
   }
   for (i=limit, r=Bars-i-1; i>=0; i--,r++) if (work[r][_color]==-1) PlotPoint(i,macdda,macddb,macd);
   return(0);         
}

//+-------------------------------------------------------------------
//|                                                                  
//+-------------------------------------------------------------------
//
//
//
//
//

void manageAlerts()
{
   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,"up");
         if (trend[whichBar] == -1) doAlert(whichBar,"down");
      }
   }
}

//
//
//
//
//

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()," ",timeFrameToString(Period())," at ",TimeToStr(TimeLocal(),TIME_SECONDS)," Leader of the MACD changed to ",doWhat);
          if (alertsMessage) Alert(message);
          if (alertsEmail)   SendMail(StringConcatenate(Symbol()," Leader of the MACD"),message);
          if (alertsSound)   PlaySound("alert2.wav");
   }
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

void manageArrow(int i)
{
   if (ShowArrows && !calculateValue)
   {
      double dist = ArrowsGap*iATR(NULL,0,20,i);
      ObjectDelete(ArrowsIdentifier+Time[i]);         
            
      //
      //
      //
      //
      //
           
      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);
               ObjectSet(name,OBJPROP_WIDTH,ArrowUpWidth);
         }
         else
         {
            ObjectCreate(name,OBJ_ARROW,0, Time[i],High[i]+1.25*dist);
               ObjectSet(name,OBJPROP_ARROWCODE,242);
               ObjectSet(name,OBJPROP_COLOR,ArrowDownColor);
               ObjectSet(name,OBJPROP_WIDTH,ArrowDownWidth);
         }
      }
   }
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

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 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) { StringToUpper(str); return(str); }