//+------------------------------------------------------------------+
//|                                                ML_Supertrend.mq5 |
//|                             Traducido de Pine Script v5 a MQL5   |
//+------------------------------------------------------------------+
#property copyright "DM"
#property indicator_chart_window

//--- Definimos 3 plots: Linea Up, Linea Down y el Ribbon (Relleno)
#property indicator_buffers 4
#property indicator_plots   3

//--- Plot 1: Supertrend Alcista (Verde)
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrDeepSkyBlue
#property indicator_width1  2

//--- Plot 2: Supertrend Bajista (Rojo)
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrViolet
#property indicator_width2  2

//--- Plot 3: Ribbon / Fill (Sombra)
#property indicator_type3   DRAW_FILLING
#property indicator_color3  clrDarkGreen, clrDarkRed  // Color arriba / Color abajo

//--- Inputs
input group "=== ML Supertrend Parameters ==="
input int      InpATRPeriod = 25;       // ATR Length
input double   InpFactor    = 2.2;      // Factor
input int      InpForecast  = 3;        // Forecast Period

//--- Buffers
double BufferUp[];
double BufferDown[];
double BufferFill1[]; // Buffer 1 para el Relleno (Precio Medio)
double BufferFill2[]; // Buffer 2 para el Relleno (Linea Supertrend)

//--- Global Variables
double K_weights[];

//+------------------------------------------------------------------+
//| Function: Kernel RBF                                             |
//+------------------------------------------------------------------+
double RBF(double x1, double x2, double l)
{
   double diff = x1 - x2;
   return MathExp(-(diff * diff) / (2.0 * l * l));
}

//+------------------------------------------------------------------+
//| Precalculo de pesos de Regresion Kernel                          |
//+------------------------------------------------------------------+
void InitKernelWeights()
{
   ArrayResize(K_weights, InpATRPeriod);
   double sum = 0.0;
   double l = (double)InpATRPeriod;
   
   for(int i = 0; i < InpATRPeriod; i++)
   {
      double dist = (double)(InpATRPeriod - 1 - i + InpForecast);
      K_weights[i] = RBF(dist, 0, l);
      sum += K_weights[i];
   }
   
   if(sum > 0.0)
   {
      for(int i = 0; i < InpATRPeriod; i++)
         K_weights[i] /= sum;
   }
}

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
   // Buffers para las lineas
   SetIndexBuffer(0, BufferUp, INDICATOR_DATA);
   SetIndexBuffer(1, BufferDown, INDICATOR_DATA);
   
   // Buffers para el Ribbon (Relleno)
   SetIndexBuffer(2, BufferFill1, INDICATOR_DATA);
   SetIndexBuffer(3, BufferFill2, INDICATOR_DATA);
   
   PlotIndexSetString(0, PLOT_LABEL, "Up Trend");
   PlotIndexSetString(1, PLOT_LABEL, "Down Trend");
   PlotIndexSetString(2, PLOT_LABEL, "Ribbon Fill");
   
   PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetDouble(2, PLOT_EMPTY_VALUE, EMPTY_VALUE);

   IndicatorSetString(INDICATOR_SHORTNAME, "ML Supertrend + Ribbon");

   InitKernelWeights();

   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 < InpATRPeriod + 5) return(0);

   ArraySetAsSeries(open, true);
   ArraySetAsSeries(close, true);
   ArraySetAsSeries(BufferUp, true);
   ArraySetAsSeries(BufferDown, true);
   ArraySetAsSeries(BufferFill1, true);
   ArraySetAsSeries(BufferFill2, true);

   int limit = rates_total - prev_calculated;
   if(limit > rates_total - InpATRPeriod - 1)
      limit = rates_total - InpATRPeriod - 1;

   static double prev_supertrend = 0.0;
   static int prev_direction = 1;

   for(int i = limit; i >= 0; i--)
   {
      // 1. Promedio movil simple (mean)
      double sum_src = 0.0;
      for(int j = 0; j < InpATRPeriod; j++)
         sum_src += close[i + j];
      double mean = sum_src / (double)InpATRPeriod;

      // 2. Prediccion ML basada en Kernel
      double dotprod = 0.0;
      for(int j = 0; j < InpATRPeriod; j++)
      {
         dotprod += K_weights[j] * (close[i + (InpATRPeriod - 1 - j)] - mean);
      }
      double predicted_value = dotprod + mean;

      // 3. Estimacion MAE
      double sum_abs = 0.0;
      for(int j = 0; j < InpATRPeriod; j++)
         sum_abs += MathAbs(close[i + j] - predicted_value);
      
      double mae = (sum_abs / (double)InpATRPeriod) * InpFactor;
      
      double upper = predicted_value + mae;
      double lower = predicted_value - mae;

      // 4. Logica Supertrend
      double supertrend = 0.0;
      int direction = prev_direction;

      if(prev_supertrend == 0.0)
      {
         supertrend = (close[i] > lower) ? lower : upper;
         direction = (close[i] > lower) ? 1 : 0;
      }
      else
      {
         if(prev_direction == 1)
         {
            supertrend = MathMax(lower, prev_supertrend);
            if(close[i] < supertrend)
            {
               direction = 0;
               supertrend = upper;
            }
         }
         else
         {
            supertrend = MathMin(upper, prev_supertrend);
            if(close[i] > supertrend)
            {
               direction = 1;
               supertrend = lower;
            }
         }
      }

      // 5. Asignar Buffers de Lineas
      if(direction == 1)
      {
         BufferUp[i] = supertrend;
         BufferDown[i] = EMPTY_VALUE;
      }
      else
      {
         BufferDown[i] = supertrend;
         BufferUp[i] = EMPTY_VALUE;
      }

      // 6. Asignar Buffers para el Ribbon (Relleno entre el centro de la vela y la linea)
      double bodyMiddle = (open[i] + close[i]) / 2.0;
      BufferFill1[i] = bodyMiddle;
      BufferFill2[i] = supertrend;

      // Guardar estados
      if(i > 0)
      {
         prev_supertrend = supertrend;
         prev_direction = direction;
      }
   }

   return(rates_total);
}
//+------------------------------------------------------------------+