//+------------------------------------------------------------------+
//|                                        supertrend-alert.mq4        |
//|  Plots the SuperTrend line (an ATR-based stop-and-reverse trend    |
//|  line: support below price in an uptrend, resistance above price  |
//|  in a downtrend) and alerts on a flip.                             |
//|  Source: web-forex (educational, free to use and modify)          |
//+------------------------------------------------------------------+
#property copyright "web-forex"
#property strict
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_color1 clrLimeGreen
#property indicator_color2 clrRed
#property indicator_width1 2
#property indicator_width2 2

extern int    ATRPeriod   = 10;
extern double Multiplier  = 3.0;
extern bool   EnableAlert = true;
extern bool   EnablePush  = false;

double UpBuffer[];
double DownBuffer[];
double FinalUpperArr[];
double FinalLowerArr[];
double TrendArr[]; // 1 = up (line = lower band), -1 = down (line = upper band)

int lastTrend = 0;

int OnInit()
{
   SetIndexBuffer(0, UpBuffer);
   SetIndexStyle(0, DRAW_LINE);
   SetIndexEmptyValue(0, EMPTY_VALUE);
   SetIndexLabel(0, "SuperTrend Up");

   SetIndexBuffer(1, DownBuffer);
   SetIndexStyle(1, DRAW_LINE);
   SetIndexEmptyValue(1, EMPTY_VALUE);
   SetIndexLabel(1, "SuperTrend Down");

   IndicatorShortName("SuperTrend Alert (" + IntegerToString(ATRPeriod) + ", " + DoubleToString(Multiplier, 1) + ")");
   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 < ATRPeriod + 2)
      return(0);

   // The SuperTrend line is recursive (each bar's band depends on the
   // previous bar's band and trend state), so it's recalculated over a
   // fixed lookback on every tick rather than only the newest bars --
   // partial updates would drift from the true recursive value.
   int lookback = MathMin(rates_total - 1, 2000);
   int oldest = lookback;

   ArrayResize(FinalUpperArr, oldest + 1);
   ArrayResize(FinalLowerArr, oldest + 1);
   ArrayResize(TrendArr, oldest + 1);

   for (int i = oldest - ATRPeriod; i >= 0; i--)
   {
      double atr = iATR(NULL, 0, ATRPeriod, i);
      double mid = (High[i] + Low[i]) / 2.0;
      double basicUpper = mid + Multiplier * atr;
      double basicLower = mid - Multiplier * atr;

      double finalUpper, finalLower;
      if (i == oldest - ATRPeriod)
      {
         finalUpper = basicUpper;
         finalLower = basicLower;
      }
      else
      {
         double prevFinalUpper = FinalUpperArr[i + 1];
         double prevFinalLower = FinalLowerArr[i + 1];
         double prevClose      = Close[i + 1];

         finalUpper = (basicUpper < prevFinalUpper || prevClose > prevFinalUpper) ? basicUpper : prevFinalUpper;
         finalLower = (basicLower > prevFinalLower || prevClose < prevFinalLower) ? basicLower : prevFinalLower;
      }

      FinalUpperArr[i] = finalUpper;
      FinalLowerArr[i] = finalLower;

      double prevTrend = (i == oldest - ATRPeriod) ? 1 : TrendArr[i + 1];
      double trend;
      if (prevTrend == 1)
         trend = (Close[i] < finalLower) ? -1 : 1;
      else
         trend = (Close[i] > finalUpper) ? 1 : -1;

      TrendArr[i] = trend;

      if (trend == 1)
      {
         UpBuffer[i]   = finalLower;
         DownBuffer[i] = EMPTY_VALUE;
      }
      else
      {
         UpBuffer[i]   = EMPTY_VALUE;
         DownBuffer[i] = finalUpper;
      }
   }

   CheckFlipSignal();
   return(rates_total);
}

void CheckFlipSignal()
{
   if (!EnableAlert && !EnablePush)
      return;
   if (ArraySize(TrendArr) < 3)
      return;

   double trendLast = TrendArr[1];
   double trendPrev = TrendArr[2];

   if (trendLast != trendPrev)
   {
      int t = (int)trendLast;
      if (t != lastTrend)
      {
         string msg = (t == 1)
            ? Symbol() + " " + EnumToString((ENUM_TIMEFRAMES)Period()) + ": SuperTrend flipped up (bullish)"
            : Symbol() + " " + EnumToString((ENUM_TIMEFRAMES)Period()) + ": SuperTrend flipped down (bearish)";

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

         lastTrend = t;
      }
   }
}
