//+------------------------------------------------------------------+
//|                                            stochastic-alert.mq4   |
//|  Plots %K and %D and alerts on crossovers inside the overbought   |
//|  or oversold zone.                                                 |
//|  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 clrOrangeRed
#property indicator_minimum 0
#property indicator_maximum 100
#property indicator_level1 20
#property indicator_level2 50
#property indicator_level3 80

extern int    KPeriod      = 5;
extern int    DPeriod      = 3;
extern int    Slowing      = 3;
extern double Overbought   = 80.0;
extern double Oversold     = 20.0;
extern bool   EnableAlert  = true;
extern bool   EnablePush   = false;

double KBuffer[];
double DBuffer[];

int lastSignal = 0; // 0 = none, 1 = bullish cross, -1 = bearish cross

int OnInit()
{
   SetIndexBuffer(0, KBuffer);
   SetIndexStyle(0, DRAW_LINE);
   SetIndexLabel(0, "%K");

   SetIndexBuffer(1, DBuffer);
   SetIndexStyle(1, DRAW_LINE);
   SetIndexLabel(1, "%D");

   IndicatorShortName("Stochastic Alert (" + IntegerToString(KPeriod) + "," + IntegerToString(DPeriod) + "," + IntegerToString(Slowing) + ")");
   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 - KPeriod - DPeriod - Slowing - 1)
      start = rates_total - KPeriod - DPeriod - Slowing - 1;
   if (start < 0)
      return(rates_total);

   for (int i = start; i >= 0; i--)
   {
      KBuffer[i] = iStochastic(NULL, 0, KPeriod, DPeriod, Slowing, MODE_SMA, 0, MODE_MAIN, i);
      DBuffer[i] = iStochastic(NULL, 0, KPeriod, DPeriod, Slowing, MODE_SMA, 0, MODE_SIGNAL, i);
   }

   CheckCrossSignal();
   return(rates_total);
}

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

   double kPrev = iStochastic(NULL, 0, KPeriod, DPeriod, Slowing, MODE_SMA, 0, MODE_MAIN, 2);
   double dPrev = iStochastic(NULL, 0, KPeriod, DPeriod, Slowing, MODE_SMA, 0, MODE_SIGNAL, 2);
   double kLast = iStochastic(NULL, 0, KPeriod, DPeriod, Slowing, MODE_SMA, 0, MODE_MAIN, 1);
   double dLast = iStochastic(NULL, 0, KPeriod, DPeriod, Slowing, MODE_SMA, 0, MODE_SIGNAL, 1);

   int signal = 0;
   if (kPrev <= dPrev && kLast > dLast && kLast < Oversold && dLast < Oversold)
      signal = 1;  // bullish cross in oversold zone
   else if (kPrev >= dPrev && kLast < dLast && kLast > Overbought && dLast > Overbought)
      signal = -1; // bearish cross in overbought zone

   if (signal != 0 && signal != lastSignal)
   {
      string msg = (signal == 1)
         ? Symbol() + " " + EnumToString((ENUM_TIMEFRAMES)Period()) + ": Stochastic bullish cross in oversold zone"
         : Symbol() + " " + EnumToString((ENUM_TIMEFRAMES)Period()) + ": Stochastic bearish cross in overbought zone";

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

      lastSignal = signal;
   }
   else if (kLast > Oversold + 5 && kLast < Overbought - 5)
      lastSignal = 0;
}
