//+------------------------------------------------------------------+
//|                                                 rsi-alert.mq4     |
//|  Plots RSI in a separate window and alerts on overbought/oversold |
//|  Source: web-forex (educational, free to use and modify)          |
//+------------------------------------------------------------------+
#property copyright "web-forex"
#property strict
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_color1 clrDodgerBlue
#property indicator_minimum 0
#property indicator_maximum 100
#property indicator_level1 30
#property indicator_level2 50
#property indicator_level3 70

extern int    RSIPeriod    = 14;
extern int    AppliedPrice = PRICE_CLOSE;
extern double Overbought   = 70.0;
extern double Oversold     = 30.0;
extern bool   EnableAlert  = true;
extern bool   EnablePush   = false;

double RSIBuffer[];

int lastZone = 0; // 0 = neutral, 1 = overbought, -1 = oversold

int OnInit()
{
   SetIndexBuffer(0, RSIBuffer);
   SetIndexStyle(0, DRAW_LINE);
   SetIndexLabel(0, "RSI (" + IntegerToString(RSIPeriod) + ")");

   IndicatorShortName("RSI Alert (" + IntegerToString(RSIPeriod) + ")");
   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 - RSIPeriod - 1)
      start = rates_total - RSIPeriod - 1;
   if (start < 0)
      return(rates_total);

   for (int i = start; i >= 0; i--)
      RSIBuffer[i] = iRSI(NULL, 0, RSIPeriod, AppliedPrice, i);

   CheckZoneSignal();
   return(rates_total);
}

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

   double rsiLast = iRSI(NULL, 0, RSIPeriod, AppliedPrice, 1);

   int zone = 0;
   if (rsiLast >= Overbought)
      zone = 1;
   else if (rsiLast <= Oversold)
      zone = -1;

   if (zone != 0 && zone != lastZone)
   {
      string msg = (zone == 1)
         ? Symbol() + " " + EnumToString((ENUM_TIMEFRAMES)Period()) + ": RSI Overbought (" + DoubleToString(rsiLast, 2) + ")"
         : Symbol() + " " + EnumToString((ENUM_TIMEFRAMES)Period()) + ": RSI Oversold (" + DoubleToString(rsiLast, 2) + ")";

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

   if (zone != 0)
      lastZone = zone;
   else if (rsiLast > Oversold + 5 && rsiLast < Overbought - 5)
      lastZone = 0;
}
