RSI Divergence
Python Programming
Technical Analysis
Stock Market
Trading Algorithms

How to implement RSI Divergence in Python

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

RSI divergence is a pattern where price and momentum stop agreeing. A bullish setup appears when price makes a lower low while RSI makes a higher low, and a bearish setup appears when price makes a higher high while RSI makes a lower high.

Compute RSI first

Before you can detect divergence, you need a reliable RSI series. The example below uses pandas and Wilder-style smoothing with ewm, which is a practical approach for backtesting and chart analysis.

python
1import pandas as pd
2
3
4def compute_rsi(close: pd.Series, period: int = 14) -> pd.Series:
5    delta = close.diff()
6    gain = delta.clip(lower=0)
7    loss = -delta.clip(upper=0)
8
9    avg_gain = gain.ewm(alpha=1 / period, adjust=False, min_periods=period).mean()
10    avg_loss = loss.ewm(alpha=1 / period, adjust=False, min_periods=period).mean()
11
12    rs = avg_gain / avg_loss
13    rsi = 100 - (100 / (1 + rs))
14    return rsi

This function expects a Series of closing prices. The first period rows will be NaN, which is normal because RSI needs historical data before it can produce a stable value.

Find swing highs and swing lows

Divergence is based on pivots, not on every single candle. A simple way to detect pivots is to compare each value with a small window around it.

python
1def pivot_lows(series: pd.Series, window: int = 3) -> list[int]:
2    lows = []
3    for i in range(window, len(series) - window):
4        segment = series.iloc[i - window : i + window + 1]
5        if series.iloc[i] == segment.min():
6            lows.append(i)
7    return lows
8
9
10def pivot_highs(series: pd.Series, window: int = 3) -> list[int]:
11    highs = []
12    for i in range(window, len(series) - window):
13        segment = series.iloc[i - window : i + window + 1]
14        if series.iloc[i] == segment.max():
15            highs.append(i)
16    return highs

This method is intentionally simple. It works well for illustrating the idea, and it is good enough for many research scripts. In production trading systems, you may want stricter pivot rules or a confirmation delay so the signal does not repaint as the most recent candles move.

Detect bullish and bearish divergence

Now compare the last two relevant pivots in price with the RSI values at those same pivot indexes.

python
1def find_divergences(close: pd.Series, rsi: pd.Series, window: int = 3) -> dict[str, list[tuple[int, int]]]:
2    lows = pivot_lows(close, window)
3    highs = pivot_highs(close, window)
4
5    bullish = []
6    bearish = []
7
8    for first, second in zip(lows, lows[1:]):
9        if close.iloc[second] < close.iloc[first] and rsi.iloc[second] > rsi.iloc[first]:
10            bullish.append((first, second))
11
12    for first, second in zip(highs, highs[1:]):
13        if close.iloc[second] > close.iloc[first] and rsi.iloc[second] < rsi.iloc[first]:
14            bearish.append((first, second))
15
16    return {"bullish": bullish, "bearish": bearish}

Here is a full runnable example with sample data:

python
1import pandas as pd
2
3prices = pd.Series(
4    [100, 98, 96, 95, 97, 99, 94, 92, 93, 95, 97, 99, 101, 100, 102, 104, 103, 105]
5)
6
7rsi = compute_rsi(prices, period=5)
8signals = find_divergences(prices, rsi, window=2)
9
10print("Bullish divergences:", signals["bullish"])
11print("Bearish divergences:", signals["bearish"])
12print(pd.DataFrame({"close": prices, "rsi": rsi.round(2)}))

The output is a list of index pairs. Each pair marks the first and second pivot that formed the divergence. In a charting application, you would use those indexes to draw lines between price pivots and RSI pivots.

Make the signal usable

A divergence signal by itself is usually not enough for a trade. Most traders add one more filter, such as trend direction, volume confirmation, or a support and resistance check. Even a simple rule like "only take bullish divergence above a long-term moving average" can eliminate many weak setups.

If you want to backtest this properly, store signals in a DataFrame with timestamps, entry rules, exit rules, and stop placement. That makes the script measurable instead of just visually interesting.

Common Pitfalls

The most common error is comparing arbitrary local points instead of confirmed pivots. That creates many false positives because every small wiggle starts to look like divergence.

Another mistake is using RSI values before the indicator is warmed up. Early NaN rows or unstable initial values can distort the first few comparisons.

Window size matters too. A very small window finds too many pivots, while a very large window misses useful signals. Test a few values against the timeframe you trade instead of assuming one setting fits every market.

Finally, do not treat divergence as a guaranteed reversal. Strong trends can keep moving against a divergence for a long time, so risk management still matters.

Summary

  • Compute RSI on a clean closing-price series before looking for patterns.
  • Detect divergence from pivot highs and pivot lows, not from every bar.
  • Bullish divergence means lower price lows with higher RSI lows.
  • Bearish divergence means higher price highs with lower RSI highs.
  • Add confirmation and backtesting before using divergence in a live strategy.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.