//+------------------------------------------------------------------+
//|                                                  VBSM.mq5        |
//|            Volume Based Buy and Sell Momentum by 2tm              |
//|                        (Pine Script Conversion)                   |
//+------------------------------------------------------------------+
#property copyright "Converted from Pine Script by MetaTrader Assistant"
#property link      ""
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 4
#property indicator_plots   3

//--- Plot 1: PVI + NVI (nRes3)
#property indicator_label1  "PVI + NVI"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrMediumBlue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- Plot 2: SMA composite (nResEMA3)
#property indicator_label2  "SMA"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrMaroon
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

//--- Hidden fill buffers (use DRAW_FILLING on plot 2 via code)
#property indicator_label3  "Momentum Fill"
#property indicator_type3   DRAW_FILLING
#property indicator_color3  clrMediumBlue, clrMaroon

//--- input parameters
input int      InpLength = 25;           // Length
input color    FillClrUp = clrMediumBlue;
input color    FillClrDn = clrMaroon;

//--- indicator buffers
double         BufferPviNvi[];           // nRes3 = nRes1 + nRes2
double         BufferEma[];              // nResEMA3 = SMA(nRes1) + SMA(nRes2)
double         BufferFill1[];            // Same as nRes3 (for fill)
double         BufferFill2[];            // Same as nResEMA3 (for fill)

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Indicator buffers mapping
   SetIndexBuffer(0, BufferPviNvi, INDICATOR_DATA);
   SetIndexBuffer(1, BufferEma,    INDICATOR_DATA);
   SetIndexBuffer(2, BufferFill1,  INDICATOR_DATA);
   SetIndexBuffer(3, BufferFill2,  INDICATOR_DATA);

//--- Configure filling colors
   PlotIndexSetInteger(2, PLOT_DRAW_TYPE, DRAW_FILLING);
   PlotIndexSetInteger(2, PLOT_LINE_COLOR, 0, FillClrUp);   // when BufferPviNvi > BufferEma
   PlotIndexSetInteger(2, PLOT_LINE_COLOR, 1, FillClrDn);    // when BufferPviNvi <= BufferEma

//--- Set empty value
   PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, 0.0);
   PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, 0.0);
   PlotIndexSetDouble(2, PLOT_EMPTY_VALUE, 0.0);
   PlotIndexSetDouble(3, PLOT_EMPTY_VALUE, 0.0);

//--- Short name
   IndicatorSetString(INDICATOR_SHORTNAME, "VBSM(" + (string)InpLength + ")");

   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 < 2)
      return(0);

   int start = (prev_calculated == 0) ? 1 : prev_calculated - 1;

   //--- Local static arrays to persist nRes1 and nRes2 across bars (like Pine var)
   static double nRes1[];
   static double nRes2[];

   //--- Initialize or resize static arrays
   if(ArraySize(nRes1) != rates_total)
     {
      ArrayResize(nRes1, rates_total);
      ArrayResize(nRes2, rates_total);
      if(prev_calculated == 0)
        {
         ArrayInitialize(nRes1, 0.0);
         ArrayInitialize(nRes2, 0.0);
        }
     }

   //--- Temporary SMA accumulators
   double ma1 = 0.0, ma2 = 0.0;

   for(int i = start; i < rates_total; i++)
     {
      //--- Rate of Change (%): roc(close, 1) = (close / close[1] - 1) * 100
      double xROC = (close[i - 1] > 0.0) ? ((close[i] / close[i - 1]) - 1.0) * 100.0 : 0.0;

      //--- Carry forward previous values (Pine var default: keep last value)
      nRes1[i] = nRes1[i - 1];
      nRes2[i] = nRes2[i - 1];

      //--- nRes1: accumulates xROC when volume decreases
      if(tick_volume[i] < tick_volume[i - 1])
         nRes1[i] += xROC;

      //--- nRes2: accumulates xROC when volume increases
      if(tick_volume[i] > tick_volume[i - 1])
         nRes2[i] += xROC;

      //--- Volume unchanged: neither accumulator changes (already carried forward)

      //--- nRes3 = nRes1 + nRes2
      BufferPviNvi[i] = nRes1[i] + nRes2[i];
      BufferFill1[i]  = BufferPviNvi[i];

      //--- Calculate SMAs on the fly using a simple sum over the window
      if(i >= InpLength - 1)
        {
         ma1 = 0.0;
         ma2 = 0.0;
         for(int k = 0; k < InpLength; k++)
           {
            ma1 += nRes1[i - k];
            ma2 += nRes2[i - k];
           }
         BufferEma[i]   = (ma1 / InpLength) + (ma2 / InpLength);
        }
      else
        {
         BufferEma[i] = 0.0;
        }

      BufferFill2[i] = BufferEma[i];
     }

   return(rates_total);
  }
//+------------------------------------------------------------------+
