Indicator · Pine Script v4 · On the chart

RSI/Stoch/BB/Divs (Brahim)

by bfoura· code credited to dolan_0x

This indicator detects regular and hidden divergences across multiple technical oscillators, including MACD, RSI, Stochastic, CCI, Momentum, OBV, CMF, and MFI.

View on GitHub

GitHub stars4on the repository
Pine versionv4older, still runs
Lines of code534
Settings40inputs
LicenceNone statedfile: MPL-2.0
Last update4 years ago15 Oct 2022

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new indicator, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart, then adjust the settings with the gear icon next to its name.

Source Code

534 lines of Pine Script v4 from combined_studies/v4/rsi_stoch_bb_divs.pine, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.

rsi_stoch_bb_divs.pine
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © dolan_0x

//@version=4
study(title="RSI/Stoch/BB/Divs (Brahim)", shorttitle="RSI/Stoch Signal", overlay=true)

// Divergences

prd = input(defval = 5, title = "Pivot Period", minval = 1, maxval = 50)
source = input(defval = "Close", title = "Source for Pivot Points", options = ["Close", "High/Low"])
searchdiv = input(defval = "Regular", title = "Divergence Type", options = ["Regular", "Hidden", "Regular/Hidden"])
showindis = input(defval = "Full", title = "Show Indicator Names", options = ["Full", "First Letter", "Don't Show"])
showlimit = input(1, title="Minimum Number of Divergence", minval = 1, maxval = 11)
maxpp = input(defval = 10, title = "Maximum Pivot Points to Check", minval = 1, maxval = 20)
maxbars = input(defval = 100, title = "Maximum Bars to Check", minval = 30, maxval = 200)
shownum = input(defval = true, title = "Show Divergence Number")
showlast = input(defval = false, title = "Show Only Last Divergence")
dontconfirm = input(defval = false, title = "Don't Wait for Confirmation")
showlines = input(defval = true, title = "Show Divergence Lines")
showpivot = input(defval = false, title = "Show Pivot Points")
calcmacd = input(defval = true, title = "MACD")
calcmacda = input(defval = true, title = "MACD Histogram")
calcrsi = input(defval = true, title = "RSI")
calcstoc = input(defval = true, title = "Stochastic")
calccci = input(defval = false, title = "CCI")
calcmom = input(defval = false, title = "Momentum")
calcobv = input(defval = false, title = "OBV")
calcvwmacd = input(false, title = "VWmacd")
calccmf = input(false, title = "Chaikin Money Flow")
calcmfi = input(false, title = "Money Flow Index")
calcext = input(false, title = "Check External Indicator")
externalindi = input(defval = close, title = "External Indicator")
pos_reg_div_col = input(defval = color.yellow, title = "Positive Regular Divergence")
neg_reg_div_col = input(defval = color.navy, title = "Negative Regular Divergence")
pos_hid_div_col = input(defval = color.lime, title = "Positive Hidden Divergence")
neg_hid_div_col = input(defval = color.red, title = "Negative Hidden Divergence")
pos_div_text_col = input(defval = color.black, title = "Positive Divergence Text Color")
neg_div_text_col = input(defval = color.white, title = "Negative Divergence Text Color")
reg_div_l_style_ = input(defval = "Solid", title = "Regular Divergence Line Style", options = ["Solid", "Dashed", "Dotted"])
hid_div_l_style_ = input(defval = "Dashed", title = "Hdden Divergence Line Style", options = ["Solid", "Dashed", "Dotted"])
reg_div_l_width = input(defval = 2, title = "Regular Divergence Line Width", minval = 1, maxval = 5)
hid_div_l_width = input(defval = 1, title = "Hidden Divergence Line Width", minval = 1, maxval = 5)
showmas = input(defval = false, title = "Show MAs 50 & 200", inline = "ma12")
cma1col = input(defval = color.lime, title = "", inline = "ma12")
cma2col = input(defval = color.red, title = "", inline = "ma12")

plot(showmas ? sma(close, 50) : na, color = showmas ? cma1col : na)
plot(showmas ? sma(close, 200) : na, color = showmas ? cma2col: na)

// set line styles
var reg_div_l_style = reg_div_l_style_ == "Solid" ? line.style_solid : 
                       reg_div_l_style_ == "Dashed" ? line.style_dashed :
                       line.style_dotted
var hid_div_l_style = hid_div_l_style_ == "Solid" ? line.style_solid : 
                       hid_div_l_style_ == "Dashed" ? line.style_dashed :
                       line.style_dotted


// get indicators
rsi = rsi(close, 14) // RSI
[macd, signal, deltamacd] = macd(close, 12, 26, 9) // MACD
moment = mom(close, 10) // Momentum
cci = cci(close, 10) // CCI
Obv = obv // OBV
stk = sma(stoch(close, high, low, 14), 3) // Stoch
maFast = vwma(close, 12), maSlow = vwma(close, 26), vwmacd = maFast - maSlow // volume weighted macd
Cmfm = ((close-low) - (high-close)) / (high - low), Cmfv = Cmfm * volume, cmf = sma(Cmfv, 21) / sma(volume,21) // Chaikin money flow
Mfi = mfi(close, 14) // Moneyt Flow Index

// keep indicators names and colors in arrays
var indicators_name = array.new_string(11)
var div_colors = array.new_color(4)
if barstate.isfirst
    // names
    array.set(indicators_name, 0, showindis == "Full" ? "MACD" : "M")
    array.set(indicators_name, 1, showindis == "Full" ? "Hist" : "H")
    array.set(indicators_name, 2, showindis == "Full" ? "RSI" : "E")
    array.set(indicators_name, 3, showindis == "Full" ? "Stoch" : "S")
    array.set(indicators_name, 4, showindis == "Full" ? "CCI" : "C")
    array.set(indicators_name, 5, showindis == "Full" ? "MOM" : "M")
    array.set(indicators_name, 6, showindis == "Full" ? "OBV" : "O")
    array.set(indicators_name, 7, showindis == "Full" ? "VWMACD" : "V")
    array.set(indicators_name, 8, showindis == "Full" ? "CMF" : "C")
    array.set(indicators_name, 9, showindis == "Full" ? "MFI" : "M")
    array.set(indicators_name,10, showindis == "Full" ? "Extrn" : "X")
    //colors
    array.set(div_colors, 0, pos_reg_div_col)
    array.set(div_colors, 1, neg_reg_div_col)
    array.set(div_colors, 2, pos_hid_div_col)
    array.set(div_colors, 3, neg_hid_div_col)

// Check if we get new Pivot High Or Pivot Low
float ph = pivothigh((source == "Close" ? close : high), prd, prd)
float pl = pivotlow((source == "Close" ? close : low), prd, prd)
plotshape(ph and showpivot, text = "H",  style = shape.labeldown, color = color.new(color.white, 100), textcolor = color.red, location = location.abovebar, offset = -prd)
plotshape(pl and showpivot, text = "L",  style = shape.labelup, color = color.new(color.white, 100), textcolor = color.lime, location = location.belowbar, offset = -prd)

// keep values and positions of Pivot Highs/Lows in the arrays
var int maxarraysize = 20
var ph_positions = array.new_int(maxarraysize, 0)
var pl_positions = array.new_int(maxarraysize, 0)
var ph_vals = array.new_float(maxarraysize, 0.)
var pl_vals = array.new_float(maxarraysize, 0.)

// add PHs to the array
if ph
    array.unshift(ph_positions, bar_index)
    array.unshift(ph_vals, ph)
    if array.size(ph_positions) > maxarraysize
        array.pop(ph_positions)
        array.pop(ph_vals)

// add PLs to the array
if pl
    array.unshift(pl_positions, bar_index)
    array.unshift(pl_vals, pl)
    if array.size(pl_positions) > maxarraysize
        array.pop(pl_positions)
        array.pop(pl_vals)

// functions to check Regular Divergences and Hidden Divergences

// function to check positive regular or negative hidden divergence
// cond == 1 => positive_regular, cond == 2=> negative_hidden
positive_regular_positive_hidden_divergence(src, cond)=>
    divlen = 0
    prsc = source == "Close" ? close : low
    // if indicators higher than last value and close price is higher than las close 
    if dontconfirm or src > src[1] or close > close[1]
        startpoint = dontconfirm ? 0 : 1 // don't check last candle
        // we search last 15 PPs
        for x = 0 to maxpp - 1
            len = bar_index - array.get(pl_positions, x) + prd
            // if we reach non valued array element or arrived 101. or previous bars then we don't search more
            if array.get(pl_positions, x) == 0 or len > maxbars
                break
            if len > 5 and 
               ((cond == 1 and src[startpoint] > src[len] and prsc[startpoint] < nz(array.get(pl_vals, x))) or
               (cond == 2 and src[startpoint] < src[len] and prsc[startpoint] > nz(array.get(pl_vals, x))))
                slope1 = (src[startpoint] - src[len]) / (len - startpoint)
                virtual_line1 = src[startpoint] - slope1
                slope2 = (close[startpoint] - close[len]) / (len - startpoint)
                virtual_line2 = close[startpoint] - slope2
                arrived = true
                for y = 1 + startpoint to len - 1
                    if src[y] < virtual_line1 or nz(close[y]) < virtual_line2
                        arrived := false
                        break
                    virtual_line1 := virtual_line1 - slope1
                    virtual_line2 := virtual_line2 - slope2
                
                if arrived
                    divlen := len
                    break
    divlen

// function to check negative regular or positive hidden divergence
// cond == 1 => negative_regular, cond == 2=> positive_hidden
negative_regular_negative_hidden_divergence(src, cond)=>
    divlen = 0
    prsc = source == "Close" ? close : high
    // if indicators higher than last value and close price is higher than las close 
    if dontconfirm or src < src[1] or close < close[1]
        startpoint = dontconfirm ? 0 : 1 // don't check last candle
        // we search last 15 PPs
        for x = 0 to maxpp - 1
            len = bar_index - array.get(ph_positions, x) + prd
            // if we reach non valued array element or arrived 101. or previous bars then we don't search more
            if array.get(ph_positions, x) == 0 or len > maxbars
                break
            if len > 5 and 
               ((cond == 1 and src[startpoint] < src[len] and prsc[startpoint] > nz(array.get(ph_vals, x))) or 
               (cond == 2 and src[startpoint] > src[len] and prsc[startpoint] < nz(array.get(ph_vals, x))))
                slope1 = (src[startpoint] - src[len]) / (len - startpoint)
                virtual_line1 = src[startpoint] - slope1
                slope2 = (close[startpoint] - nz(close[len])) / (len - startpoint)
                virtual_line2 = close[startpoint] - slope2
                arrived = true
                for y = 1 + startpoint to len - 1
                    if src[y] > virtual_line1 or nz(close[y]) > virtual_line2
                        arrived := false
                        break
                    virtual_line1 := virtual_line1 - slope1
                    virtual_line2 := virtual_line2 - slope2
                
                if arrived
                    divlen := len
                    break
    divlen

// calculate 4 types of divergence if enabled in the options and return divergences in an array
calculate_divs(cond, indicator)=>
    divs = array.new_int(4, 0)
    array.set(divs, 0, cond and (searchdiv == "Regular" or searchdiv == "Regular/Hidden") ? positive_regular_positive_hidden_divergence(indicator, 1) : 0)
    array.set(divs, 1, cond and (searchdiv == "Regular" or searchdiv == "Regular/Hidden") ? negative_regular_negative_hidden_divergence(indicator, 1) : 0)
    array.set(divs, 2, cond and (searchdiv == "Hidden" or searchdiv == "Regular/Hidden")  ? positive_regular_positive_hidden_divergence(indicator, 2) : 0)
    array.set(divs, 3, cond and (searchdiv == "Hidden" or searchdiv == "Regular/Hidden")  ? negative_regular_negative_hidden_divergence(indicator, 2) : 0)
    divs

// array to keep all divergences
var all_divergences = array.new_int(44) // 11 indicators * 4 divergence = 44 elements
// set related array elements
array_set_divs(div_pointer, index)=>
    for x = 0 to 3
        array.set(all_divergences, index * 4 + x, array.get(div_pointer, x))

// set divergences array 
array_set_divs(calculate_divs(calcmacd, macd), 0)
array_set_divs(calculate_divs(calcmacda, deltamacd), 1)
array_set_divs(calculate_divs(calcrsi, rsi), 2)
array_set_divs(calculate_divs(calcstoc, stk), 3)
array_set_divs(calculate_divs(calccci, cci), 4)
array_set_divs(calculate_divs(calcmom, moment), 5)
array_set_divs(calculate_divs(calcobv, Obv), 6)
array_set_divs(calculate_divs(calcvwmacd, vwmacd), 7)
array_set_divs(calculate_divs(calccmf, cmf), 8)
array_set_divs(calculate_divs(calcmfi, Mfi), 9)
array_set_divs(calculate_divs(calcext, externalindi), 10)

// check minimum number of divergence, if less than showlimit then delete all divergence
total_div = 0
for x = 0 to array.size(all_divergences) - 1
    total_div := total_div + round(sign(array.get(all_divergences, x)))

if total_div < showlimit
    array.fill(all_divergences, 0)

// keep line in an array
var pos_div_lines = array.new_line(0)
var neg_div_lines = array.new_line(0)
var pos_div_labels = array.new_label(0)
var neg_div_labels = array.new_label(0) 

// remove old lines and labels if showlast option is enabled
delete_old_pos_div_lines()=>
    if array.size(pos_div_lines) > 0    
        for j = 0 to array.size(pos_div_lines) - 1 
            line.delete(array.get(pos_div_lines, j))
        array.clear(pos_div_lines)

delete_old_neg_div_lines()=>
    if array.size(neg_div_lines) > 0    
        for j = 0 to array.size(neg_div_lines) - 1 
            line.delete(array.get(neg_div_lines, j))
        array.clear(neg_div_lines)

delete_old_pos_div_labels()=>
    if array.size(pos_div_labels) > 0 
        for j = 0 to array.size(pos_div_labels) - 1 
            label.delete(array.get(pos_div_labels, j))
        array.clear(pos_div_labels)

delete_old_neg_div_labels()=>
    if array.size(neg_div_labels) > 0    
        for j = 0 to array.size(neg_div_labels) - 1 
            label.delete(array.get(neg_div_labels, j))
        array.clear(neg_div_labels)

// delete last created lines and labels until we met new PH/PV 
delete_last_pos_div_lines_label(n)=>
    if n > 0 and array.size(pos_div_lines) >= n    
        asz = array.size(pos_div_lines)
        for j = 1 to n
            line.delete(array.get(pos_div_lines, asz - j))
            array.pop(pos_div_lines)
        if array.size(pos_div_labels) > 0  
            label.delete(array.get(pos_div_labels, array.size(pos_div_labels) - 1))
            array.pop(pos_div_labels)

delete_last_neg_div_lines_label(n)=>
    if n > 0 and array.size(neg_div_lines) >= n    
        asz = array.size(neg_div_lines)
        for j = 1 to n
            line.delete(array.get(neg_div_lines, asz - j))
            array.pop(neg_div_lines)
        if array.size(neg_div_labels) > 0  
            label.delete(array.get(neg_div_labels, array.size(neg_div_labels) - 1))
            array.pop(neg_div_labels)
            
// variables for Alerts
pos_reg_div_detected = false
neg_reg_div_detected = false
pos_hid_div_detected = false
neg_hid_div_detected = false

// to remove lines/labels until we met new // PH/PL
var last_pos_div_lines = 0
var last_neg_div_lines = 0
var remove_last_pos_divs = false 
var remove_last_neg_divs = false
if pl
    remove_last_pos_divs := false
    last_pos_div_lines := 0
if ph
    remove_last_neg_divs := false
    last_neg_div_lines := 0

// draw divergences lines and labels
divergence_text_top = ""
divergence_text_bottom = ""
distances = array.new_int(0)
dnumdiv_top = 0
dnumdiv_bottom = 0
top_label_col = color.white
bottom_label_col = color.white
old_pos_divs_can_be_removed = true
old_neg_divs_can_be_removed = true
startpoint = dontconfirm ? 0 : 1 // used for don't confirm option

removed_unconfirmed_neg_div = false
removed_unconfirmed_pos_div = false

for x = 0 to 10
    div_type = -1
    for y = 0 to 3
        if array.get(all_divergences, x * 4 + y) > 0 // any divergence?
            div_type := y
            if (y % 2) == 1 
                dnumdiv_top := dnumdiv_top + 1
                top_label_col := array.get(div_colors, y)
            if (y % 2) == 0
                dnumdiv_bottom := dnumdiv_bottom + 1
                bottom_label_col := array.get(div_colors, y)
            if not array.includes(distances, array.get(all_divergences, x * 4 + y))  // line not exist ?
                array.push(distances, array.get(all_divergences, x * 4 + y))
                new_line = showlines ? line.new(x1 = bar_index - array.get(all_divergences, x * 4 + y), 
                          y1 = (source == "Close" ? close[array.get(all_divergences, x * 4 + y)] : 
                                           (y % 2) == 0 ? low[array.get(all_divergences, x * 4 + y)] : 
                                                          high[array.get(all_divergences, x * 4 + y)]),
                          x2 = bar_index - startpoint,
                          y2 = (source == "Close" ? close[startpoint] : 
                                           (y % 2) == 0 ? low[startpoint] : 
                                                          high[startpoint]),
                          color = array.get(div_colors, y),
                          style = y < 2 ? reg_div_l_style : hid_div_l_style,
                          width = y < 2 ? reg_div_l_width : hid_div_l_width
                          )
                          : na
                if (y % 2) == 0
                    if old_pos_divs_can_be_removed
                        old_pos_divs_can_be_removed := false
                        if not showlast and remove_last_pos_divs
                            delete_last_pos_div_lines_label(last_pos_div_lines)
                            last_pos_div_lines := 0
                        if showlast
                            delete_old_pos_div_lines()
                    array.push(pos_div_lines, new_line)
                    last_pos_div_lines := last_pos_div_lines + 1
                    remove_last_pos_divs := true
                    
                if (y % 2) == 1
                    if old_neg_divs_can_be_removed
                        old_neg_divs_can_be_removed := false
                        if not showlast and remove_last_neg_divs
                            delete_last_neg_div_lines_label(last_neg_div_lines)
                            last_neg_div_lines := 0
                            removed_unconfirmed_neg_div := true
                        if showlast
                            delete_old_neg_div_lines()
                    array.push(neg_div_lines, new_line)
                    last_neg_div_lines := last_neg_div_lines + 1
                    remove_last_neg_divs := true
                    
            // set variables for alerts
            if y == 0
                pos_reg_div_detected := true
            if y == 1
                neg_reg_div_detected := true
            if y == 2
                pos_hid_div_detected := true
            if y == 3
                neg_hid_div_detected := true
    // get text for labels
    if div_type >= 0
        divergence_text_top    := divergence_text_top    + ((div_type % 2) == 1 ? (showindis != "Don't Show" ? array.get(indicators_name, x) + "\n" : "") : "")
        divergence_text_bottom := divergence_text_bottom + ((div_type % 2) == 0 ? (showindis != "Don't Show" ? array.get(indicators_name, x) + "\n" : "") : "")


// draw labels
if showindis != "Don't Show" or shownum
    if shownum and dnumdiv_top > 0
        divergence_text_top := divergence_text_top + tostring(dnumdiv_top)
    if shownum and dnumdiv_bottom > 0
        divergence_text_bottom := divergence_text_bottom + tostring(dnumdiv_bottom)
    if divergence_text_top != ""
        if showlast
            delete_old_neg_div_labels()
        array.push(neg_div_labels, 
                      label.new( x = bar_index, 
                                 y = max(high, high[1]), 
                                 text = divergence_text_top,
                                 color = top_label_col,
                                 textcolor = neg_div_text_col,
                                 style = label.style_label_down
                                 ))
                                 
    if divergence_text_bottom != ""
        if showlast
            delete_old_pos_div_labels()
        array.push(pos_div_labels, 
                      label.new( x = bar_index, 
                                 y = min(low, low[1]), 
                                 text = divergence_text_bottom,
                                 color = bottom_label_col, 
                                 textcolor = pos_div_text_col,
                                 style = label.style_label_up
                                 ))
        
// plotshape(pos_reg_div_detected, title= "Should Buy", location=location.belowbar, color=color.green, transp=0, style=shape.triangleup, text="BUY")
// plotshape(neg_reg_div_detected, title= "Should Sell", location=location.belowbar, color=color.red, transp=0, style=shape.triangledown, text="SELL")

// GetPipSize() =>
//     syminfo.mintick * (syminfo.type == "forex" ? 10 : 1)

// take_profit_pips = 50 
// stop_loss_pips = 50
// pipSize = GetPipSize()
// price_target = close + (take_profit_pips * pipSize)
// price_stop_loss = close - (stop_loss_pips * pipSize)
// long_qty = 5
// short_qty = 5

// if (pos_reg_div_detected and dnumdiv_bottom >= 4)
//     long_strategy_id = "Long Entry "+tostring(bar_index)+ " ("+tostring(close)+")"
//     exit_long_strategy_id = "Exit Long "+tostring(bar_index)
//     strategy.entry(long_strategy_id, strategy.long, qty = long_qty) // Buy Market Order at bar close
//     strategy.exit(exit_long_strategy_id,long_strategy_id,profit = take_profit_pips, loss = stop_loss_pips)


// if (neg_reg_div_detected and dnumdiv_top >= 4)
//     short_strategy_id = "Short Entry "+tostring(bar_index)+ " ("+tostring(close)+")"
//     exit_short_strategy_id = "Exit Short "+tostring(bar_index)
//     strategy.entry(short_strategy_id, strategy.short, qty = short_qty)
//     strategy.exit(exit_short_strategy_id,short_strategy_id,profit = take_profit_pips, loss = stop_loss_pips)



// Bollinger

length = input(title="Length", type=input.integer, defval=20, minval=1)
src = input(close, title="Source")
mult = input(type=input.float, defval=2.0, minval=0.001, maxval=50, title="StdDev")
offset = input(defval=10, title="Offset", type=input.integer, minval = -500, maxval = 500)
near_offset = input(defval=20, title="Near Offset", type=input.integer)

basis = sma(src, length)
dev = mult * stdev(src, length)
upper = basis + dev
lower = basis - dev

between(price, min,max) =>
    is_between = price <= max and price >= min
    is_between

isPriceNearLower(lower, price) =>
    max = lower + near_offset
    min = lower - near_offset
    is_near = between(price, min, max)
    is_near

isPriceNearUpper(upper, price) =>
    max = upper + near_offset
    min = upper - near_offset
    is_near = between(price, min, max)
    is_near

price_near_lower_bb = isPriceNearLower(lower, low)
price_near_upper_bb = isPriceNearUpper(upper, high)


// RSI inputs

rsi_source = input(title="RSI Source", type=input.source, defval=close)
rsi_length = input(title="RSI stoch_length", type=input.integer, defval=7)
rsi_over_bought_level = input(title="RSI Overbought Level", type=input.integer, defval=70)
rsi_over_sold_level = input(title="RSI Oversold Level", type=input.integer, defval=30)

isRSIOverBought(rsi_over_bought_level) =>
    rsiValue = rsi(rsi_source, rsi_length)
    is_over_bought = rsiValue >= rsi_over_bought_level
    is_over_bought

isRSIOverSold(rsi_over_sold_level) =>
    rsiValue = rsi(rsi_source, rsi_length)
    is_over_sold = rsiValue <= rsi_over_sold_level
    is_over_sold

// Stoch inputs

stoch_length = input(defval=14, minval=1, title = "Stochastic Length")
k = input(defval=1, minval=1, title = "Stochastic %K")
d = input(defval=3, minval=1, title = "Stochastic %D")
stoch_over_bought_level = input(title="RSI Overbought Level", type=input.integer, defval=80)
stoch_over_sold_level = input(title="RSI Oversold Level", type=input.integer, defval=20)


isStochOverBought(stoch_over_bought_level, k) => 
    Sto = stoch (close, high, low, stoch_length)
    K= sma (Sto, k)
    is_over_bought = K >= stoch_over_bought_level
    is_over_bought

isStochOverSold(stoch_over_sold_level, k) => 
    Sto = stoch (close, high, low, stoch_length)
    K= sma (Sto, k)
    is_over_sold = K <= stoch_over_sold_level
    is_over_sold


price_is_over_bought = isRSIOverBought(rsi_over_bought_level) and isStochOverBought(stoch_over_bought_level, k)
price_is_over_sold = isRSIOverSold(rsi_over_sold_level) and isStochOverSold(stoch_over_sold_level, k)


// All combined

should_buy() => 
    conditions_met = price_is_over_sold and price_near_lower_bb and pos_reg_div_detected
    conditions_met

should_sell() => 
    conditions_met = price_is_over_bought and price_near_upper_bb and neg_reg_div_detected
    conditions_met



plotshape(should_buy(), title= "Should Buy", location=location.belowbar, color=color.green, transp=0, style=shape.triangleup, text="BUY")
plotshape(should_sell(), title= "Should Sell", location=location.belowbar, color=color.red, transp=0, style=shape.triangledown, text="SELL")


// Plot
// plotshape(price_is_over_bought,  title= "Overbought", location=location.abovebar, color=color.red, transp=0, style=shape.triangledown, text="OB")
// plotshape(price_is_over_sold, title= "Oversold", location=location.belowbar, color=color.green, transp=0, style=shape.triangleup, text="OS")

// alertcondition(price_is_over_bought or price_is_over_sold, title="Stoch Alert!", message="Stoch Alert")

Overview

Plotted directly on the price chart, it draws divergence connecting lines and visual labels when a minimum threshold of confirming oscillators display a divergence. Users can customize pivot calculation periods, divergence types, and oscillator toggles, as well as enable optional 50-period and 200-period simple moving averages. Divergence signals are identified using past pivot points and confirm after the pivot period completes.

Details

Published by

bfoura on GitHub

Code credit

dolan_0x, as written in the script's header

Type

Indicator, Pine Script v4

Draws

On the price chart

Category

Divergence, Oscillators & momentum, Moving averages

Markets

Any symbol

Timeframes

Any timeframe

Risk Notes

No repainting, lookahead or stacked entries were found in its code or README. That says nothing about how well it works: test it first.

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
Pivot Periodint5prd
Source for Pivot PointsstringClosesource
Divergence TypestringRegularsearchdiv
Show Indicator NamesstringFullshowindis
Minimum Number of Divergenceint1showlimit
Maximum Pivot Points to Checkint10maxpp
Maximum Bars to Checkint100maxbars
Show Divergence Numberbooltrueshownum
Show Only Last Divergenceboolfalseshowlast
Don't Wait for Confirmationboolfalsedontconfirm
Show Divergence Linesbooltrueshowlines
Show Pivot Pointsboolfalseshowpivot
Show all 40 settings
SettingTypeDefaultVariable
MACDbooltruecalcmacd
MACD Histogrambooltruecalcmacda
RSIbooltruecalcrsi
Stochasticbooltruecalcstoc
CCIboolfalsecalccci
Momentumboolfalsecalcmom
OBVboolfalsecalcobv
VWmacdboolfalsecalcvwmacd
Chaikin Money Flowboolfalsecalccmf
Money Flow Indexboolfalsecalcmfi
Check External Indicatorboolfalsecalcext
External Indicatorsourcecloseexternalindi
Positive Regular Divergencecolorcolor.yellowpos_reg_div_col
Negative Regular Divergencecolorcolor.navyneg_reg_div_col
Positive Hidden Divergencecolorcolor.limepos_hid_div_col
Negative Hidden Divergencecolorcolor.redneg_hid_div_col
Positive Divergence Text Colorcolorcolor.blackpos_div_text_col
Negative Divergence Text Colorcolorcolor.whiteneg_div_text_col
Regular Divergence Line StylestringSolidreg_div_l_style_
Hdden Divergence Line StylestringDashedhid_div_l_style_
Regular Divergence Line Widthint2reg_div_l_width
Hidden Divergence Line Widthint1hid_div_l_width
Show MAs 50 & 200boolfalseshowmas
cma1colcolorcolor.limecma1col
cma2colcolorcolor.redcma2col
Lengthint20length
Sourcesourceclosesrc
StdDevfloat2.0mult
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

23 stars

This indicator collection calculates and plots previous daily high and low price levels on the chart to identify potential supply and demand zones. It includes real-time intraday high and low calculations, RSI divergence detection across a customizable period

Indicator v4 Support & resistanceDivergence
Updated 3 years ago · None stated GitHub repository of Daily High and Low Strategy
5 stars

This indicator overlays multiple technical analysis tools onto the price chart to evaluate trend direction and trade setups. It computes an exponential moving average, a smoothed Stochastic RSI, a custom Williams Alligator using smoothed moving averages with o

Indicator v4 TrendMoving averages
Updated 3 years ago · Apache-2.0 GitHub repository of 200 EMA + Alligator + Stochastic

Fractals with Divergence Scanner is an overlay indicator that combines Exponential Moving Averages, an eight-line EMA ribbon cloud, and WaveTrend divergence analysis. It calculates baseline EMA trends alongside WaveTrend oscillators to detect regular and hidde

Indicator v5 TrendMoving averages
Updated 5 months ago · None stated GitHub repository of Fractals with Divergence Scanner
2 stars

ARPS Ultimate MultiStrategy Trading combines multiple technical indicators into a single chart overlay. It calculates and plots trend lines, moving averages, Ichimoku cloud components, Williams Alligator lines, and Fibonacci support and resistance levels direc

Indicator v4 TrendOscillators & momentum
Updated 6 months ago · None stated GitHub repository of ARPS Ultimate MultiStrategy Trading

Complexity Trender

by panzmoravylab
2 stars

Complexity Trender is an indicator that combines EMA crossovers, RSI momentum, Stochastic signals, Bollinger Bands, ADX trend strength, volume analysis, and divergence detection to identify trends. It plots labels, trend lines, and a summary table directly on

Indicator v6 TrendOscillators & momentum
Updated 1 year ago · None stated GitHub repository of Complexity Trender

This multi-timeframe indicator combines higher-timeframe trend analysis, MACD divergence detection, and short-term oscillator timing to identify trading opportunities on GBPJPY. It evaluates trend direction using a 4-hour EMA, locates MACD divergences with Zig

Indicator v6 DivergenceOscillators & momentum

More indicators

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers