//+------------------------------------------------------------------+
//|                                        rsi digital Kahler.mq5    |
//|                                  Copyright "mladen", MetaQuotes |
//|                                      http://www.forex-station.com |
//+------------------------------------------------------------------+
#property copyright "mladen"
#property link      "www.forex-station.com"
#property version   "1.00"

#property indicator_separate_window
#property indicator_buffers 5
#property indicator_plots   3

//--- Plot Buffer 0 (Línea principal)
#property indicator_label1  "RSI Digital"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrLimeGreen
#property indicator_style1  STYLE_SOLID
#property indicator_width1  3

//--- Plot Buffer 1 (Línea B)
#property indicator_label2  "RSI Digital Down A"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrOrange
#property indicator_style2  STYLE_SOLID
#property indicator_width2  3

//--- Plot Buffer 3 (Línea C)
#property indicator_label3  "RSI Digital Down B"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrOrange
#property indicator_style3  STYLE_SOLID
#property indicator_width3  3

//--- Inputs
input int                InpPeriod     = 14;          // Calculating period
input ENUM_APPLIED_PRICE InpPrice      = PRICE_CLOSE; // Price
input int                InpSperiod    = 14;          // Smoothing period
input ENUM_MA_METHOD     InpSmethod    = MODE_SMA;    // Smoothing method
input int                InpLinesWidth = 3;           // Lines width
input double             InpFastr      = 8.0;         // Fast ratio
input double             InpSlowr      = 22.0;        // Slow ratio

//--- Indicator Buffers
double buffer[];
double bufferda[];
double bufferdb[];
double trend[];
double work[];
double workEma[];

//--- Handles para indicadores internos
int handleRsi;
int handleMaOnRsi;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
   // Asignación de búferes
   SetIndexBuffer(0, buffer, INDICATOR_DATA);
   SetIndexBuffer(1, bufferda, INDICATOR_DATA);
   SetIndexBuffer(2, bufferdb, INDICATOR_DATA);
   SetIndexBuffer(3, trend, INDICATOR_CALCULATIONS);
   SetIndexBuffer(4, work, INDICATOR_CALCULATIONS);

   // Invertir orden de indexación (Series como en MT4: 0 = barra actual)
   ArraySetAsSeries(buffer, true);
   ArraySetAsSeries(bufferda, true);
   ArraySetAsSeries(bufferdb, true);
   ArraySetAsSeries(trend, true);
   ArraySetAsSeries(work, true);
   ArraySetAsSeries(workEma, true);

   // Estilos dinámicos
   PlotIndexSetInteger(0, PLOT_LINE_WIDTH, InpLinesWidth);
   PlotIndexSetInteger(1, PLOT_LINE_WIDTH, InpLinesWidth);
   PlotIndexSetInteger(2, PLOT_LINE_WIDTH, InpLinesWidth);

   // Valores vacíos para renderizado correcto
   PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetDouble(2, PLOT_EMPTY_VALUE, EMPTY_VALUE);

   // Obtener Handle de RSI
   handleRsi = iRSI(_Symbol, _Period, InpPeriod, InpPrice);
   if(handleRsi == INVALID_HANDLE)
   {
      Print("Error creando handle de RSI");
      return(INIT_FAILED);
   }

   // Obtener Handle de MA sobre el RSI
   handleMaOnRsi = iMA(_Symbol, _Period, InpSperiod, 0, InpSmethod, handleRsi);
   if(handleMaOnRsi == INVALID_HANDLE)
   {
      Print("Error creando handle de MA sobre RSI");
      return(INIT_FAILED);
   }

   IndicatorSetString(INDICATOR_SHORTNAME, "rsi digital Kahler (" + (string)InpPeriod + "," + (string)InpSperiod + ")");

   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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 < InpPeriod + InpSperiod) return(0);

   // Redimensionar arreglo dinámico del EMA
   if(ArraySize(workEma) != rates_total)
      ArrayResize(workEma, rates_total);

   int limit;
   if(prev_calculated == 0)
   {
      limit = rates_total - 1;
      ArrayInitialize(buffer, EMPTY_VALUE);
      ArrayInitialize(bufferda, EMPTY_VALUE);
      ArrayInitialize(bufferdb, EMPTY_VALUE);
      ArrayInitialize(trend, 0);
      ArrayInitialize(workEma, 0);
   }
   else
   {
      limit = rates_total - prev_calculated;
   }

   // Copiar valores de indicadores nativos a los arrays internos
   if(CopyBuffer(handleRsi, 0, 0, limit + 1, work) < 0) return(0);
   
   // Búfer auxiliar para los valores suavizados del RSI
   double maWork[];
   ArraySetAsSeries(maWork, true);
   if(CopyBuffer(handleMaOnRsi, 0, 0, limit + 1, maWork) < 0) return(0);

   if(limit < rates_total - 1 && trend[limit] == -1) 
      CleanPoint(limit, bufferda, bufferdb);

   double denom = InpFastr + InpSlowr;

   for(int i = limit; i >= 0; i--)
   {
      double fast_k = work[i];
      double slow_k = maWork[i];
      double temp   = 0;

      if(denom != 0.0)
      {
         double calcVal = (InpSlowr * slow_k + InpFastr * fast_k) / denom;
         if(calcVal > 50.0) temp =  1.0;
         if(calcVal < 50.0) temp = -1.0;
      }

      buffer[i]   = iEmaCustom(temp, InpPeriod, i, rates_total);
      bufferda[i] = EMPTY_VALUE;
      bufferdb[i] = EMPTY_VALUE;

      if(i < rates_total - 1)
         trend[i] = trend[i + 1];

      if(i < rates_total - 1)
      {
         if(buffer[i] > buffer[i + 1]) trend[i] =  1;
         if(buffer[i] < buffer[i + 1]) trend[i] = -1;
      }

      if(trend[i] == -1) 
         PlotPoint(i, bufferda, bufferdb, buffer, rates_total);
   }

   return(rates_total);
}

//+------------------------------------------------------------------+
//| EMA interna adaptada a MT5                                       |
//+------------------------------------------------------------------+
double iEmaCustom(double tprice, double eperiod, int r, int rates_total)
{
   int idx = rates_total - r - 1; // Conversión de índice invertido a normal
   
   if(idx <= 0)
   {
      workEma[idx] = tprice;
      return(workEma[idx]);
   }

   double alpha = 2.0 / (1.0 + eperiod);
   workEma[idx] = workEma[idx - 1] + alpha * (tprice - workEma[idx - 1]);
   return(workEma[idx]);
}

//+------------------------------------------------------------------+
//| Limpieza de puntos                                              |
//+------------------------------------------------------------------+
void CleanPoint(int i, double &first[], double &second[])
{
   if((second[i] != EMPTY_VALUE) && (second[i + 1] != EMPTY_VALUE))
      second[i + 1] = EMPTY_VALUE;
   else if((first[i] != EMPTY_VALUE) && (first[i + 1] != EMPTY_VALUE) && (first[i + 2] == EMPTY_VALUE))
      first[i + 1] = EMPTY_VALUE;
}

//+------------------------------------------------------------------+
//| Ploteo de puntos                                                 |
//+------------------------------------------------------------------+
void PlotPoint(int i, double &first[], double &second[], double &from[], int rates_total)
{
   if(i >= rates_total - 2) return;

   if(first[i + 1] == EMPTY_VALUE)
   {
      if(first[i + 2] == EMPTY_VALUE)
      {
         first[i]     = from[i];
         first[i + 1] = from[i + 1];
         second[i]    = EMPTY_VALUE;
      }
      else
      {
         second[i]     = from[i];
         second[i + 1] = from[i + 1];
         first[i]      = EMPTY_VALUE;
      }
   }
   else
   {
      first[i]  = from[i];
      second[i] = EMPTY_VALUE;
   }
}