Detecting RSI Divergence in Pine Script

This lesson demonstrates how to detect RSI divergence in Pine Script. This method can also be used for other oscillators, such as MACD, Stochastics and even On Balance Volume with some minor modifications.

Check out my other free lessons!

Source Code

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © ZenAndTheArtOfTrading / www.PineScriptMastery.com
// @version=5
indicator("Pine-Script.com: RSI Divergence", overlay=true)

// Get user input
int i_MaxDistance       = input.int(title="Max Bar Distance", defval=50)
int i_RSI_Length        = input.int(title="RSI Length", defval=14, minval=1)
float i_RSI_Overbought  = input.float(title="RSI Overbought", defval=70.0)
float i_RSI_Oversold    = input.float(title="RSI Oversold", defval=30.0)

// Get RSI value
rsiValue = ta.rsi(close, i_RSI_Length)

// --------- BULLISH DIVERGENCE --------- //
var float checkFirstLow     = na
var float initialLowPrice   = na
var float initialLowRSI     = na
var int initialLowIndex     = na
bool bullishDivergence      = false
float swingLowRSI           = ta.lowest(rsiValue, 5)

// Save lowest low while RSI is oversold, and store it when market leaves OS condition
if (rsiValue < i_RSI_Oversold or rsiValue[1] < i_RSI_Oversold)
    if not na(initialLowPrice)
        initialLowPrice := na
    if na(checkFirstLow) or low < checkFirstLow
        checkFirstLow := low
        initialLowIndex := bar_index
        initialLowRSI := swingLowRSI
else
    // RSI is no longer OS, save lowest price during OS condition and reset temporary low
    if not na(checkFirstLow)
        initialLowPrice := checkFirstLow
    checkFirstLow := na

// Check for a second low that is lower than the first, and with a higher RSI value, and within our max distance
if low[1] < initialLowPrice and low > low[1] and swingLowRSI > initialLowRSI and bar_index - initialLowIndex <= i_MaxDistance
    bullishDivergence := true
    line.new(initialLowIndex, initialLowPrice, bar_index - 1, low[1], color=color.green, width=2)
    initialLowPrice := na

// Draw bearish divergence signal
plotshape(bullishDivergence, "Bullish Divergence", shape.triangleup, location.belowbar, color.green)

// --------- BEARISH DIVERGENCE --------- //
var float checkFirstHigh    = na
var float initialHighPrice  = na
var float initialHighRSI    = na
var int initialHighIndex    = na
bool bearishDivergence      = false
float swingHighRSI          = ta.highest(rsiValue, 5)

// Save highest high while RSI is overbought, and store it when market leaves OB condition
if (rsiValue > i_RSI_Overbought or rsiValue[1] > i_RSI_Overbought)
    if not na(initialHighPrice)
        initialHighPrice := na
    if na(checkFirstHigh) or high > checkFirstHigh
        checkFirstHigh := high
        initialHighIndex := bar_index
        initialHighRSI := swingHighRSI
else
    // RSI is no longer OB, save highest price during OB condition and reset temporary high
    if not na(checkFirstHigh)
        initialHighPrice := checkFirstHigh
    checkFirstHigh := na

// Check for a second high that is higher than the first, and with a lower RSI value, and within our max distance
if high[1] > initialHighPrice and high < high[1] and swingHighRSI < initialHighRSI and bar_index - initialHighIndex <= i_MaxDistance
    bearishDivergence := true
    line.new(initialHighIndex, initialHighPrice, bar_index - 1, high[1], color=color.red, width=2)
    initialHighPrice := na

// Draw bearish divergence signal
plotshape(bearishDivergence, "Bearish Divergence", shape.triangledown, location.abovebar, color.red)

// --------- ALERTS --------- //
if bearishDivergence
    alert("Bearish RSI Divergence Detected - RSI Difference:" + str.tostring(initialHighRSI - swingHighRSI, "#.##"), alert.freq_once_per_bar_close)
if bullishDivergence
    alert("Bullish RSI Divergence Detected - RSI Difference:" + str.tostring(swingLowRSI - initialLowRSI, "#.##"), alert.freq_once_per_bar_close)
alertcondition(bearishDivergence, "RSI Bearish Divergence", "RSI Bearish Divergence Detected")
alertcondition(bullishDivergence, "RSI Bullish Divergence", "RSI Bullish Divergence Detected")