//+------------------------------------------------------------------+
//| 58_QQE_VT_Trend_Overlay_v1_01.mq5                               |
//| Displays a smoothed RSI and confirmed 50-level crosses.          |
//+------------------------------------------------------------------+
#property strict
#property version   "1.01"
#property indicator_separate_window
#property indicator_minimum 0.0
#property indicator_maximum 100.0
#property indicator_level1 50.0
#property indicator_levelcolor clrDimGray
#property indicator_levelstyle STYLE_DOT
#property indicator_plots 3
#property indicator_buffers 3
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrDeepSkyBlue
#property indicator_width1 2
#property indicator_label1 "Smoothed RSI"
#property indicator_type2 DRAW_ARROW
#property indicator_color2 clrLime
#property indicator_width2 2
#property indicator_label2 "50 cross up"
#property indicator_type3 DRAW_ARROW
#property indicator_color3 clrTomato
#property indicator_width3 2
#property indicator_label3 "50 cross down"

input int InpRsiPeriod    = 14;
input int InpSmoothPeriod = 5;

double SmoothedRsi[];
double CrossUp[];
double CrossDown[];
int    g_rsi_handle = INVALID_HANDLE;

int OnInit()
{
   if(InpRsiPeriod < 2 || InpSmoothPeriod < 1)
      return INIT_PARAMETERS_INCORRECT;

   SetIndexBuffer(0, SmoothedRsi, INDICATOR_DATA);
   SetIndexBuffer(1, CrossUp, INDICATOR_DATA);
   SetIndexBuffer(2, CrossDown, INDICATOR_DATA);
   ArraySetAsSeries(SmoothedRsi, true);
   ArraySetAsSeries(CrossUp, true);
   ArraySetAsSeries(CrossDown, true);

   PlotIndexSetInteger(1, PLOT_ARROW, 233);
   PlotIndexSetInteger(2, PLOT_ARROW, 234);
   PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetDouble(2, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   const int draw_begin = InpRsiPeriod + InpSmoothPeriod - 2;
   PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, draw_begin);
   PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, draw_begin + 1);
   PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, draw_begin + 1);

   ResetLastError();
   g_rsi_handle = iRSI(_Symbol, _Period, InpRsiPeriod, PRICE_CLOSE);
   if(g_rsi_handle == INVALID_HANDLE)
   {
      PrintFormat("QQE-VT: iRSI failed error=%d", GetLastError());
      return INIT_FAILED;
   }

   IndicatorSetString(INDICATOR_SHORTNAME, "QQE-VT smoothed RSI (14,5)");
   IndicatorSetInteger(INDICATOR_DIGITS, 2);
   return INIT_SUCCEEDED;
}

void OnDeinit(const int reason)
{
   if(g_rsi_handle != INVALID_HANDLE)
      IndicatorRelease(g_rsi_handle);
}

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[])
{
   const int minimum_bars = InpRsiPeriod + InpSmoothPeriod + 1;
   if(rates_total < minimum_bars || BarsCalculated(g_rsi_handle) < rates_total)
      return 0;

   double raw_rsi[];
   ArraySetAsSeries(raw_rsi, true);
   ResetLastError();
   const int copied = CopyBuffer(g_rsi_handle, 0, 0, rates_total, raw_rsi);
   if(copied != rates_total)
   {
      PrintFormat("QQE-VT: CopyBuffer requested=%d copied=%d error=%d",
                  rates_total, copied, GetLastError());
      return 0;
   }

   if(prev_calculated == 0)
   {
      ArrayInitialize(SmoothedRsi, EMPTY_VALUE);
      ArrayInitialize(CrossUp, EMPTY_VALUE);
      ArrayInitialize(CrossDown, EMPTY_VALUE);
   }

   const int oldest_valid = rates_total - InpSmoothPeriod;
   const int limit = (prev_calculated == 0)
                     ? oldest_valid
                     : MathMin(oldest_valid, rates_total - prev_calculated + 1);

   for(int i = limit; i >= 0; --i)
   {
      CrossUp[i] = EMPTY_VALUE;
      CrossDown[i] = EMPTY_VALUE;

      double sum = 0.0;
      bool valid = true;
      for(int j = 0; j < InpSmoothPeriod; ++j)
      {
         const double value = raw_rsi[i + j];
         if(value == EMPTY_VALUE || !MathIsValidNumber(value))
         {
            valid = false;
            break;
         }
         sum += value;
      }

      if(!valid)
      {
         SmoothedRsi[i] = EMPTY_VALUE;
         continue;
      }

      SmoothedRsi[i] = sum / InpSmoothPeriod;
      if(i + 1 > oldest_valid || SmoothedRsi[i + 1] == EMPTY_VALUE)
         continue;

      if(SmoothedRsi[i] > 50.0 && SmoothedRsi[i + 1] <= 50.0)
         CrossUp[i] = 50.0;
      else if(SmoothedRsi[i] < 50.0 && SmoothedRsi[i + 1] >= 50.0)
         CrossDown[i] = 50.0;
   }

   return rates_total;
}
//+------------------------------------------------------------------+
