//+------------------------------------------------------------------+
//|                                  NonRepaintVSAArrows.mq4         |
//|                        Based on Volume Spread Analysis           |
//+------------------------------------------------------------------+
#property copyright ""
#property link      ""
#property version   "1.00"
#property strict
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots   2

//--- Plot BuySignal
#property indicator_label1  "Buy Signal"
#property indicator_type1   DRAW_ARROW
#property indicator_color1  clrLime
#property indicator_style1  STYLE_SOLID
#property indicator_width1  2

//--- Plot SellSignal
#property indicator_label2  "Sell Signal"
#property indicator_type2   DRAW_ARROW
#property indicator_color2  clrRed
#property indicator_style2  STYLE_SOLID
#property indicator_width2  2

//--- Input Parameters
input int      MA_Volume_Period = 20;           // MA Period for Volume
input double   Volume_Multiplier = 1.5;         // Volume Multiplier for threshold
input double   Close_Position_Threshold_Buy = 0.99; // Close position % for Buy (0.7 = 70%)
input double   Close_Position_Threshold_Sell = 0.01; // Close position % for Sell (0.3 = 30%)
input int      ArrowOffsetPoints = 100;         // Arrow offset in points

//--- Indicator Buffers
double         BuyBuffer[];
double         SellBuffer[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
//--- Indicator buffers mapping
   SetIndexBuffer(0, BuyBuffer);
   SetIndexBuffer(1, SellBuffer);

//--- Set arrows
   SetIndexArrow(0, 233); // Up arrow
   SetIndexArrow(1, 234); // Down arrow

//--- Set EMPTY_VALUE
   SetIndexEmptyValue(0, EMPTY_VALUE);
   SetIndexEmptyValue(1, EMPTY_VALUE);

   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[])
{
//--- Check for minimum data
   if(rates_total < MA_Volume_Period)
      return(0);

//--- Calculate start position
   int start;
   if(prev_calculated == 0)
      start = MA_Volume_Period;
   else
      start = prev_calculated - 1;

//--- Process only closed bars
   int end = rates_total - 2;
   if(end < start)
      return(prev_calculated);

//--- Main processing loop
   for(int i = start; i <= end; i++)
   {
      //--- Get volume MA value
      double maVolume = iMA(NULL, 0, MA_Volume_Period, 0, MODE_SMA, 0, i);

      //--- Get price data
      double currentLow = low[i];
      double previousLow = low[i-1];
      double currentHigh = high[i];
      double previousHigh = high[i-1];
      double currentClose = close[i];
      long currentVolume = tick_volume[i];
      double barSpread = currentHigh - currentLow;

      //--- Skip invalid bars
      if(barSpread <= 0) continue;

      //--- Calculate close position in bar
      double closePosition = (currentClose - currentLow) / barSpread;

      //--- Check Buy conditions (Spring)
      bool buySignal = (currentLow < previousLow) &&
                       (closePosition >= Close_Position_Threshold_Buy) &&
                       (currentVolume > (maVolume * Volume_Multiplier));

      //--- Check Sell conditions (UpThrust)
      bool sellSignal = (currentHigh > previousHigh) &&
                        (closePosition <= Close_Position_Threshold_Sell) &&
                        (currentVolume > (maVolume * Volume_Multiplier));

      //--- Set Buy arrow
      if(buySignal && BuyBuffer[i] == EMPTY_VALUE)
         BuyBuffer[i] = currentLow - (ArrowOffsetPoints * _Point);

      //--- Set Sell arrow
      if(sellSignal && SellBuffer[i] == EMPTY_VALUE)
         SellBuffer[i] = currentHigh + (ArrowOffsetPoints * _Point);
   }

   return(rates_total);
}
//+------------------------------------------------------------------+