TradingView screening methods

RSI divergence screener: compare confirmed pivots across a symbol list

An RSI divergence screener compares two confirmed price lows or highs with RSI measured on those same bars, then repeats the rule for each symbol. A lower price low with higher RSI is regular bullish divergence; a higher price high with lower RSI is regular bearish divergence. The example below scans three explicit symbols and compares RSI with the MACD line using identical price pivots. Confirmation takes time, and a confirmed divergence can still fail.

Explore Market Screener

Specify the pivot pair before comparing indicators

For a candidate price-pivot bar p, require its low to be strictly below the lows of the L bars before it and R bars after it. For a high pivot, reverse the inequalities. The default is L = R = 2. Compare each new confirmed low only with the immediately preceding confirmed low, and each high only with the preceding high. This example has no maximum pair spacing, hidden-divergence rule, oversold gate or trend filter. Those changes would define a different screen.

  • RSI uses close and Wilder smoothing. MACD here is EMA(close, 12) minus EMA(close, 26). The MACD signal line and histogram are not used; a histogram divergence can produce a different list.
  • Both oscillators use the same price-pivot timestamps. Finding their own independent peaks can compare different events and change the classification.
  • This definition is intentionally explicit. It need not match TradingView's built-in RSI divergence indicator or a community script that anchors pivots on RSI, allows ties, or restricts the number of bars between pivots.
EventPrice ruleOscillator rule at the same two bars
Regular bullishNew pivot low < previous pivot lowNew RSI > previous RSI; independently test new MACD line > previous MACD line
Regular bearishNew pivot high > previous pivot highNew RSI < previous RSI; independently test new MACD line < previous MACD line
No divergenceEqual prices, equal oscillator values, or inequalities not metStrict comparisons; a tie does not pass
Unavailable pairEither pivot lacks eligible oscillator historyDo not convert missing values into zero or a bearish result

Keep the pivot date separate from the detection date

A low at daily bar 20 cannot be confirmed with R = 2 until bar 22 has closed. The script evaluates that completed bar through a one-bar-offset daily request, so the row becomes available in the following daily period, subject to host-chart execution. The table labels the pivot opening time separately from the evaluated close. It never plots a signal backward onto bar 20.

  • The right-bar delay is measured in that symbol's trading bars, not calendar days. A weekend or holiday can extend elapsed time.
  • Every requested output is shifted by [1] inside the daily context before lookahead_on is applied. An unshifted daily expression with lookahead_on would leak future daily information into historical intraday bars.
  • The latest row is an event result for one completed daily bar, not a persistent "buy" or "sell" state. A divergence row returns to No new pivot on a later evaluated bar with no pivot event.
  • Confirmed inputs reduce differences caused by unfinished bars. They do not prevent feed corrections, changes in available history, or false signals. A bullish divergence can occur while price keeps falling.

Recompute three synthetic symbols before using market data

These fixtures contain complete close histories from bar 0, in arbitrary price units. Set each open equal to close, high = close + 1, low = close - 1, and use consecutive daily bars. For compact arithmetic only, set RSI length = 3, MACD fast = 3, slow = 6, and L = R = 2. These are synthetic symbols A, B and C, not returns, forecasts or the live default tickers. The last listed bar is the confirmation bar; the request exposes its result only in the next daily period.

  • For RSI(3), average the first three positive changes and first three absolute negative changes, counting the opposite direction as zero. Thereafter update each average as (2 × previous average + current gain or loss) / 3. RSI = 100 - 100 / (1 + average gain / average loss). A zero loss with positive gain gives 100; zero gain with positive loss gives 0. Reject an undefined both-zero fixture value.
  • Seed each EMA with close[0]. Then EMA(n)[t] = EMA(n)[t-1] + 2 / (n + 1) × (close[t] - EMA(n)[t-1]). Subtract EMA(6) from EMA(3) for the fixture MACD line. Calculations use full precision; the next table rounds only the displayed values.
  • The script requires the pivot index to be at least max(RSI length, slow EMA length - 1), plus nonmissing oscillator values at both pivots. This minimum-history guard is not proof that EMA initialization effects have disappeared. Use consistent earlier history when comparing real charts.
Synthetic symbolCloses from bar 0 through confirmation
A100, 99, 100, 97, 100, 105, 103, 100, 97, 92, 95, 96, 91, 90, 92, 93
B100, 98, 95, 96, 93, 98, 103, 108, 111, 110, 107, 112, 107, 110
C100, 95, 92, 89, 91, 89, 90, 91, 90, 85, 83, 86, 89, 91, 96, 97, 92, 87, 89, 94, 96, 99, 102, 100, 98

Expected fixture results and a disagreement worth retaining

Apply the same strict price pivots to every series. Symbol A passes both regular bullish rules; B passes both regular bearish rules; C passes only RSI regular bearish. If the final filter requires both oscillators to agree, keep A and B and reject C. If it accepts either, retain C with its disagreement visible. No future price outcome is supplied, so this fixture cannot measure predictive accuracy or a false-positive rate.

  • For A, 89 < 91, 20.845662 > 13.682195 and -1.930971 > -2.084723. Both comparisons are bullish, although both MACD values remain negative.
  • For C, price rises and RSI falls, but MACD rises too. MACD being positive is not the bearish-divergence condition.
  • Truncate A at bar 14: the low at bar 13 has only one right bar and must not produce the bar-15 event. Make a neighboring low equal to the pivot low: the strict pivot must disappear. Missing or insufficient history must not become a passing signal.
Symbol / pivot barsPrice at pivotsRSI(3)MACD line (3,6)Confirmation / result
A lows 9 → 1391 → 8913.682195 → 20.845662-2.084723 → -1.930971Bar 15: bullish in both
B highs 8 → 11112 → 11389.045045 → 74.0016613.394344 → 2.145106Bar 13: bearish in both
C highs 15 → 2298 → 10388.525771 → 87.6617892.288349 → 2.588917Bar 24: RSI bearish; MACD no divergence

Run the complete three-symbol Pine Script v6 screen

Paste this indicator into Pine Editor and add it to a standard intraday candle chart, such as 60 minutes. Choose three exchange-qualified symbols in Settings. All requests use daily bars. RSI and MACD calculations run separately in each requested symbol's context; the code does not reuse the host chart's oscillator for other symbols. The displayed UTC close time identifies the daily bar evaluated, not the time a user first saw the row.

  • Warm-up means the current pivot location lacks minimum history or an oscillator value. Need eligible pair means a pivot exists but no usable preceding same-side pair is available. Pair: no divergence means at least one eligible pair was evaluated and the oscillator rule failed. No new pivot means this evaluated bar confirmed no strict price pivot.
  • The script uses three unique request contexts for three distinct symbols and 12 returned tuple elements. Adding symbols or intervals consumes further request and tuple capacity. TradingView documents limits on both; a small named list is the contract here.
  • Invalid symbols return No data. gaps_off can carry the last completed daily result forward across holidays or interruptions. Read the timestamp before treating a populated row as current.
  • Markets need not open together. A US-equity host chart cannot update while it is not executing, even if a requested crypto market trades. Each requested market also needs its next daily period before this offset pattern exposes the preceding result.
  • This table does not import a watchlist or scan an entire exchange. It is not a TradingView Pine Screener configuration, an alert service, or a multi-asset strategy. To study trades, define entries, exits and costs separately and validate each symbol.
Three daily request contexts, four returned values per request, no orders or alert calls. Defaults: RSI 14; MACD line 12/26; strict price pivots 2/2.pine
//@version=6
indicator("Confirmed RSI / MACD divergence: three symbols", overlay = true)
int leftBars = input.int(2, "Pivot left bars", minval = 1, maxval = 20)
int rightBars = input.int(2, "Pivot right bars", minval = 1, maxval = 20)
int rsiLength = input.int(14, "RSI length", minval = 2, maxval = 100)
int fastLength = input.int(12, "MACD fast EMA", minval = 2, maxval = 100)
int slowLength = input.int(26, "MACD slow EMA", minval = 3, maxval = 200)
string symbol1 = input.symbol("NASDAQ:AAPL", "Symbol 1")
string symbol2 = input.symbol("NASDAQ:MSFT", "Symbol 2")
string symbol3 = input.symbol("NASDAQ:NVDA", "Symbol 3")
if not timeframe.isintraday or timeframe.in_seconds() >= timeframe.in_seconds("1D") or not chart.is_standard
    runtime.error("Use standard intraday candles, such as 60 minutes.")
if fastLength >= slowLength
    runtime.error("MACD fast length must be less than slow length.")

// A strict price pivot: tied highs/lows do not qualify.
pivot(float source, bool isLow) =>
    float value = source[rightBars]
    for i = 0 to leftBars + rightBars
        if i != rightBars and (na(source[i]) or (isLow ? source[rightBars] >= source[i] : source[rightBars] <= source[i]))
            value := na
    value

scan() =>
    float r = ta.rsi(close, rsiLength)
    float m = ta.ema(close, fastLength) - ta.ema(close, slowLength)
    float lo = pivot(low, true)
    float hi = pivot(high, false)
    bool hasLow = not na(lo)
    bool hasHigh = not na(hi)
    int minimum = math.max(rsiLength, slowLength - 1)
    float prevLow = ta.valuewhen(hasLow, lo, 1)
    float prevHigh = ta.valuewhen(hasHigh, hi, 1)
    float prevLowR = ta.valuewhen(hasLow, r[rightBars], 1)
    float prevHighR = ta.valuewhen(hasHigh, r[rightBars], 1)
    float prevLowM = ta.valuewhen(hasLow, m[rightBars], 1)
    float prevHighM = ta.valuewhen(hasHigh, m[rightBars], 1)
    int prevLowIndex = ta.valuewhen(hasLow, bar_index - rightBars, 1)
    int prevHighIndex = ta.valuewhen(hasHigh, bar_index - rightBars, 1)
    bool ready = bar_index - rightBars >= minimum and not na(r[rightBars]) and not na(m[rightBars])
    bool lowPair = hasLow and ready and not na(prevLowR) and not na(prevLowM) and prevLowIndex >= minimum
    bool highPair = hasHigh and ready and not na(prevHighR) and not na(prevHighM) and prevHighIndex >= minimum
    bool rb = lowPair and lo < prevLow and r[rightBars] > prevLowR
    bool rs = highPair and hi > prevHigh and r[rightBars] < prevHighR
    bool mb = lowPair and lo < prevLow and m[rightBars] > prevLowM
    bool ms = highPair and hi > prevHigh and m[rightBars] < prevHighM
    int base = not ready ? -2 : not hasLow and not hasHigh ? 0 : not lowPair and not highPair ? -3 : 3
    int rState = rb and rs ? 2 : rb ? 1 : rs ? -1 : base
    int mState = mb and ms ? 2 : mb ? 1 : ms ? -1 : base
    int pivotTime = hasLow or hasHigh ? time[rightBars] : na
    // Every returned field is offset inside the requested daily context.
    [rState[1], mState[1], time_close[1], pivotTime[1]]

[r1, m1, t1, p1] = request.security(symbol1, "1D", scan(), gaps = barmerge.gaps_off, lookahead = barmerge.lookahead_on, ignore_invalid_symbol = true)
[r2, m2, t2, p2] = request.security(symbol2, "1D", scan(), gaps = barmerge.gaps_off, lookahead = barmerge.lookahead_on, ignore_invalid_symbol = true)
[r3, m3, t3, p3] = request.security(symbol3, "1D", scan(), gaps = barmerge.gaps_off, lookahead = barmerge.lookahead_on, ignore_invalid_symbol = true)

state(int value) =>
    switch value
        1 => "Regular bullish"
        -1 => "Regular bearish"
        2 => "Bullish + bearish"
        -2 => "Warm-up"
        -3 => "Need eligible pair"
        3 => "Pair: no divergence"
        => "No new pivot"
stamp(int value) =>
    na(value) ? "N/A" : str.format_time(value, "yyyy-MM-dd HH:mm", "UTC")
var table results = table.new(position.top_right, 5, 4, border_width = 1)
row(int n, string symbol, int r, int m, int t, int p) =>
    array<string> cells = array.from(symbol, stamp(t), stamp(p), na(t) ? "No data" : state(r), na(t) ? "No data" : state(m))
    for col = 0 to 4
        table.cell(results, col, n, array.get(cells, col), text_color = color.white, bgcolor = color.new(color.navy, 15))
if barstate.islast
    array<string> headers = array.from("Symbol", "Evaluated close UTC", "Pivot open UTC", "RSI", "MACD line")
    for col = 0 to 4
        table.cell(results, col, 0, array.get(headers, col), text_color = color.white, bgcolor = color.navy)
    row(1, symbol1, r1, m1, t1, p1)
    row(2, symbol2, r2, m2, t2, p2)
    row(3, symbol3, r3, m3, t3, p3)

Audit false signals and delay on the actual candidate list

A screen identifies a mathematical disagreement, not a completed reversal. Additional confirmation may remove some candidates while delaying the surviving ones. Neither longer pivots nor agreement between RSI and MACD can eliminate false positives or lag. The two indicators also share the same closing-price input, so agreement is not independent evidence.

Audit itemRecord for each candidateReason
TimingPivot bars, confirmation bar, evaluated close UTC and first observed timeSeparate mathematical confirmation from delivery delay
AlignmentExchange-qualified ticker, daily interval, session and adjustment settingsDifferent data contexts can form different pivots
Pair ruleL/R, consecutive same-side pivots, ties and oscillator lengthsChanging these settings changes the candidate set
DecisionRSI flag, MACD flag, agreement rule and reason retained/rejectedKeep disagreements and failures visible
Outcome studyPredeclared horizon and failure rule, evaluated after detectionDo not backdate a hypothetical entry to the pivot or choose the outcome window afterward

Map supported Pineify fields without inventing a divergence filter

Pineify Market Screener exposes RSI 14 (rsi14), RSI State (rsi_state), MACD Histogram (macd_hist) and MACD State (macd_state) in its supported field catalog. They help organize a candidate collection, but a current RSI value or MACD state does not establish the two aligned price pivots required by this page. The current catalog does not provide this exact confirmed price-pivot RSI/MACD divergence test.

  • Create a finite collection with available symbols, use a consistent daily interval and inspect snapshot barTime and receivedAt before comparing rows. Save the candidates and settings, then verify each selected symbol on a matching TradingView chart.
  • Do not substitute MACD Histogram for this example's MACD line. Do not interpret an indicator called RSI Divergence as proof of a pivot algorithm: Pineify's separate script-builder configuration with that name computes fast RSI minus slow RSI.
  • AI Finance Agent can help research a candidate using available data and public sources. Give it the symbol, timestamps, pivot definition and missing fields; ask it to identify what evidence is absent. It cannot infer a verified historical pivot pair from a single current snapshot.
  • For the exact rule, use the finite Pine example and keep its confirmation log. Product snapshots, manually verified candidates and hypothetical trade results should remain separately labeled.
Where Pineify fits

Pineify Market Screener

Compare supported RSI and MACD fields in a candidate collection, then verify the exact pivot pairs on TradingView.

Also useful: AI Finance Agent. Research candidates and check available public evidence. Supply the pivot rules and timestamps; leave missing observations unresolved.

Explore Market Screener

Frequently asked questions

Educational information, not investment advice. All fixture prices and results are synthetic. Divergence is a screening condition, not a prediction, trading instruction or guarantee of profit.

Sources and verification

Published by Pineify. Pineify is an independent product and is not affiliated with TradingView. Sources support the technical explanations; examples do not establish trading performance.