Page 1 of 2

How to detect divergence in forex scalping?

Posted: Tue Aug 11, 2026 5:15 pm
by FTtrader
Hello everybody,

today i would like to share with you one of best way how to see divergence in forex charts. This should help first of all newbie traders, because it is very common problem to spot it directly.

Coding divergence is notoriously tricky for beginners because humans see shapes and trendlines instantly, but a computer only sees raw numbers. To make an MT4 Expert Advisor "see" divergence, you have to force it to look back in time, find two distinct peaks or valleys, and compare them.
This logic makes a perfect technical guide.
Here is how to break it down.

The Logic (How to Make MT4 "See" It)
Instead of complicated ZigZag arrays, the cleanest way to code this for scalping is to split the recent past into two "windows" or blocks of time.

1. Window 1 (The Recent Extreme): Look at the last, say, 15 candles. Find the lowest price.

2. Window 2 (The Older Extreme): Look at the 15 candles before Window 1. Find the lowest price there.

3. The Comparison: Check the Stochastic value at the exact same candle index where those two price lows occurred.
If the price in Window 1 is lower than Window 2, but the Stochastic in Window 1 is higher, you have bullish divergence.

Re: How to detect divergence in forex scalping?

Posted: Tue Aug 11, 2026 5:17 pm
by FTtrader
Here i prepared for you code for MT4 traders:

The MQL4 Code

Here is a clean, modular function you can drop into an EA to detect both bullish and bearish divergence.

Code: Select all

 //+------------------------------------------------------------------+
//| Divergence Detector for MQL4                                     |
//+------------------------------------------------------------------+
void CheckStochasticDivergence()
{
    // --- 1. Define our search windows (adjust these for your timeframe) ---
    int window1_start = 1;       // Start looking from the previous closed candle
    int window1_length = 15;     // Look back 15 candles for the recent extreme
    
    int window2_start = 16;      // Start looking from candle 16
    int window2_length = 20;     // Look back 20 candles for the older extreme
    
    // --- 2. Find the candle INDEX (shift) of the highest and lowest prices ---
    // iLowest/iHighest returns the index number of the candle, not the price itself
    int recentLowIndex  = iLowest(Symbol(), 0, MODE_LOW, window1_length, window1_start);
    int olderLowIndex   = iLowest(Symbol(), 0, MODE_LOW, window2_length, window2_start);
    
    int recentHighIndex = iHighest(Symbol(), 0, MODE_HIGH, window1_length, window1_start);
    int olderHighIndex  = iHighest(Symbol(), 0, MODE_HIGH, window2_length, window2_start);

    // --- 3. Get the Stochastic Main Line values at those EXACT candle indexes ---
    // Using standard 5,3,3 scalping settings
    double stochRecentLow = iStochastic(Symbol(), 0, 5, 3, 3, MODE_SMA, 0, MODE_MAIN, recentLowIndex);
    double stochOlderLow  = iStochastic(Symbol(), 0, 5, 3, 3, MODE_SMA, 0, MODE_MAIN, olderLowIndex);
    
    double stochRecentHigh = iStochastic(Symbol(), 0, 5, 3, 3, MODE_SMA, 0, MODE_MAIN, recentHighIndex);
    double stochOlderHigh  = iStochastic(Symbol(), 0, 5, 3, 3, MODE_SMA, 0, MODE_MAIN, olderHighIndex);

    // --- 4. BULLISH DIVERGENCE LOGIC ---
    // Price makes a Lower Low, but Stochastic makes a Higher Low
    bool priceLowerLow = (Low[recentLowIndex] < Low[olderLowIndex]);
    bool stochHigherLow = (stochRecentLow > stochOlderLow);
    
    // Optional: Ensure this is happening in the oversold zone (< 20)
    bool isOversold = (stochRecentLow < 20);

    if (priceLowerLow && stochHigherLow && isOversold)
    {
        Print("Bullish Divergence Detected! Potential Buy Setup.");
        // Add your Buy Order logic here
    }

    // --- 5. BEARISH DIVERGENCE LOGIC ---
    // Price makes a Higher High, but Stochastic makes a Lower High
    bool priceHigherHigh = (High[recentHighIndex] > High[olderHighIndex]);
    bool stochLowerHigh = (stochRecentHigh < stochOlderHigh);
    
    // Optional: Ensure this is happening in the overbought zone (> 80)
    bool isOverbought = (stochRecentHigh > 80);

    if (priceHigherHigh && stochLowerHigh && isOverbought)
    {
        Print("Bearish Divergence Detected! Potential Sell Setup.");
        // Add your Sell Order logic here
    }
}

Re: How to detect divergence in forex scalping?

Posted: Tue Aug 11, 2026 5:18 pm
by FTtrader
Why This Method Works

The key to this code is how it uses ⁠iLowest()⁠ and ⁠iHighest()⁠.
Many beginners try to compare the Stochastic value right now to the Stochastic value 10 candles ago. That fails because the indicator might not have been peaking exactly 10 candles ago. By finding the exact candle index where price bottomed out (⁠recentLowIndex⁠), you can query the indicator at that precise moment in time to get an apples-to-apples comparison.

Re: How to detect divergence in forex scalping?

Posted: Tue Aug 11, 2026 5:21 pm
by FTtrader
Plus i think, that it could be cool, to draw series into charts, so this is even extended version.

(Please let me know, which one seems to be better for you)

To draw arrows on the chart, you bypass indicator buffers and directly interact with the MT4 chart engine using the ⁠ObjectCreate()⁠ function.

Since you are writing this as a function within an Expert Advisor, you must give every arrow a unique string ID. If you try to draw an arrow with a name that already exists, MT4 will ignore the command. The cleanest way to ensure uniqueness is by appending the exact candle timestamp (⁠Time[0]⁠) to the object name.

Here is the modified function with the object rendering logic injected directly into the buy and sell triggers:

Code: Select all

 //+------------------------------------------------------------------+
//| Divergence Detector for MQL4 (With Chart Arrows)                 |
//+------------------------------------------------------------------+
void CheckStochasticDivergence()
{
    // --- 1. Define our search windows ---
    int window1_start = 1;       
    int window1_length = 15;     
    
    int window2_start = 16;      
    int window2_length = 20;     
    
    // --- 2. Find the candle INDEX (shift) ---
    int recentLowIndex  = iLowest(Symbol(), 0, MODE_LOW, window1_length, window1_start);
    int olderLowIndex   = iLowest(Symbol(), 0, MODE_LOW, window2_length, window2_start);
    
    int recentHighIndex = iHighest(Symbol(), 0, MODE_HIGH, window1_length, window1_start);
    int olderHighIndex  = iHighest(Symbol(), 0, MODE_HIGH, window2_length, window2_start);

    // --- 3. Get the Stochastic Main Line values ---
    double stochRecentLow = iStochastic(Symbol(), 0, 5, 3, 3, MODE_SMA, 0, MODE_MAIN, recentLowIndex);
    double stochOlderLow  = iStochastic(Symbol(), 0, 5, 3, 3, MODE_SMA, 0, MODE_MAIN, olderLowIndex);
    
    double stochRecentHigh = iStochastic(Symbol(), 0, 5, 3, 3, MODE_SMA, 0, MODE_MAIN, recentHighIndex);
    double stochOlderHigh  = iStochastic(Symbol(), 0, 5, 3, 3, MODE_SMA, 0, MODE_MAIN, olderHighIndex);

    // --- 4. BULLISH DIVERGENCE LOGIC ---
    bool priceLowerLow = (Low[recentLowIndex] < Low[olderLowIndex]);
    bool stochHigherLow = (stochRecentLow > stochOlderLow);
    bool isOversold = (stochRecentLow < 20);

    if (priceLowerLow && stochHigherLow && isOversold)
    {
        // 1. Create a unique name using the current candle's timestamp
        string buyArrowName = "DivBuy_" + IntegerToString(Time[0]);
        
        // 2. Check if the object already exists to prevent duplicate drawing on the same candle
        if (ObjectFind(0, buyArrowName) < 0) 
        {
            // Draw an Up Arrow just below the current candle's low
            double drawPrice = Low[0] - (10 * Point); 
            
            ObjectCreate(0, buyArrowName, OBJ_ARROW_UP, 0, Time[0], drawPrice);
            ObjectSetInteger(0, buyArrowName, OBJPROP_COLOR, clrDodgerBlue); // Set color
            ObjectSetInteger(0, buyArrowName, OBJPROP_WIDTH, 3);             // Set size
            
            Print("Bullish Divergence Detected! Buy Arrow Drawn.");
        }
    }

    // --- 5. BEARISH DIVERGENCE LOGIC ---
    bool priceHigherHigh = (High[recentHighIndex] > High[olderHighIndex]);
    bool stochLowerHigh = (stochRecentHigh < stochOlderHigh);
    bool isOverbought = (stochRecentHigh > 80);

    if (priceHigherHigh && stochLowerHigh && isOverbought)
    {
        string sellArrowName = "DivSell_" + IntegerToString(Time[0]);
        
        if (ObjectFind(0, sellArrowName) < 0) 
        {
            // Draw a Down Arrow just above the current candle's high
            double drawPrice = High[0] + (10 * Point); 
            
            ObjectCreate(0, sellArrowName, OBJ_ARROW_DOWN, 0, Time[0], drawPrice);
            ObjectSetInteger(0, sellArrowName, OBJPROP_COLOR, clrCrimson);
            ObjectSetInteger(0, sellArrowName, OBJPROP_WIDTH, 3);
            
            Print("Bearish Divergence Detected! Sell Arrow Drawn.");
        }
    }
}

Re: How to detect divergence in forex scalping?

Posted: Tue Aug 11, 2026 5:22 pm
by FTtrader
And May be later we can try some of this visualisation tip ;-)

Visual Optimization Tips

Spacing the Arrows: The ⁠10 * Point⁠ math ensures the arrow hovers slightly away from the wick so it doesn't overlap the candlestick body. If you test this on a pair with high volatility (or JPY pairs where Pip scaling differs), you may want to adjust that multiplier.

Object Cleanup: Over days of running, this will spawn hundreds of objects on the chart. To prevent memory drag, it is best practice to include an ⁠ObjectsDeleteAll(0, "DivBuy_")⁠ and ⁠ObjectsDeleteAll(0, "DivSell_")⁠ command inside your EA's ⁠OnDeinit()⁠ function so the chart cleans itself up when you remove the robot.

Re: How to detect divergence in forex scalping?

Posted: Tue Aug 11, 2026 5:24 pm
by FTtrader
And for Meta trader 5 forex traders i prepared final code as well.

Moving from MQL4 to MQL5 requires a fundamental shift in architecture. MT4 creates indicator instances inline on every tick, whereas MT5 requires you to instantiate an indicator "handle" in ⁠OnInit()⁠ and then read from its buffer array.
Since MT5 also doesn't provide global ⁠High[]⁠, ⁠Low[]⁠, and ⁠Time[]⁠ arrays out of the box, we have to copy that data into our own arrays and reverse their indexing using ⁠ArraySetAsSeries()⁠ so they behave like MT4's right-to-left shift logic.

Here is the complete, modular translation for MT5.

Code: Select all

 //+------------------------------------------------------------------+
//| Global Variables                                                 |
//+------------------------------------------------------------------+
int stochHandle; // Handle for the Stochastic indicator

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
    // 1. Initialize the Stochastic handle (5, 3, 3, SMA, Low/High)
    stochHandle = iStochastic(_Symbol, _Period, 5, 3, 3, MODE_SMA, STO_LOWHIGH);
    
    if(stochHandle == INVALID_HANDLE) 
    {
        Print("Failed to create Stochastic handle");
        return INIT_FAILED;
    }
    
    return INIT_SUCCEEDED;
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    // Clean up memory and chart objects
    IndicatorRelease(stochHandle);
    ObjectsDeleteAll(0, "DivBuy_");
    ObjectsDeleteAll(0, "DivSell_");
}

//+------------------------------------------------------------------+
//| Divergence Detector for MQL5 (With Chart Arrows)                 |
//+------------------------------------------------------------------+
void CheckStochasticDivergence()
{
    // --- 1. Define our search windows ---
    int window1_start = 1;       
    int window1_length = 15;     
    
    int window2_start = 16;      
    int window2_length = 20;     
    
    int totalCopy = window2_start + window2_length;

    // --- 2. Initialize Arrays ---
    double lowArr[], highArr[], stochArr[];
    datetime timeArr[];

    // Flip arrays to behave like MT4 (Index 0 is current candle)
    ArraySetAsSeries(lowArr, true);
    ArraySetAsSeries(highArr, true);
    ArraySetAsSeries(timeArr, true);
    ArraySetAsSeries(stochArr, true);

    // --- 3. Copy Data to Arrays ---
    if (CopyLow(_Symbol, _Period, 0, totalCopy, lowArr) < totalCopy) return;
    if (CopyHigh(_Symbol, _Period, 0, totalCopy, highArr) < totalCopy) return;
    if (CopyTime(_Symbol, _Period, 0, totalCopy, timeArr) < totalCopy) return;
    
    // Copy Stochastic Main Line (Buffer 0)
    if (CopyBuffer(stochHandle, 0, 0, totalCopy, stochArr) < totalCopy) return;

    // --- 4. Find the candle INDEX (shift) ---
    // ArrayMinimum/ArrayMaximum returns the index of the highest/lowest value
    int recentLowIndex  = ArrayMinimum(lowArr, window1_start, window1_length);
    int olderLowIndex   = ArrayMinimum(lowArr, window2_start, window2_length);
    
    int recentHighIndex = ArrayMaximum(highArr, window1_start, window1_length);
    int olderHighIndex  = ArrayMaximum(highArr, window2_start, window2_length);

    // Safety check to prevent out-of-range errors
    if (recentLowIndex < 0 || olderLowIndex < 0 || recentHighIndex < 0 || olderHighIndex < 0) return;

    // --- 5. Get the Stochastic Main Line values ---
    double stochRecentLow = stochArr[recentLowIndex];
    double stochOlderLow  = stochArr[olderLowIndex];
    
    double stochRecentHigh = stochArr[recentHighIndex];
    double stochOlderHigh  = stochArr[olderHighIndex];

    // --- 6. BULLISH DIVERGENCE LOGIC ---
    bool priceLowerLow = (lowArr[recentLowIndex] < lowArr[olderLowIndex]);
    bool stochHigherLow = (stochRecentLow > stochOlderLow);
    bool isOversold = (stochRecentLow < 20);

    if (priceLowerLow && stochHigherLow && isOversold)
    {
        string buyArrowName = "DivBuy_" + IntegerToString(timeArr[0]);
        
        if (ObjectFind(0, buyArrowName) < 0) 
        {
            double drawPrice = lowArr[0] - (10 * _Point); 
            
            ObjectCreate(0, buyArrowName, OBJ_ARROW_UP, 0, timeArr[0], drawPrice);
            ObjectSetInteger(0, buyArrowName, OBJPROP_COLOR, clrDodgerBlue); 
            ObjectSetInteger(0, buyArrowName, OBJPROP_WIDTH, 3);             
            
            Print("Bullish Divergence Detected! Buy Arrow Drawn.");
        }
    }

    // --- 7. BEARISH DIVERGENCE LOGIC ---
    bool priceHigherHigh = (highArr[recentHighIndex] > highArr[olderHighIndex]);
    bool stochLowerHigh = (stochRecentHigh < stochOlderHigh);
    bool isOverbought = (stochRecentHigh > 80);

    if (priceHigherHigh && stochLowerHigh && isOverbought)
    {
        string sellArrowName = "DivSell_" + IntegerToString(timeArr[0]);
        
        if (ObjectFind(0, sellArrowName) < 0) 
        {
            double drawPrice = highArr[0] + (10 * _Point); 
            
            ObjectCreate(0, sellArrowName, OBJ_ARROW_DOWN, 0, timeArr[0], drawPrice);
            ObjectSetInteger(0, sellArrowName, OBJPROP_COLOR, clrCrimson);
            ObjectSetInteger(0, sellArrowName, OBJPROP_WIDTH, 3);
            
            Print("Bearish Divergence Detected! Sell Arrow Drawn.");
        }
    }
    
    // Force the chart to redraw immediately to show the new arrows
    ChartRedraw(0);
}

Re: How to detect divergence in forex scalping?

Posted: Tue Aug 11, 2026 5:25 pm
by FTtrader
Key Differences in MT5:

⁠IndicatorRelease()⁠: Always release indicator handles in ⁠OnDeinit()⁠, or memory leaks will pile up rapidly when backtesting or reloading the EA.

⁠ArrayMinimum()⁠ / ⁠ArrayMaximum()⁠: These replace ⁠iLowest()⁠ and ⁠iHighest()⁠. You pass the target array, the starting index, and how far back to look.

System Variables: Notice the underscore prefix (⁠_Symbol⁠, ⁠_Period⁠, ⁠_Point⁠). While MT5 still supports the old MT4 equivalents for backward compatibility, standard MQL5 uses the prefixed system variables.

⁠ChartRedraw(0)⁠: In MT5, graphical objects sometimes wait for the next chart tick to appear. Forcing a redraw at the end of the function ensures the arrow paints instantly.

Re: How to detect divergence in forex scalping?

Posted: Tue Aug 11, 2026 5:27 pm
by FTtrader
Here is implementation for Ctraders:

Moving this logic into cTrader is where you get to leave the clunky array handling of MQL behind. Because cTrader uses C# (.NET) and the cAlgo API, memory management is handled automatically, and drawing on charts is significantly cleaner.
The biggest shift from MQL is that cTrader doesn't have a direct native equivalent to ⁠iLowest()⁠ or ⁠iHighest()⁠.

However, because it's C#, we can easily write two quick helper methods using the ⁠DataSeries.Last(index)⁠ property, which perfectly mimics MT4's right-to-left "shift" indexing (where ⁠0⁠ is the current candle, ⁠1⁠ is the previous).
Here is the complete cBot implementation:

Code: Select all

 using System;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class StochasticDivergenceBot : Robot
    {
        [Parameter("K Period", DefaultValue = 5)]
        public int KPeriod { get; set; }

        [Parameter("D Period", DefaultValue = 3)]
        public int DPeriod { get; set; }

        [Parameter("Slowing", DefaultValue = 3)]
        public int Slowing { get; set; }

        private StochasticOscillator _stoch;

        protected override void OnStart()
        {
            // Initialize the Stochastic Indicator
            _stoch = Indicators.StochasticOscillator(KPeriod, Slowing, DPeriod, MovingAverageType.Simple);
        }

        protected override void OnBar()
        {
            // Running on candle close prevents false signals and repainting
            CheckDivergence();
        }

        private void CheckDivergence()
        {
            // --- 1. Define our search windows ---
            int window1Start = 1;
            int window1Length = 15;

            int window2Start = 16;
            int window2Length = 20;

            // --- 2. Find the shift (bars ago) of the highs and lows ---
            int recentLowShift = GetLowestShift(Bars.LowPrices, window1Start, window1Length);
            int olderLowShift = GetLowestShift(Bars.LowPrices, window2Start, window2Length);

            int recentHighShift = GetHighestShift(Bars.HighPrices, window1Start, window1Length);
            int olderHighShift = GetHighestShift(Bars.HighPrices, window2Start, window2Length);

            // --- 3. Get Stochastic PercentK (Main Line) at those exact shifts ---
            double stochRecentLow = _stoch.PercentK.Last(recentLowShift);
            double stochOlderLow = _stoch.PercentK.Last(olderLowShift);

            double stochRecentHigh = _stoch.PercentK.Last(recentHighShift);
            double stochOlderHigh = _stoch.PercentK.Last(olderHighShift);

            // --- 4. BULLISH DIVERGENCE LOGIC ---
            bool priceLowerLow = Bars.LowPrices.Last(recentLowShift) < Bars.LowPrices.Last(olderLowShift);
            bool stochHigherLow = stochRecentLow > stochOlderLow;
            bool isOversold = stochRecentLow < 20;

            if (priceLowerLow && stochHigherLow && isOversold)
            {
                // Create unique ID for the arrow using the candle's open time
                string arrowName = "DivBuy_" + Bars.OpenTimes.Last(0).ToString("yyyyMMddHHmmss");
                
                // Position the arrow 10 pips below the low
                double drawPrice = Bars.LowPrices.Last(0) - (10 * Symbol.PipSize);
                
                Chart.DrawIcon(arrowName, ChartIconType.UpArrow, Bars.OpenTimes.Last(0), drawPrice, Color.DodgerBlue);
                Print("Bullish Divergence Detected! Buy Arrow Drawn.");
            }

            // --- 5. BEARISH DIVERGENCE LOGIC ---
            bool priceHigherHigh = Bars.HighPrices.Last(recentHighShift) > Bars.HighPrices.Last(olderHighShift);
            bool stochLowerHigh = stochRecentHigh < stochOlderHigh;
            bool isOverbought = stochRecentHigh > 80;

            if (priceHigherHigh && stochLowerHigh && isOverbought)
            {
                string arrowName = "DivSell_" + Bars.OpenTimes.Last(0).ToString("yyyyMMddHHmmss");
                double drawPrice = Bars.HighPrices.Last(0) + (10 * Symbol.PipSize);
                
                Chart.DrawIcon(arrowName, ChartIconType.DownArrow, Bars.OpenTimes.Last(0), drawPrice, Color.Crimson);
                Print("Bearish Divergence Detected! Sell Arrow Drawn.");
            }
        }

        // --- Helper Methods to Replace MQL's iLowest and iHighest ---

        private int GetLowestShift(DataSeries series, int startShift, int length)
        {
            int lowestShift = startShift;
            double lowestValue = double.MaxValue;

            for (int i = startShift; i < startShift + length; i++)
            {
                if (series.Last(i) < lowestValue)
                {
                    lowestValue = series.Last(i);
                    lowestShift = i; // Store the shift index, not the price
                }
            }
            return lowestShift;
        }

        private int GetHighestShift(DataSeries series, int startShift, int length)
        {
            int highestShift = startShift;
            double highestValue = double.MinValue;

            for (int i = startShift; i < startShift + length; i++)
            {
                if (series.Last(i) > highestValue)
                {
                    highestValue = series.Last(i);
                    highestShift = i;
                }
            }
            return highestShift;
        }
    }
}

Re: How to detect divergence in forex scalping?

Posted: Tue Aug 11, 2026 5:27 pm
by FTtrader
Key Upgrades in cTrader (C#)

Chart.DrawIcon()⁠: This replaces MT4's verbose ⁠ObjectCreate()⁠ syntax. cTrader's engine automatically handles the sizing and scaling of the icon based on your zoom level, so you don't need to manually define the line width.

⁠Symbol.PipSize⁠: Instead of MQL's raw ⁠Point⁠ value, cTrader intelligently handles pip sizing natively, making your draw offsets (like ⁠10 * Symbol.PipSize⁠) consistent across JPY pairs, indices, and standard currency pairs.

Garbage Collection: You do not need to call ⁠IndicatorRelease⁠ or delete objects in an ⁠OnDeinit()⁠ function. The .NET garbage collector handles the indicator instance, and drawn icons can be managed natively through cTrader's visual object manager.

Re: How to detect divergence in forex scalping?

Posted: Tue Aug 11, 2026 5:29 pm
by FTtrader
Finally here is implementaiton in pine script for trading view traders:

Pine Script v5 makes this significantly cleaner than MQL or C#. Because TradingView executes on a series-based execution model, you don't need manual memory cleanup, custom low/high loops, or object creation functions.
Instead, built-in functions like ⁠ta.lowestbars()⁠ and ⁠plotshape()⁠ handle window lookbacks and chart rendering natively.
Here is the full Pine Script v5 indicator code designed to run directly as an overlay on the main chart:

Code: Select all

 //@version=5
indicator("Stochastic Divergence Detector", overlay=true)

// --- Inputs ---
kPeriod   = input.int(5, title="%K Period", group="Stochastic Settings")
dPeriod   = input.int(3, title="%D Period", group="Stochastic Settings")
slowing   = input.int(3, title="Slowing", group="Stochastic Settings")

w1_length = input.int(15, title="Window 1 Length (Recent)", group="Divergence Windows")
w2_start  = input.int(16, title="Window 2 Start Shift", group="Divergence Windows")
w2_length = input.int(20, title="Window 2 Length (Older)", group="Divergence Windows")

// --- Stochastic Calculation ---
// ta.stoch returns raw %K; ta.sma applies the Slowing smoothing
stochK = ta.sma(ta.stoch(close, high, low, kPeriod), slowing)

// --- Window Lookbacks ---
// ta.lowestbars/highestbars return a negative bar index offset relative to the series offset
shiftRecentLow = 1 - ta.lowestbars(low[1], w1_length)
shiftOlderLow  = w2_start - ta.lowestbars(low[w2_start], w2_length)

shiftRecentHigh = 1 - ta.highestbars(high[1], w1_length)
shiftOlderHigh  = w2_start - ta.highestbars(high[w2_start], w2_length)

// --- Extract Price & Stochastic Values at Exact Bar Shifts ---
priceRecentLow  = low[shiftRecentLow]
priceOlderLow   = low[shiftOlderLow]
stochRecentLow  = stochK[shiftRecentLow]
stochOlderLow   = stochK[shiftOlderLow]

priceRecentHigh = high[shiftRecentHigh]
priceOlderHigh  = high[shiftOlderHigh]
stochRecentHigh = stochK[shiftRecentHigh]
stochOlderHigh  = stochK[shiftOlderHigh]

// --- Divergence Logic ---
bullDivergence = (priceRecentLow < priceOlderLow) and (stochRecentLow > stochOlderLow) and (stochRecentLow < 20)
bearDivergence = (priceRecentHigh > priceOlderHigh) and (stochRecentHigh < stochOlderHigh) and (stochRecentHigh > 80)

// --- Plot Signals on Chart ---
plotshape(bullDivergence, title="Bullish Divergence", style=shape.arrowup, location=location.belowbar, color=color.new(#1E90FF, 0), size=size.normal)
plotshape(bearDivergence, title="Bearish Divergence", style=shape.arrowdown, location=location.abovebar, color=color.new(#FF1493, 0), size=size.normal)

// --- Webhooks & Alerts Setup ---
alertcondition(bullDivergence, title="Bullish Divergence Alert", message="Stochastic Bullish Divergence on {{ticker}} ({{interval}})")
alertcondition(bearDivergence, title="Bearish Divergence Alert", message="Stochastic Bearish Divergence on {{ticker}} ({{interval}})")