//+------------------------------------------------------------------+
//|                                              trix-alert.mq5       |
//|  Plots TRIX (the percentage rate of change of a triple-smoothed   |
//|  EMA of price) with a signal line, and alerts on a TRIX/Signal    |
//|  crossover. No built-in TRIX function in MQL5 — calculated        |
//|  directly from Close.                                             |
//|  Source: web-forex (educational, free to use and modify)          |
//+------------------------------------------------------------------+
#property copyright "web-forex"
#property indicator_separate_window
#property indicator_buffers 5
#property indicator_plots   2
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrDodgerBlue
#property indicator_label1  "TRIX"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrOrange
#property indicator_label2  "Signal"
#property indicator_level1  0

input int  TrixPeriod   = 14;
input int  SignalPeriod = 9;
input bool EnableAlert  = true;
input bool EnablePush   = false;

double TrixBuffer[];
double SignalBuffer[];
double Ema1Buffer[];
double Ema2Buffer[];
double Ema3Buffer[];

int lastCross = 0; // 0 = none, 1 = TRIX above Signal, -1 = TRIX below Signal

int OnInit()
{
   SetIndexBuffer(0, TrixBuffer, INDICATOR_DATA);
   SetIndexBuffer(1, SignalBuffer, INDICATOR_DATA);
   SetIndexBuffer(2, Ema1Buffer, INDICATOR_CALCULATIONS);
   SetIndexBuffer(3, Ema2Buffer, INDICATOR_CALCULATIONS);
   SetIndexBuffer(4, Ema3Buffer, INDICATOR_CALCULATIONS);
   ArraySetAsSeries(TrixBuffer, true);
   ArraySetAsSeries(SignalBuffer, true);
   ArraySetAsSeries(Ema1Buffer, true);
   ArraySetAsSeries(Ema2Buffer, true);
   ArraySetAsSeries(Ema3Buffer, true);

   IndicatorSetString(INDICATOR_SHORTNAME, "TRIX Alert (" + IntegerToString(TrixPeriod) + "," + IntegerToString(SignalPeriod) + ")");
   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 < 2)
      return(0);

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

   int start = rates_total - prev_calculated;
   if (start >= rates_total)
      start = rates_total - 1;
   if (start < 0)
      start = 0;

   double alpha = 2.0 / (TrixPeriod + 1.0);

   for (int i = start; i >= 0; i--)
   {
      if (i == rates_total - 1)
      {
         Ema1Buffer[i] = c[i];
         Ema2Buffer[i] = c[i];
         Ema3Buffer[i] = c[i];
         TrixBuffer[i] = 0;
      }
      else
      {
         Ema1Buffer[i] = alpha * c[i] + (1 - alpha) * Ema1Buffer[i + 1];
         Ema2Buffer[i] = alpha * Ema1Buffer[i] + (1 - alpha) * Ema2Buffer[i + 1];
         Ema3Buffer[i] = alpha * Ema2Buffer[i] + (1 - alpha) * Ema3Buffer[i + 1];
         TrixBuffer[i] = (Ema3Buffer[i + 1] != 0)
            ? (Ema3Buffer[i] - Ema3Buffer[i + 1]) / Ema3Buffer[i + 1] * 100.0
            : 0;
      }
   }

   for (int i = start; i >= 0; i--)
   {
      if (i > rates_total - SignalPeriod)
      {
         SignalBuffer[i] = 0;
         continue;
      }
      double sum = 0;
      for (int j = 0; j < SignalPeriod; j++)
         sum += TrixBuffer[i + j];
      SignalBuffer[i] = sum / SignalPeriod;
   }

   CheckCrossSignal();
   return(rates_total);
}

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

   double trixLast   = TrixBuffer[1];
   double signalLast = SignalBuffer[1];
   double trixPrev   = TrixBuffer[2];
   double signalPrev = SignalBuffer[2];

   bool bullishCross = (trixPrev <= signalPrev && trixLast > signalLast);
   bool bearishCross = (trixPrev >= signalPrev && trixLast < signalLast);

   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) + ": TRIX crossed above its Signal line"
         : _Symbol + " " + EnumToString((ENUM_TIMEFRAMES)_Period) + ": TRIX crossed below its Signal line";

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

   if (cross != 0)
      lastCross = cross;
}
