//+------------------------------------------------------------------+
//|                                           TwinRangeFilter.mq4   |
//|                        Copyright 2026, Converted by Grok @ xAI   |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "Converted by Grok @ xAI"
#property link      ""
#property version   "1.00"
#property strict

#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots 2

//--- plot Buy
#property indicator_label1  "Long"
#property indicator_type1   DRAW_ARROW
#property indicator_color1  clrLime
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- plot Short
#property indicator_label2  "Short"
#property indicator_type2   DRAW_ARROW
#property indicator_color2  clrRed
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

//--- Inputs
extern int per1 = 27;
extern double mult1 = 1.6;
extern int per2 = 55;
extern double mult2 = 2.0;

//--- Buffers
double BuyBuffer[];
double SellBuffer[];

//--- Calculation arrays
double avrng1[];
double smoothrng1[];
double avrng2[];
double smoothrng2[];
double smrng_[];
double filt_[];
double upward_[];
double downward_[];
double CondIni_[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   SetIndexBuffer(0, BuyBuffer);
   SetIndexArrow(0, 233); // Up arrow for Long
   SetIndexEmptyValue(0, EMPTY_VALUE);

   SetIndexBuffer(1, SellBuffer);
   SetIndexArrow(1, 234); // Down arrow for Short
   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[])
  {
   ArraySetAsSeries(time, false);
   ArraySetAsSeries(open, false);
   ArraySetAsSeries(high, false);
   ArraySetAsSeries(low, false);
   ArraySetAsSeries(close, false);

   ArraySetAsSeries(BuyBuffer, false);
   ArraySetAsSeries(SellBuffer, false);
   ArraySetAsSeries(avrng1, false);
   ArraySetAsSeries(smoothrng1, false);
   ArraySetAsSeries(avrng2, false);
   ArraySetAsSeries(smoothrng2, false);
   ArraySetAsSeries(smrng_, false);
   ArraySetAsSeries(filt_, false);
   ArraySetAsSeries(upward_, false);
   ArraySetAsSeries(downward_, false);
   ArraySetAsSeries(CondIni_, false);

   ArrayResize(avrng1, rates_total);
   ArrayResize(smoothrng1, rates_total);
   ArrayResize(avrng2, rates_total);
   ArrayResize(smoothrng2, rates_total);
   ArrayResize(smrng_, rates_total);
   ArrayResize(filt_, rates_total);
   ArrayResize(upward_, rates_total);
   ArrayResize(downward_, rates_total);
   ArrayResize(CondIni_, rates_total);

   int i_start = 0;
   if (prev_calculated > 0) i_start = prev_calculated - 1;

   if (prev_calculated == 0)
     {
      ArrayInitialize(avrng1, 0);
      ArrayInitialize(smoothrng1, 0);
      ArrayInitialize(avrng2, 0);
      ArrayInitialize(smoothrng2, 0);
      ArrayInitialize(smrng_, 0);
      ArrayInitialize(upward_, 0);
      ArrayInitialize(downward_, 0);
      ArrayInitialize(CondIni_, 0);
      ArrayInitialize(BuyBuffer, EMPTY_VALUE);
      ArrayInitialize(SellBuffer, EMPTY_VALUE);

      if (rates_total > 0)
        {
         filt_[0] = close[0];
         BuyBuffer[0] = EMPTY_VALUE;
         SellBuffer[0] = EMPTY_VALUE;
        }
      i_start = 1;
     }

   for (int i = i_start; i < rates_total; i++)
     {
      // Smooth range 1
      double alpha1 = 2.0 / (per1 + 1.0);
      avrng1[i] = alpha1 * MathAbs(close[i] - close[i-1]) + (1 - alpha1) * avrng1[i-1];

      int wper1 = per1 * 2 - 1;
      double alpha_w1 = 2.0 / (wper1 + 1.0);
      smoothrng1[i] = alpha_w1 * avrng1[i] + (1 - alpha_w1) * smoothrng1[i-1];

      double smrng1_val = smoothrng1[i] * mult1;

      // Smooth range 2
      double alpha2 = 2.0 / (per2 + 1.0);
      avrng2[i] = alpha2 * MathAbs(close[i] - close[i-1]) + (1 - alpha2) * avrng2[i-1];

      int wper2 = per2 * 2 - 1;
      double alpha_w2 = 2.0 / (wper2 + 1.0);
      smoothrng2[i] = alpha_w2 * avrng2[i] + (1 - alpha_w2) * smoothrng2[i-1];

      double smrng2_val = smoothrng2[i] * mult2;

      // Average smrng
      smrng_[i] = (smrng1_val + smrng2_val) / 2.0;

      // Range filter
      double r = smrng_[i];
      double x = close[i];
      double prev_filt = filt_[i-1];
      if (x > prev_filt)
        {
         filt_[i] = (x - r < prev_filt) ? prev_filt : x - r;
        }
      else
        {
         filt_[i] = (x + r > prev_filt) ? prev_filt : x + r;
        }

      // Upward
      if (filt_[i] > filt_[i-1])
        {
         upward_[i] = upward_[i-1] + 1;
        }
      else if (filt_[i] < filt_[i-1])
        {
         upward_[i] = 0;
        }
      else
        {
         upward_[i] = upward_[i-1];
        }

      // Downward
      if (filt_[i] < filt_[i-1])
        {
         downward_[i] = downward_[i-1] + 1;
        }
      else if (filt_[i] > filt_[i-1])
        {
         downward_[i] = 0;
        }
      else
        {
         downward_[i] = downward_[i-1];
        }

      // Conditions
      bool longCond = (close[i] > filt_[i] && close[i] > close[i-1] && upward_[i] > 0) ||
                      (close[i] > filt_[i] && close[i] < close[i-1] && upward_[i] > 0);

      bool shortCond = (close[i] < filt_[i] && close[i] < close[i-1] && downward_[i] > 0) ||
                       (close[i] < filt_[i] && close[i] > close[i-1] && downward_[i] > 0);

      // CondIni
      if (longCond)
        {
         CondIni_[i] = 1;
        }
      else if (shortCond)
        {
         CondIni_[i] = -1;
        }
      else
        {
         CondIni_[i] = CondIni_[i-1];
        }

      // Signals
      bool long_signal = longCond && (CondIni_[i-1] == -1);
      bool short_signal = shortCond && (CondIni_[i-1] == 1);

      BuyBuffer[i] = long_signal ? low[i] : EMPTY_VALUE;
      SellBuffer[i] = short_signal ? high[i] : EMPTY_VALUE;
     }

   return(rates_total);
  }
//+------------------------------------------------------------------+