//+------------------------------------------------------------------+
//|                                  RedK_VARSI_Trend_Overlay.mq5    |
//|                                  Copyright 2026, RedKTrader / MT5 |
//+------------------------------------------------------------------+
#property copyright   "RedKTrader / Converted to MQL5"
#property link        "https://www.tradingview.com/script/RedK_VARSI/"
#property version     "1.00"
#property description "RedK VARSI On-Chart Trend Overlay Moving Average"
#property indicator_chart_window
#property indicator_buffers 3
#property indicator_plots   1

//--- Plot 1: Trend MA Line
#property indicator_type1   DRAW_COLOR_LINE
#property indicator_color1  C'51,170,0', C'255,17,17'
#property indicator_style1  STYLE_SOLID
#property indicator_width1  2
#property indicator_label1  "VARSI Trend MA"

//+------------------------------------------------------------------+
//| Enums                                                            |
//+------------------------------------------------------------------+
enum ENUM_MA_TYPE_OV
{
   MA_OV_EMA, // EMA
   MA_OV_HMA, // HMA
   MA_OV_SMA, // SMA
   MA_OV_WMA  // WMA
};

enum ENUM_COLOR_SOURCE
{
   COLOR_SRC_VARSI_DUALTF, // Color by Dual TF Alignment (Bullish/Bearish)
   COLOR_SRC_MA_SLOPE      // Color by MA Slope (Rising/Falling)
};

//+------------------------------------------------------------------+
//| Inputs                                                           |
//+------------------------------------------------------------------+
input group "=== On-Chart Moving Average ==="
input int                InpMaLen          = 20;                   // MA Length
input ENUM_MA_TYPE_OV    InpMaType         = MA_OV_WMA;            // MA Method
input ENUM_APPLIED_PRICE InpAppliedPrice   = PRICE_CLOSE;          // Applied Price
input ENUM_COLOR_SOURCE  InpColorSource    = COLOR_SRC_VARSI_DUALTF;// Color Source
input color              InpColBull        = C'51,170,0';          // Bullish Color
input color              InpColBear        = C'255,17,17';         // Bearish Color

input group "=== Context VARSI Filter ==="
input int                InpHtfMult        = 5;                    // Context Multiplier
input int                InpRsiLen         = 14;                   // VARSI Length

//+------------------------------------------------------------------+
//| Indicator Buffers                                                |
//+------------------------------------------------------------------+
double Buffer_MA[];
double Buffer_MA_Color[];
double Buffer_Price[];

//+------------------------------------------------------------------+
//| Helper: MA Calculators                                           |
//+------------------------------------------------------------------+
void CalcSMA(const double &src[], const int total, const int len, double &out[])
{
   ArrayResize(out, total);
   if(total == 0) return;
   double sum = 0.0;
   for(int i = 0; i < total; i++)
   {
      sum += src[i];
      if(i >= len) sum -= src[i - len];
      out[i] = (i >= len - 1) ? sum / (double)len : sum / (double)(i + 1);
   }
}

void CalcEMA(const double &src[], const int total, const int len, double &out[])
{
   ArrayResize(out, total);
   if(total == 0) return;
   double alpha = 2.0 / (len + 1.0);
   double sum = 0.0;
   int warmup = MathMin(len, total);
   for(int i = 0; i < warmup; i++) { sum += src[i]; out[i] = sum / (double)(i + 1); }
   for(int i = warmup; i < total; i++) out[i] = alpha * src[i] + (1.0 - alpha) * out[i - 1];
}

void CalcWMA(const double &src[], const int total, const int len, double &out[])
{
   ArrayResize(out, total);
   if(total == 0) return;
   double denom = (double)len * ((double)len + 1.0) / 2.0;
   for(int i = 0; i < total; i++)
   {
      double sum = 0.0;
      if(i >= len - 1)
      {
         for(int k = 0; k < len; k++) sum += src[i - k] * (double)(len - k);
         out[i] = sum / denom;
      }
      else
      {
         double p_denom = (double)(i + 1) * ((double)i + 2.0) / 2.0;
         for(int k = 0; k <= i; k++) sum += src[i - k] * (double)(i + 1 - k);
         out[i] = sum / p_denom;
      }
   }
}

void CalcHMA(const double &src[], const int total, const int len, double &out[])
{
   int half_len = (int)MathFloor(len / 2.0);
   if(half_len < 1) half_len = 1;
   int sqrt_len = (int)MathRound(MathSqrt(len));
   if(sqrt_len < 1) sqrt_len = 1;
   
   double wma_half[], wma_full[], diff[];
   CalcWMA(src, total, half_len, wma_half);
   CalcWMA(src, total, len, wma_full);
   
   ArrayResize(diff, total);
   for(int i = 0; i < total; i++) diff[i] = 2.0 * wma_half[i] - wma_full[i];
   CalcWMA(diff, total, sqrt_len, out);
}

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
   SetIndexBuffer(0, Buffer_MA, INDICATOR_DATA);
   SetIndexBuffer(1, Buffer_MA_Color, INDICATOR_COLOR_INDEX);
   SetIndexBuffer(2, Buffer_Price, INDICATOR_CALCULATIONS);

   PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_COLOR_LINE);
   PlotIndexSetInteger(0, PLOT_LINE_COLOR, 0, InpColBull);
   PlotIndexSetInteger(0, PLOT_LINE_COLOR, 1, InpColBear);
   PlotIndexSetInteger(0, PLOT_LINE_WIDTH, 2);
   PlotIndexSetString(0, PLOT_LABEL, "VARSI Trend MA");

   IndicatorSetString(INDICATOR_SHORTNAME, "RedK_VARSI_Trend_Overlay");
   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 <= InpMaLen + 2) return(0);

   // Extract applied price
   ArrayResize(Buffer_Price, rates_total);
   for(int i = 0; i < rates_total; i++)
   {
      switch(InpAppliedPrice)
      {
         case PRICE_OPEN:     Buffer_Price[i] = open[i]; break;
         case PRICE_HIGH:     Buffer_Price[i] = high[i]; break;
         case PRICE_LOW:      Buffer_Price[i] = low[i]; break;
         case PRICE_MEDIAN:   Buffer_Price[i] = (high[i] + low[i]) / 2.0; break;
         case PRICE_TYPICAL:  Buffer_Price[i] = (high[i] + low[i] + close[i]) / 3.0; break;
         case PRICE_WEIGHTED: Buffer_Price[i] = (high[i] + low[i] + 2.0 * close[i]) / 4.0; break;
         default:             Buffer_Price[i] = close[i]; break;
      }
   }

   // Compute Moving Average
   switch(InpMaType)
   {
      case MA_OV_SMA: CalcSMA(Buffer_Price, rates_total, InpMaLen, Buffer_MA); break;
      case MA_OV_EMA: CalcEMA(Buffer_Price, rates_total, InpMaLen, Buffer_MA); break;
      case MA_OV_HMA: CalcHMA(Buffer_Price, rates_total, InpMaLen, Buffer_MA); break;
      case MA_OV_WMA: CalcWMA(Buffer_Price, rates_total, InpMaLen, Buffer_MA); break;
      default:        CalcWMA(Buffer_Price, rates_total, InpMaLen, Buffer_MA); break;
   }

   // Color MA line based on slope or slope + momentum
   for(int i = 0; i < rates_total; i++)
   {
      if(i == 0)
         Buffer_MA_Color[i] = 0;
      else
         Buffer_MA_Color[i] = (Buffer_MA[i] >= Buffer_MA[i - 1]) ? 0 : 1;
   }

   return(rates_total);
}
//+------------------------------------------------------------------+
