//+------------------------------------------------------------------+
//|                                            vortex-alert.mq4       |
//|  Plots the Vortex Indicator (VI+ and VI-, derived from directional|
//|  movement and true range) and alerts on a VI+/VI- crossover.      |
//|  Source: web-forex (educational, free to use and modify)          |
//+------------------------------------------------------------------+
#property copyright "web-forex"
#property strict
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_color1 clrDodgerBlue
#property indicator_color2 clrOrange

extern int    VortexPeriod = 14;
extern bool   EnableAlert  = true;
extern bool   EnablePush   = false;

double VIPlusBuffer[];
double VIMinusBuffer[];

int lastCross = 0; // 0 = none, 1 = VI+ above VI-, -1 = VI- above VI+

int OnInit()
{
   SetIndexBuffer(0, VIPlusBuffer);
   SetIndexStyle(0, DRAW_LINE);
   SetIndexLabel(0, "VI+");

   SetIndexBuffer(1, VIMinusBuffer);
   SetIndexStyle(1, DRAW_LINE);
   SetIndexLabel(1, "VI-");

   IndicatorShortName("Vortex Indicator Alert (" + IntegerToString(VortexPeriod) + ")");
   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 - VortexPeriod - 2)
      start = rates_total - VortexPeriod - 2;
   if (start < 0)
      return(rates_total);

   for (int i = start; i >= 0; i--)
      CalculateVortex(i);

   CheckCrossSignal();
   return(rates_total);
}

void CalculateVortex(int i)
{
   double sumVMPlus = 0, sumVMMinus = 0, sumTR = 0;

   for (int j = 0; j < VortexPeriod; j++)
   {
      int idx     = i + j;
      int idxPrev = idx + 1;

      double vmPlus  = MathAbs(High[idx] - Low[idxPrev]);
      double vmMinus = MathAbs(Low[idx] - High[idxPrev]);
      double tr      = MathMax(High[idx] - Low[idx],
                        MathMax(MathAbs(High[idx] - Close[idxPrev]), MathAbs(Low[idx] - Close[idxPrev])));

      sumVMPlus  += vmPlus;
      sumVMMinus += vmMinus;
      sumTR      += tr;
   }

   VIPlusBuffer[i]  = (sumTR > 0) ? sumVMPlus / sumTR : 0;
   VIMinusBuffer[i] = (sumTR > 0) ? sumVMMinus / sumTR : 0;
}

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

   double viPlusLast  = VIPlusBuffer[1];
   double viMinusLast = VIMinusBuffer[1];
   double viPlusPrev  = VIPlusBuffer[2];
   double viMinusPrev = VIMinusBuffer[2];

   bool bullishCross = (viPlusPrev <= viMinusPrev && viPlusLast > viMinusLast);
   bool bearishCross = (viPlusPrev >= viMinusPrev && viPlusLast < viMinusLast);

   int cross = 0;
   if (bullishCross)
      cross = 1;
   else if (bearishCross)
      cross = -1;

   if (cross != 0 && cross != lastCross)
   {
      string msg = (cross == 1)
         ? Symbol() + " " + EnumToString((ENUM_TIMEFRAMES)Period()) + ": Vortex VI+ crossed above VI-"
         : Symbol() + " " + EnumToString((ENUM_TIMEFRAMES)Period()) + ": Vortex VI- crossed above VI+";

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

   if (cross != 0)
      lastCross = cross;
}
