//+------------------------------------------------------------------+
//|                                                adx-di-alert.mq4   |
//|  Plots ADX, +DI, and -DI and alerts on directional crossovers     |
//|  when ADX confirms a real trend.                                   |
//|  Source: web-forex (educational, free to use and modify)          |
//+------------------------------------------------------------------+
#property copyright "web-forex"
#property strict
#property indicator_separate_window
#property indicator_buffers 3
#property indicator_color1 clrDodgerBlue
#property indicator_color2 clrLimeGreen
#property indicator_color3 clrOrangeRed
#property indicator_minimum 0
#property indicator_maximum 100
#property indicator_level1 25

extern int    ADXPeriod    = 14;
extern double TrendLevel   = 25.0;
extern bool   EnableAlert  = true;
extern bool   EnablePush   = false;

double AdxBuffer[];
double PlusDiBuffer[];
double MinusDiBuffer[];

int lastSignal = 0; // 0 = none, 1 = +DI above -DI, -1 = -DI above +DI

int OnInit()
{
   SetIndexBuffer(0, AdxBuffer);
   SetIndexStyle(0, DRAW_LINE);
   SetIndexLabel(0, "ADX");

   SetIndexBuffer(1, PlusDiBuffer);
   SetIndexStyle(1, DRAW_LINE);
   SetIndexLabel(1, "+DI");

   SetIndexBuffer(2, MinusDiBuffer);
   SetIndexStyle(2, DRAW_LINE);
   SetIndexLabel(2, "-DI");

   IndicatorShortName("ADX/DI Alert (" + IntegerToString(ADXPeriod) + ")");
   return(INIT_SUCCEEDED);
}

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
   int start = rates_total - prev_calculated;
   if (start > rates_total - ADXPeriod - 1)
      start = rates_total - ADXPeriod - 1;
   if (start < 0)
      return(rates_total);

   for (int i = start; i >= 0; i--)
   {
      AdxBuffer[i]      = iADX(NULL, 0, ADXPeriod, PRICE_CLOSE, MODE_MAIN, i);
      PlusDiBuffer[i]   = iADX(NULL, 0, ADXPeriod, PRICE_CLOSE, MODE_PLUSDI, i);
      MinusDiBuffer[i]  = iADX(NULL, 0, ADXPeriod, PRICE_CLOSE, MODE_MINUSDI, i);
   }

   CheckCrossSignal();
   return(rates_total);
}

void CheckCrossSignal()
{
   if (!EnableAlert && !EnablePush)
      return;

   double plusPrev  = iADX(NULL, 0, ADXPeriod, PRICE_CLOSE, MODE_PLUSDI, 2);
   double minusPrev = iADX(NULL, 0, ADXPeriod, PRICE_CLOSE, MODE_MINUSDI, 2);
   double plusLast  = iADX(NULL, 0, ADXPeriod, PRICE_CLOSE, MODE_PLUSDI, 1);
   double minusLast = iADX(NULL, 0, ADXPeriod, PRICE_CLOSE, MODE_MINUSDI, 1);
   double adxLast   = iADX(NULL, 0, ADXPeriod, PRICE_CLOSE, MODE_MAIN, 1);

   if (adxLast < TrendLevel)
      return; // no confirmed trend yet, ignore DI crosses

   int signal = 0;
   if (plusPrev <= minusPrev && plusLast > minusLast)
      signal = 1;  // +DI crossed above -DI
   else if (plusPrev >= minusPrev && plusLast < minusLast)
      signal = -1; // -DI crossed above +DI

   if (signal != 0 && signal != lastSignal)
   {
      string msg = (signal == 1)
         ? Symbol() + " " + EnumToString((ENUM_TIMEFRAMES)Period()) + ": +DI crossed above -DI (ADX " + DoubleToString(adxLast, 1) + ")"
         : Symbol() + " " + EnumToString((ENUM_TIMEFRAMES)Period()) + ": -DI crossed above +DI (ADX " + DoubleToString(adxLast, 1) + ")";

      if (EnableAlert)
         Alert(msg);
      if (EnablePush)
         SendNotification(msg);

      lastSignal = signal;
   }
}
