//+------------------------------------------------------------------+
//|                                            vortex-alert.mq5       |
//|  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 indicator_separate_window
#property indicator_buffers 2
#property indicator_plots   2
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrDodgerBlue
#property indicator_label1  "VI+"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrOrange
#property indicator_label2  "VI-"

input int  VortexPeriod = 14;
input bool EnableAlert  = true;
input 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, INDICATOR_DATA);
   SetIndexBuffer(1, VIMinusBuffer, INDICATOR_DATA);
   ArraySetAsSeries(VIPlusBuffer, true);
   ArraySetAsSeries(VIMinusBuffer, true);

   IndicatorSetString(INDICATOR_SHORTNAME, "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[])
{
   if (rates_total < VortexPeriod + 2)
      return(0);

   double h[], l[], c[];
   ArraySetAsSeries(h, true);
   ArraySetAsSeries(l, true);
   ArraySetAsSeries(c, true);
   if (CopyHigh(_Symbol, _Period, 0, rates_total, h) < rates_total) return(0);
   if (CopyLow(_Symbol, _Period, 0, rates_total, l) < rates_total) return(0);
   if (CopyClose(_Symbol, _Period, 0, rates_total, c) < rates_total) return(0);

   int limit = rates_total - VortexPeriod - 2;

   for (int i = limit; i >= 0; i--)
      CalculateVortex(i, h, l, c);

   CheckCrossSignal();
   return(rates_total);
}

void CalculateVortex(int i, const double &h[], const double &l[], const double &c[])
{
   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(h[idx] - l[idxPrev]);
      double vmMinus = MathAbs(l[idx] - h[idxPrev]);
      double tr      = MathMax(h[idx] - l[idx],
                        MathMax(MathAbs(h[idx] - c[idxPrev]), MathAbs(l[idx] - c[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;
}
