
//+------------------------------------------------------------------+
//| Ultimate Stochastic & ADX Exhaustion V17 (MT5 Native)          |
//| Converted from Pine Script                                      |
//| Buy/Sell signals only (no MT4 functions, no series arrays)      |
//+------------------------------------------------------------------+
#property strict
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots   2

//--- plot Buy
#property indicator_label1  "Buy"
#property indicator_type1    DRAW_ARROW
#property indicator_color1   clrLime
#property indicator_width1   1

//--- plot Sell
#property indicator_label2  "Sell"
#property indicator_type2    DRAW_ARROW
#property indicator_color2   clrRed
#property indicator_width2   1

//-------------------- INPUTS --------------------
input int K1=9; input int D1=3;
input int K2=14; input int D2=3;
input int K3=40; input int D3=4;
input int K4=60; input int D4=10;



enum stoch_
{
   stoch1D,
   stoch2D,
   stoch3D,
   stoch4D
};
input stoch_ mainSource = stoch1D;










input bool useTightLevels=false;

input bool filterCandle=true;
input bool filterStructure=true;
input int pivotLookback=3;

input bool useAdxFilter=true;
input int ADXLength=14; 
input double ADXThreshold=25;

input bool useVolumeFilter=false;
input int volumeLookback=14;

input bool useAtrFilter=false;
input int ATRLookback=14;

input bool useVolFilter = false;

input int volLookback = 14;
input int ATRSMAPer = 50;
//-------------------- BUFFERS --------------------
double BuyBuffer[];
double SellBuffer[];

//-------------------- HANDLES --------------------
int hStoch1, hStoch2, hStoch3, hStoch4;
int hADX, hATR;

//-------------------- INIT --------------------
int OnInit()
{
   SetIndexBuffer(0, BuyBuffer, INDICATOR_DATA);
   SetIndexBuffer(1, SellBuffer, INDICATOR_DATA);

   PlotIndexSetInteger(0, PLOT_ARROW, 233);
   PlotIndexSetInteger(1, PLOT_ARROW, 234);

   hStoch1 = iStochastic(_Symbol,_Period,K1,D1,3,MODE_SMA,STO_LOWHIGH);
   hStoch2 = iStochastic(_Symbol,_Period,K2,D2,3,MODE_SMA,STO_LOWHIGH);
   hStoch3 = iStochastic(_Symbol,_Period,K3,D3,3,MODE_SMA,STO_LOWHIGH);
   hStoch4 = iStochastic(_Symbol,_Period,K4,D4,3,MODE_SMA,STO_LOWHIGH);

   hADX = iADX(_Symbol,_Period,ADXLength);
   hATR = iATR(_Symbol,_Period,ATRLookback);

   return(INIT_SUCCEEDED);
}

//-------------------- HELPERS --------------------
double HighestHigh(const double &high[], int i, int lookback)
{
   double maxh = high[i];
   for(int j=i+1;j<i+lookback && j<ArraySize(high);j++)
      if(high[j]>maxh) maxh=high[j];
   return maxh;
}

double LowestLow(const double &low[], int i, int lookback)
{
   double minl = low[i];
   for(int j=i+1;j<i+lookback && j<ArraySize(low);j++)
      if(low[j]<minl) minl=low[j];
   return minl;
}

//-------------------- MAIN --------------------
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<100) return 0;

   double st1[],st2[],st3[],st4[];
   double adx[],atr[];

   ArrayResize(st1,rates_total);
   ArrayResize(st2,rates_total);
   ArrayResize(st3,rates_total);
   ArrayResize(st4,rates_total);
   ArrayResize(adx,rates_total);
   ArrayResize(atr,rates_total);

   CopyBuffer(hStoch1,0,0,rates_total,st1);
   CopyBuffer(hStoch2,0,0,rates_total,st2);
   CopyBuffer(hStoch3,0,0,rates_total,st3);
   CopyBuffer(hStoch4,0,0,rates_total,st4);
   CopyBuffer(hADX,0,0,rates_total,adx);
   CopyBuffer(hATR,0,0,rates_total,atr);

   bool visitedLow[], visitedHigh[], adxOK[];
   ArrayResize(visitedLow,rates_total);
   ArrayResize(visitedHigh,rates_total);
   ArrayResize(adxOK,rates_total);

   double overbought = useTightLevels ? 90 : 80;
   double oversold   = useTightLevels ? 10 : 20;

   for(int i=100; i < rates_total; i++)
   {
      BuyBuffer[i]=EMPTY_VALUE;
      SellBuffer[i]=EMPTY_VALUE;

           /* 
      // --- Calculations ---
      stoch1D = ta.sma(ta.stoch(close, high, low, k1), d1)
      stoch2D = ta.sma(ta.stoch(close, high, low, k2), d2)
      stoch3D = ta.sma(ta.stoch(close, high, low, k3), d3)
      stoch4D = ta.sma(ta.stoch(close, high, low, k4), d4)
      
      float activeD = switch mainSource
          "Stoch 1" => stoch1D
          "Stoch 2" => stoch2D
          "Stoch 3" => stoch3D
          "Stoch 4" => stoch4D
          => stoch4D
      
      float activeContStoch = switch contSource
          "Stoch 1" => stoch1D
          "Stoch 2" => stoch2D
          "Stoch 3" => stoch3D
          "Stoch 4" => stoch4D
          => stoch3D
      
      */
      double activeD0;
      double activeD1;
      if (mainSource == stoch1D)
      {
         activeD0 = st1[i];
         activeD1 = st1[i-1];
      }
      if (mainSource == stoch2D)
      {
         activeD0 = st2[i];
         activeD1 = st2[i-1];
      }
      if (mainSource == stoch3D)
      {
         activeD0 = st3[i];
         activeD1 = st3[i-1];
      }
      if (mainSource == stoch4D)
      {
         activeD0 = st4[i];
         activeD1 = st4[i-1];
      }
      
      
      /*
      // --- ADX Technical Logic ---
      // True ADX calculation requires tracking Directional Movement (+DI && -DI)
      [plusDI, minusDI, adxValue] = ta.dmi(adxLength, adxLength)
      */      
      double adxValue0 = adx[i];
      double adxValue1 = adx[i-1];
      
      
      /*
      // Track if ADX historically climbed into heavy trend territory since the Stochastic entered its extreme zone
      var bool adxExceededThreshold = false
      if activeD <= oversold || activeD >= overbought
          if adxValue >= adxThreshold
              adxExceededThreshold = true
      
      */
      bool adxExceededThreshold = false;
      if (activeD0 <= oversold || activeD0 >= overbought)
      if (adxValue0 >= ADXThreshold)
          adxExceededThreshold = true;
      
      /*
      // ADX is falling when its current value is lower than its previous bar value
      adxFalling = adxValue < adxValue[1]
      passADX    = not useAdxFilter || (adxExceededThreshold && adxFalling)
      */
      
      bool adxFalling = adxValue0 < adxValue1;
      bool passADX = !useAdxFilter || (adxExceededThreshold && adxFalling);
      
      
      /*
      // --- 50-Line Macro Exhaustion Logic ---
      var bool visitedOversold   = false
      var bool visitedOverbought = false
      
      if activeD <= oversold
          visitedOversold = true
      if activeD >= overbought
          visitedOverbought = true*/
      bool visitedOversold   = false;
      bool visitedOverbought = false;
      
      if (activeD0 <= oversold)
          visitedOversold = true;
      if (activeD0 >= overbought)
          visitedOverbought = true;   
          
          
          
          
      /*
      // Reset safety clamp if it cross extremes without hitting 50
      if activeD >= overbought && visitedOversold
          visitedOversold = false
          adxExceededThreshold = false
      if activeD <= oversold && visitedOverbought
          visitedOverbought = false
          adxExceededThreshold = false
      */
      if (activeD0 >= overbought && visitedOversold)
      {
          visitedOversold = false;
          adxExceededThreshold = false;
      }
      if (activeD0 <= oversold && visitedOverbought)
      {
          visitedOverbought = false;
          adxExceededThreshold = false; 
      }     
      
      
      /*
      // Base 50-Cross Signals
      baseBuy  = ta.crossover(activeD, 50) && visitedOversold
      baseSell = ta.crossunder(activeD, 50) && visitedOverbought*/
       
      bool baseBuy  = /*activeD0 > 50 /*&& activeD1 <= 50*/ 1&& visitedOversold;
      bool baseSell = /*activeD0 < 50/* && activeD1 >= 50*/ 1&& visitedOverbought;
      
      
      
      /*
      // --- Filter Validations ---
      
      // 1. Candle Color Confirmation
      candleBull = close > open
      candleBear = close < open
      passCandleBuy  = not filterCandle || candleBull
      passCandleSell = not filterCandle || candleBear
      */
      double c0 = close[i];
      double o0 = open[i];
      bool candleBull = c0 > o0;
      bool candleBear = c0 < o0;
      bool passCandleBuy  = !filterCandle || candleBull;
      bool passCandleSell = !filterCandle || candleBear;
      
      
      
      /*
      // 2. Market Structure Confirmation
      priceStructureBuy  = not filterStructure || (low > ta.lowest(low, pivotLookback)[1])
      priceStructureSell = not filterStructure || (high < ta.highest(high, pivotLookback)[1])
      */
      
      double lowest = ArrayMinimum(low,i-1,pivotLookback);
      double highest = ArrayMaximum(high,i-1,pivotLookback);
      
      bool priceStructureBuy  = !filterStructure || lowest;
      bool priceStructureSell = !filterStructure || highest;
      
      /*
      // 3. Volume Filter
      avgVol = ta.sma(volume, volLookback)
      passVolume = not useVolFilter || (volume > avgVol)
      */
      double avgVol = 0;
      for (int j = 0; j < volLookback; j++)
         avgVol += volume[i-j]/double(volLookback);      
      bool passVolume = !useVolFilter || (volume[i] > avgVol);
            
      /*
      // 4. ATR Volatility Filter
      myAtr = ta.atr(atrLookback)
      avgAtr = ta.sma(myAtr, 50)
      passVolatility = not useAtrFilter || (myAtr > avgAtr * 0.8)*/
      double myAtr = atr[i];
      double avgAtr = 0;
      for (int j = 0; j < ATRSMAPer; j++)
         avgAtr += atr[i-j]/double(50);
      bool passVolatility = !useAtrFilter || (myAtr > avgAtr * 0.8);
      /*
      // Combined Master Signals
      bool buySignal  = baseBuy && passCandleBuy && priceStructureBuy && passVolume && passVolatility && passADX
      bool sellSignal = baseSell && passCandleSell && priceStructureSell && passVolume && passVolatility && passADX*/
      
      
      bool buySignal  = baseBuy && passCandleBuy && priceStructureBuy && passVolume && passVolatility && passADX;
      bool sellSignal = baseSell && passCandleSell && priceStructureSell && passVolume && passVolatility && passADX;
      

      if(buySignal) BuyBuffer[i]=low[i]-_Point*10;
      if(sellSignal) SellBuffer[i]=high[i]+_Point*10;
   }

   return rates_total;
}
//+------------------------------------------------------------------+
