//+------------------------------------------------------------------+
//|                                       auto-fibonacci-alert.mq4    |
//|  Finds the swing high/low over a lookback window, draws           |
//|  Fibonacci retracement levels automatically, and alerts when      |
//|  price touches the 50% or 61.8% level.                            |
//|  Source: web-forex (educational, free to use and modify)          |
//+------------------------------------------------------------------+
#property copyright "web-forex"
#property strict
#property indicator_chart_window

extern int    LookbackBars = 100;
extern bool   EnableAlert  = true;
extern bool   EnablePush   = false;

string levelNames[7] = {"Fibo_0", "Fibo_236", "Fibo_382", "Fibo_500", "Fibo_618", "Fibo_786", "Fibo_1000"};
double levelRatios[7] = {0.0, 0.236, 0.382, 0.5, 0.618, 0.786, 1.0};
color  levelColors[7] = {clrGray, clrGray, clrGray, clrGray, clrOrange, clrGray, clrGray};

int lastTouch = 0; // 0 = none, 1 = touched 50%, 2 = touched 61.8%

int OnInit()
{
   IndicatorShortName("Auto Fibonacci Alert (" + IntegerToString(LookbackBars) + ")");
   return(INIT_SUCCEEDED);
}

void OnDeinit(const int reason)
{
   for (int i = 0; i < 7; i++)
      ObjectDelete(levelNames[i]);
}

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 highestIdx = iHighest(NULL, 0, MODE_HIGH, LookbackBars, 0);
   int lowestIdx  = iLowest(NULL, 0, MODE_LOW, LookbackBars, 0);

   double swingHigh = High[highestIdx];
   double swingLow  = Low[lowestIdx];
   bool   isUptrend = (lowestIdx > highestIdx); // swing low happened further back than the high

   double levelPrice[7];
   for (int i = 0; i < 7; i++)
   {
      if (isUptrend)
         levelPrice[i] = swingHigh - levelRatios[i] * (swingHigh - swingLow);
      else
         levelPrice[i] = swingLow + levelRatios[i] * (swingHigh - swingLow);

      DrawLevel(levelNames[i], levelPrice[i], levelColors[i]);
   }

   CheckTouchSignal(levelPrice[3], levelPrice[4]);
   return(rates_total);
}

void DrawLevel(string name, double price, color clr)
{
   if (ObjectFind(name) < 0)
   {
      ObjectCreate(name, OBJ_HLINE, 0, 0, price);
      ObjectSet(name, OBJPROP_COLOR, clr);
      ObjectSet(name, OBJPROP_STYLE, STYLE_DASH);
   }
   else
   {
      ObjectSet(name, OBJPROP_PRICE1, price);
   }
}

void CheckTouchSignal(double level50, double level618)
{
   if (!EnableAlert && !EnablePush)
      return;

   double closeLast = Close[1];
   double tolerance  = 5 * Point;

   int touch = 0;
   if (MathAbs(closeLast - level618) <= tolerance)
      touch = 2;
   else if (MathAbs(closeLast - level50) <= tolerance)
      touch = 1;

   if (touch != 0 && touch != lastTouch)
   {
      string msg = (touch == 2)
         ? Symbol() + " " + EnumToString((ENUM_TIMEFRAMES)Period()) + ": price touched the 61.8% Fibonacci level"
         : Symbol() + " " + EnumToString((ENUM_TIMEFRAMES)Period()) + ": price touched the 50% Fibonacci level";

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

   lastTouch = touch;
}
