//------------------------------------------------------------------
#property copyright "mladen"
#property link      "www.forex-tsd.com"
//------------------------------------------------------------------
#property indicator_separate_window
#property indicator_buffers 4
#property indicator_color1  LimeGreen
#property indicator_color2  Orange
#property indicator_color3  Orange
#property indicator_color4  Silver//Red
#property indicator_width1  2
#property indicator_width2  2
#property indicator_width3  2
#property indicator_style4  STYLE_DOT
#property indicator_level1  0

//
//
//
//
//

extern int                FastZLEMA   = 24;
extern int                SlowZLEMA   = 52;
extern int                SignalZLEMA = 18;
extern ENUM_APPLIED_PRICE Price       = PRICE_CLOSE;
extern bool   ColorOnSignalCross      = true;
extern bool   DoubleMacd              = false;
extern bool   alertsOn                = false;
extern bool   alertsOnCurrent         = false;
extern bool   alertsMessage           = true;
extern bool   alertsSound             = false;
extern bool   alertsEmail             = false;
extern bool   alertsNotification      = false;

double macd[];
double macdDa[];
double macdDb[];
double signal[];
double colors[];
double trend[];

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//

int init()
{
   IndicatorBuffers(6);
   SetIndexBuffer(0,macd);
   SetIndexBuffer(1,macdDa);
   SetIndexBuffer(2,macdDb);
   SetIndexBuffer(3,signal);
   SetIndexBuffer(4,colors);
   SetIndexBuffer(5,trend);
      string add = ""; if (DoubleMacd) add = "double";
      IndicatorShortName("ZeroLag MACD "+add+" ("+FastZLEMA+","+SlowZLEMA+","+SignalZLEMA+")");
   return(0);
}
int deinit() { return(0); }

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

int start()
{
   int counted_bars=IndicatorCounted();
      if(counted_bars<0) return(-1);
      if(counted_bars>0) counted_bars--;
         int limit = MathMin(Bars-counted_bars,Bars-1);

   //
   //
   //
   //
   //
   
   if (colors[limit]==-1) CleanPoint(limit,macdDa,macdDb);
   for(int i = limit; i >= 0 ; i--)
   {
      double price = iMA(NULL,0,1,0,MODE_SMA,Price,i);
      double tmacd = iZeroLag(price,FastZLEMA,i,0)-iZeroLag(price,SlowZLEMA,i,1);
      if (DoubleMacd)
            macd[i] = iZeroLag(tmacd,FastZLEMA,i,2)-iZeroLag(tmacd,SlowZLEMA,i,3); 
      else  macd[i] = tmacd;            
      macdDa[i]  = EMPTY_VALUE;
      macdDb[i]  = EMPTY_VALUE;
      signal[i]  = iZeroLag(macd[i],SignalZLEMA,i,4);
      colors[i]  = colors[i+1];
      if (ColorOnSignalCross)
         {
            if (macd[i]>signal[i]) colors[i] =  1;
            if (macd[i]<signal[i]) colors[i] = -1;
         }
      else
         {
            if (macd[i]>macd[i+1]) colors[i] =  1;
            if (macd[i]<macd[i+1]) colors[i] = -1;
         }
      if (colors[i]==-1) PlotPoint(i,macdDa,macdDb,macd);
   }         
   manageAlerts();
   return(0);
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

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; }
}

//-------------------------------------------------------------------
//                                                                  
//-------------------------------------------------------------------
//
//
//
//
//

void manageAlerts()
{
   if (alertsOn)
   {
      if (alertsOnCurrent)
           int whichBar = 0;
      else     whichBar = 1;
      
      //
      //
      //
      //
      //
      
      static string   alertType1 = "";
      static datetime alertTime1 = 0;
      if (colors[whichBar] != colors[whichBar+1])
      {
         if (ColorOnSignalCross)
         {
            if (colors[whichBar] ==  1) doAlert(alertType1,alertTime1,"macd crossed signal line up");
            if (colors[whichBar] == -1) doAlert(alertType1,alertTime1,"macd crossed signal line down");
         }
         else            
         {
            if (colors[whichBar] ==  1) doAlert(alertType1,alertTime1,"macd slope changed to up");
            if (colors[whichBar] == -1) doAlert(alertType1,alertTime1,"macd slope changed to down");
         }
      }
   }
}

//
//
//
//
//

void doAlert(string& previousAlert, datetime& previousTime, string doWhat)
{
   string message;
   
   if (previousAlert != doWhat || previousTime != Time[0]) {
       previousAlert  = doWhat;
       previousTime   = Time[0];

       //
       //
       //
       //
       //

       message = Symbol()+" at "+TimeToStr(TimeLocal(),TIME_SECONDS)+"  "+doWhat;
          if (alertsMessage)      Alert(message);
          if (alertsEmail)        SendMail(StringConcatenate(Symbol(),"macd"),message);
          if (alertsNotification) SendNotification(StringConcatenate(Symbol(),"macd "+message));
          if (alertsSound)        PlaySound("alert2.wav");
   }
}

//-------------------------------------------------------------------
//                                                                  
//-------------------------------------------------------------------
//
//
//
//
//

double workZl[][10];
#define _price 0
#define _zlema 1

double iZeroLag(double price, double length, int r, int instanceNo=0)
{
   if (ArrayRange(workZl,0)!=Bars) ArrayResize(workZl,Bars); r = Bars-r-1; instanceNo *= 2; workZl[r][_price+instanceNo] = price;

   //
   //
   //
   //
   //

   double median = 0;
   double alpha  = 2.0/(1.0+length); 
   int    per    = (length-1.0)/2.0;
   if (r<per)
          workZl[r][_zlema+instanceNo] = price;
   else   
      {
         if ((int)length%2==0)
               median = (workZl[r-per][_price+instanceNo]+workZl[r-per-1][_price+instanceNo])/2.0;
         else  median =  workZl[r-per][_price+instanceNo];
         workZl[r][_zlema+instanceNo] = workZl[r-1][_zlema+instanceNo]+alpha*(2.0*price-median-workZl[r-1][_zlema+instanceNo]);
      }            
   return(workZl[r][_zlema+instanceNo]);
}