//+------------------------------------------------------------------+
//|                                     FX5_MACD_Divergence_V1.1.mq4 |
//|                                                              FX5 |
//|                                                    hazem@uk2.net |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2007, FX5"
#property link      "hazem@uk2.net"
//----
#property indicator_separate_window
#property indicator_buffers 4
#property indicator_color1 clrGreen
#property indicator_color2 clrRed
#property indicator_color3 clrMagenta
#property indicator_color4 clrBlue
//----
#define arrowsDisplacement 0.0001
//---- input parameters
extern string separator1="*** MACD Settings ***";
extern int    fastEMA = 12;
extern int    slowEMA = 26;
extern int    signalSMA=9;
extern string separator2="*** Indicator Settings ***";
extern bool   drawIndicatorTrendLines=true;
extern bool   drawPriceTrendLines=true;
extern bool   displayAlert=true;
//---- buffers
double bullishDivergence[];
double bearishDivergence[];
double macd[];
double signal[];
//----
static datetime lastAlertTime;
static string   indicatorName;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
//---- indicators
   SetIndexStyle(0,DRAW_ARROW);
   SetIndexStyle(1,DRAW_ARROW);
   SetIndexStyle(2,DRAW_LINE);
   SetIndexStyle(3,DRAW_LINE);
//----   
   SetIndexBuffer(0,bullishDivergence);
   SetIndexBuffer(1,bearishDivergence);
   SetIndexBuffer(2,macd);
   SetIndexBuffer(3,signal);
//----   
   SetIndexArrow(0,233);
   SetIndexArrow(1,234);
//----
   indicatorName="FX5_MACD_Divergence_v1.1("+fastEMA+", "+
                 slowEMA+", "+signalSMA+")";
   SetIndexDrawBegin(3,signalSMA);
   IndicatorDigits(Digits+2);
   IndicatorShortName(indicatorName);

   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
  {
   for(int i=ObjectsTotal()-1; i>=0; i--)
     {
      string label=ObjectName(i);
      if(StringSubstr(label,0,19)!="MACD_DivergenceLine")
         continue;
      ObjectDelete(label);
     }
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
   int countedBars=IndicatorCounted();
   if(countedBars<0)
      countedBars=0;
   CalculateIndicator(countedBars);
//---- 
   return(0);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CalculateIndicator(int countedBars)
  {
   int limit=Bars-countedBars;
   if(countedBars==0) limit-=slowEMA;
   for(int i=limit; i>=0; i--)
     {
      CalculateMACD(i);
      CatchBullishDivergence(i+2);
      CatchBearishDivergence(i+2);
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CalculateMACD(int i)
  {
   macd[i]=iMACD(NULL,0,fastEMA,slowEMA,signalSMA,
                 PRICE_CLOSE,MODE_MAIN,i);

   signal[i]=iMACD(NULL,0,fastEMA,slowEMA,signalSMA,
                   PRICE_CLOSE,MODE_SIGNAL,i);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CatchBullishDivergence(int shift)
  {
   if(IsIndicatorTrough(shift)==false)
      return;
   int currentTrough=shift;
   int lastTrough=GetIndicatorLastTrough(shift);
//----   
   if((lastTrough>=0 && lastTrough<Bars) && macd[currentTrough]>macd[lastTrough] && Low[currentTrough]<Low[lastTrough])
     {
      bullishDivergence[currentTrough]=macd[currentTrough]-
                                       arrowsDisplacement;
      //----
      if(drawPriceTrendLines==true)
         DrawPriceTrendLine(Time[currentTrough],Time[lastTrough],
                            Low[currentTrough],
                            Low[lastTrough],Green,STYLE_SOLID);
      //----
      if(drawIndicatorTrendLines==true)
         DrawIndicatorTrendLine(Time[currentTrough],
                                Time[lastTrough],
                                macd[currentTrough],
                                macd[lastTrough],
                                Green,STYLE_SOLID);
      //----
      if(displayAlert==true)
         DisplayAlert("Classical bullish divergence on: ",
                      currentTrough);
     }
//----   
   if((lastTrough>=0 && lastTrough<Bars) && macd[currentTrough]<macd[lastTrough] && Low[currentTrough]>Low[lastTrough])
     {
      bullishDivergence[currentTrough]=macd[currentTrough]-
                                       arrowsDisplacement;
      //----
      if(drawPriceTrendLines==true)
         DrawPriceTrendLine(Time[currentTrough],Time[lastTrough],
                            Low[currentTrough],
                            Low[lastTrough],Green,STYLE_DOT);
      //----
      if(drawIndicatorTrendLines==true)
         DrawIndicatorTrendLine(Time[currentTrough],
                                Time[lastTrough],
                                macd[currentTrough],
                                macd[lastTrough],
                                Green,STYLE_DOT);
      //----
      if(displayAlert==true)
         DisplayAlert("Reverse bullish divergence on: ",
                      currentTrough);
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CatchBearishDivergence(int shift)
  {
   if(IsIndicatorPeak(shift)==false)
      return;
   int currentPeak=shift;
   int lastPeak=GetIndicatorLastPeak(shift);
//----   
   if((lastPeak>=0 && lastPeak<Bars) && macd[currentPeak]<macd[lastPeak] && High[currentPeak]>High[lastPeak])
     {
      bearishDivergence[currentPeak]=macd[currentPeak]+
                                     arrowsDisplacement;

      if(drawPriceTrendLines==true)
         DrawPriceTrendLine(Time[currentPeak],Time[lastPeak],
                            High[currentPeak],
                            High[lastPeak],Red,STYLE_SOLID);

      if(drawIndicatorTrendLines==true)
         DrawIndicatorTrendLine(Time[currentPeak],Time[lastPeak],
                                macd[currentPeak],
                                macd[lastPeak],Red,STYLE_SOLID);

      if(displayAlert==true)
         DisplayAlert("Classical bearish divergence on: ",
                      currentPeak);
     }
   if((lastPeak>=0 && lastPeak<Bars) && macd[currentPeak]>macd[lastPeak] && High[currentPeak]<High[lastPeak])
     {
      bearishDivergence[currentPeak]=macd[currentPeak]+
                                     arrowsDisplacement;
      //----
      if(drawPriceTrendLines==true)
         DrawPriceTrendLine(Time[currentPeak],Time[lastPeak],
                            High[currentPeak],
                            High[lastPeak],Red,STYLE_DOT);
      //----
      if(drawIndicatorTrendLines==true)
         DrawIndicatorTrendLine(Time[currentPeak],Time[lastPeak],
                                macd[currentPeak],
                                macd[lastPeak],Red,STYLE_DOT);
      //----
      if(displayAlert==true)
         DisplayAlert("Reverse bearish divergence on: ",
                      currentPeak);
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool IsIndicatorPeak(int shift)
  {
   if(macd[shift]>=macd[shift+1] && macd[shift]>macd[shift+2] && 
      macd[shift]>macd[shift-1])
      return(true);
   else
      return(false);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool IsIndicatorTrough(int shift)
  {
   if(macd[shift]<=macd[shift+1] && macd[shift]<macd[shift+2] && 
      macd[shift]<macd[shift-1])
      return(true);
   else
      return(false);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int GetIndicatorLastPeak(int shift)
  {
   for(int i=shift+5;(i<Bars-3) && (i>1); i++)
     {
      if(signal[i] >= signal[i+1] && signal[i] >= signal[i+2] &&
         signal[i] >= signal[i-1] && signal[i] >= signal[i-2])
        {
         for(int j=i;(j<Bars-3) && (j>1); j++)
           {
            if(macd[j] >= macd[j+1] && macd[j] > macd[j+2] &&
               macd[j] >= macd[j-1] && macd[j] > macd[j-2])
               return(j);
           }
        }
     }
   return(-1);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int GetIndicatorLastTrough(int shift)
  {
   for(int i=shift+5;(i<Bars-3) && (i>1); i++)
     {
      if(signal[i] <= signal[i+1] && signal[i] <= signal[i+2] &&
         signal[i] <= signal[i-1] && signal[i] <= signal[i-2])
        {
         for(int j=i;(j<Bars-3) && (j>1); j++)
           {
            if(macd[j] <= macd[j+1] && macd[j] < macd[j+2] &&
               macd[j] <= macd[j-1] && macd[j] < macd[j-2])
               return(j);
           }
        }
     }
   return(-1);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void DisplayAlert(string message,int shift)
  {
   if(shift<=2 && Time[shift]!=lastAlertTime)
     {
      lastAlertTime=Time[shift];
      Alert(message,Symbol()," , ",Period()," minutes chart");
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void DrawPriceTrendLine(datetime x1,datetime x2,double y1,
                        double y2,color lineColor,double style)
  {
   string label="MACD_DivergenceLine_v1.0# "+DoubleToStr(x1,0);
   ObjectDelete(label);
   ObjectCreate(label,OBJ_TREND,0,x1,y1,x2,y2,0,0);
   ObjectSet(label,OBJPROP_RAY,0);
   ObjectSet(label,OBJPROP_COLOR,lineColor);
   ObjectSet(label,OBJPROP_STYLE,style);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void DrawIndicatorTrendLine(datetime x1,datetime x2,double y1,
                            double y2,color lineColor,double style)
  {
   int indicatorWindow=WindowFind(indicatorName);
   if(indicatorWindow<0)
      return;
   string label="MACD_DivergenceLine_v1.0$# "+DoubleToStr(x1,0);
   ObjectDelete(label);
   ObjectCreate(label,OBJ_TREND,indicatorWindow,x1,y1,x2,y2,
                0,0);
   ObjectSet(label,OBJPROP_RAY,0);
   ObjectSet(label,OBJPROP_COLOR,lineColor);
   ObjectSet(label,OBJPROP_STYLE,style);
  }
//+------------------------------------------------------------------+
