//+------------------------------------------------------------------+
//|                      Adaptive Reversal Force                     |
//+------------------------------------------------------------------+
#property strict
#property version   "1.0"
#property indicator_separate_window
#property indicator_buffers 3
#property indicator_color1 clrSilver        // Bullish force
#property indicator_color2 clrRed           // Bearish force  
#property indicator_color3 clrGray          // Threshold lines
#property indicator_width1 2
#property indicator_width2 2
#property indicator_width3 1
#property indicator_minimum 0


// Inputs
input int ZMAPeriod = 100;
input int RSIPeriod = 14;
input int ATRPeriod = 14;
input int SmoothPeriod = 10;

// Buffers
double BullishForce[];
double BearishForce[];
double ThresholdLines[];

int OnInit()
{
   IndicatorShortName("Adaptive Reversal Force");

   SetIndexBuffer(0, BullishForce);
   SetIndexBuffer(1, BearishForce);
   SetIndexBuffer(2, ThresholdLines);
   
   SetIndexStyle(0, DRAW_HISTOGRAM);
   SetIndexStyle(1, DRAW_HISTOGRAM);
   SetIndexStyle(2, DRAW_LINE);

   ArraySetAsSeries(BullishForce, true);
   ArraySetAsSeries(BearishForce, true);
   ArraySetAsSeries(ThresholdLines, true);

   return(INIT_SUCCEEDED);
}

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 < ZMAPeriod + SmoothPeriod + 10)
      return(0);

   int start = MathMax(ZMAPeriod, MathMax(RSIPeriod, ATRPeriod)) + SmoothPeriod;
   
   int limit = rates_total - prev_calculated;
   if (prev_calculated > 0)
      limit++;
   
   limit = MathMin(limit, rates_total - start);
   
   for (int i = limit; i >= 0; i--)
   {
      // --- Z-Score (correct lookback period)
      double sum = 0, sumSq = 0;
      int count = 0;
      for (int j = 0; j < ZMAPeriod && (i + j) < rates_total; j++)
      {
         double c = close[i + j];
         sum += c;
         sumSq += c * c;
         count++;
      }

      double mean = (count > 0) ? sum / count : 0;
      double stddev = (count > 0) ? MathSqrt((sumSq / count) - (mean * mean)) : 0;
      double zscore = (stddev > 0) ? (close[i] - mean) / stddev : 0;

      // --- RSI weighting
      double rsi = iRSI(NULL, 0, RSIPeriod, PRICE_CLOSE, i);
      double rsiWeight = (rsi - 50.0) / 50.0;

      // --- ATR filter
      double atr = iATR(NULL, 0, ATRPeriod, i);
      double atrWeight = (atr > 0.0) ? 1.0 : 0.5;

      // --- Raw force
      double raw = zscore * rsiWeight * atrWeight;

      // --- Non-repainting smoothing (SMA)
      double smooth = raw;
      int smoothCount = 1;
      
      for (int j = 1; j < SmoothPeriod && (i + j) < rates_total; j++)
      {
         // Calculate components for each bar in smoothing window
         double sum_j = 0, sumSq_j = 0;
         int count_j = 0;
         
         for (int k = 0; k < ZMAPeriod && (i + j + k) < rates_total; k++)
         {
            double c_j = close[i + j + k];
            sum_j += c_j;
            sumSq_j += c_j * c_j;
            count_j++;
         }

         double mean_j = (count_j > 0) ? sum_j / count_j : 0;
         double stddev_j = (count_j > 0) ? MathSqrt((sumSq_j / count_j) - (mean_j * mean_j)) : 0;
         double zscore_j = (stddev_j > 0) ? (close[i + j] - mean_j) / stddev_j : 0;

         double rsi_j = iRSI(NULL, 0, RSIPeriod, PRICE_CLOSE, i + j);
         double rsiWeight_j = (rsi_j - 50.0) / 50.0;

         double atr_j = iATR(NULL, 0, ATRPeriod, i + j);
         double atrWeight_j = (atr_j > 0.0) ? 1.0 : 0.5;

         double raw_j = zscore_j * rsiWeight_j * atrWeight_j;
         smooth += raw_j;
         smoothCount++;
      }
      
      smooth /= smoothCount;

      // --- Assign to buffers
      if (smooth >= 0) {
         BullishForce[i] = smooth;
         BearishForce[i] = 0;
      } else {
         BullishForce[i] = 0;
         BearishForce[i] = smooth;
      }

      ThresholdLines[i] = 0.0;
   }

   return(rates_total);
}