Build a Custom RSI Divergence Detector for TradingView — Using Claude Code to Write Pine Script

intermediate 30 min · · By Alpha Guy · claude-code

Why Divergence Matters More Than Overbought/Oversold

Most traders learn RSI as a simple overbought/oversold oscillator. RSI above 70, sell. RSI below 30, buy. That framing is not wrong exactly, but it misses the most useful thing RSI can do: detect divergences between price momentum and price direction.

Here is the core idea. When price makes a new low but RSI makes a higher low, that means selling pressure is weakening even as price drops further. The market is losing conviction in the downtrend. This is bullish divergence. The reverse — price makes a new high while RSI makes a lower high — is bearish divergence. Buying pressure is fading even though price keeps pushing up.

Divergence is a leading indicator in a way that simple threshold readings are not. An RSI reading of 75 tells you “momentum is strong right now.” A bearish divergence tells you “momentum is weakening relative to the previous push,” which is actionable information about what might happen next.

I built a Pine Script indicator with Claude Code that detects both types of divergence automatically, draws the divergence lines on the chart, and fires alerts. This article walks through the entire process — the prompts, the code, the iterations, and the honest assessment of when it works and when it does not.

What You Will Build

A TradingView indicator that:

  • Identifies swing highs and swing lows on both price and RSI
  • Compares consecutive swing points to detect bullish and bearish divergence
  • Draws lines connecting the diverging points for visual confirmation
  • Plots arrow signals on the price chart
  • Includes configurable RSI period, lookback window, and sensitivity
  • Has alert conditions for both divergence types
  • Optional volume confirmation filter to reduce false signals

The Prompt I Gave Claude Code

I went through three rounds with Claude Code. The first prompt was too vague and produced a basic version similar to what you find in TradingView’s community scripts. The second prompt was better but had a repainting issue. The third prompt is what produced the working version.

Here is the final prompt:

Write a TradingView Pine Script v5 indicator called "RSI Divergence Pro" with overlay=true.

Requirements:
1. Calculate RSI with configurable period (default 14)
2. Detect pivot lows and pivot highs on both price and RSI using ta.pivotlow() and ta.pivothigh() with a configurable lookback (default 5)
3. For bullish divergence: when a new pivot low on price is LOWER than the previous pivot low, but the corresponding RSI pivot low is HIGHER than the previous RSI pivot low — signal bullish divergence
4. For bearish divergence: when a new pivot high on price is HIGHER than the previous pivot high, but the corresponding RSI pivot high is LOWER than the previous RSI pivot high — signal bearish divergence
5. Use ta.valuewhen() to get the previous pivot values for comparison
6. Draw lines on the RSI pane connecting the two diverging pivot points (both the price line and the RSI line)
7. Plot triangleup below bar for bullish divergence (green), triangledown above bar for bearish (red)
8. Add alertcondition() for both types
9. IMPORTANT: offset all signals by the lookback period to avoid repainting. Pivots are confirmed only after lookback bars have passed.
10. Add an optional volume filter: only trigger divergence if the volume on the signal bar is above the 20-period SMA of volume.
11. Add a sensitivity input (1-5) that controls the minimum RSI difference required between the two pivot points. Sensitivity 1 = at least 5 RSI points difference, sensitivity 5 = at least 1 RSI point difference.

The key detail is point 9. Without that explicit instruction about offsetting by the lookback period, the first two versions repainted — they would show a divergence signal on a bar that had not yet confirmed the pivot, and then the signal would disappear if subsequent bars invalidated the pivot. Telling Claude Code to explicitly offset the signals fixed this.

The Full Pine Script v5 Code

Here is the complete indicator. I will break down the important sections after.

//@version=5
indicator("RSI Divergence Pro", overlay=true, max_lines_count=500)

// ─── Inputs ───────────────────────────────────────────
rsiPeriod    = input.int(14, "RSI Period", minval=2, maxval=50)
lookback     = input.int(5, "Pivot Lookback", minval=2, maxval=20)
sensitivity  = input.int(3, "Sensitivity (1=strict, 5=loose)", minval=1, maxval=5)
useVolFilter = input.bool(false, "Require Above-Average Volume")
volPeriod    = input.int(20, "Volume SMA Period", minval=1)
showLines    = input.bool(true, "Draw Divergence Lines")

// ─── RSI Calculation ──────────────────────────────────
rsi = ta.rsi(close, rsiPeriod)

// ─── Sensitivity Mapping ──────────────────────────────
// Sensitivity 1 = need 5+ RSI points difference (strict)
// Sensitivity 5 = need 1+ RSI point difference (loose)
minRsiDiff = 6.0 - sensitivity  // Maps 1->5, 2->4, 3->3, 4->2, 5->1

// ─── Pivot Detection ─────────────────────────────────
// Pivots are detected with a lookback offset, meaning
// they are confirmed only after 'lookback' bars pass
pricePivotLow  = ta.pivotlow(low, lookback, lookback)
pricePivotHigh = ta.pivothigh(high, lookback, lookback)
rsiPivotLow    = ta.pivotlow(rsi, lookback, lookback)
rsiPivotHigh   = ta.pivothigh(rsi, lookback, lookback)

// ─── Previous Pivot Values ───────────────────────────
// ta.valuewhen(condition, source, occurrence)
// occurrence=1 means "the value the PREVIOUS time condition was true"
prevPriceLow  = ta.valuewhen(not na(pricePivotLow), low[lookback], 1)
prevPriceHigh = ta.valuewhen(not na(pricePivotHigh), high[lookback], 1)
prevRsiLow    = ta.valuewhen(not na(rsiPivotLow), rsi[lookback], 1)
prevRsiHigh   = ta.valuewhen(not na(rsiPivotHigh), rsi[lookback], 1)

// Previous pivot bar indices (for drawing lines)
prevLowBar  = ta.valuewhen(not na(pricePivotLow), bar_index[lookback], 1)
prevHighBar = ta.valuewhen(not na(pricePivotHigh), bar_index[lookback], 1)

// Current pivot values (offset by lookback since that's where the pivot actually is)
currPriceLow  = low[lookback]
currPriceHigh = high[lookback]
currRsiLow    = rsi[lookback]
currRsiHigh   = rsi[lookback]
currBar       = bar_index[lookback]

// ─── Volume Filter ───────────────────────────────────
volSma    = ta.sma(volume, volPeriod)
volOk     = not useVolFilter or (volume[lookback] > volSma[lookback])

// ─── Bullish Divergence Detection ────────────────────
// Price makes a lower low, RSI makes a higher low
bullDiv = not na(pricePivotLow)
     and not na(rsiPivotLow)
     and currPriceLow < prevPriceLow
     and currRsiLow > prevRsiLow
     and (currRsiLow - prevRsiLow) >= minRsiDiff
     and volOk

// ─── Bearish Divergence Detection ────────────────────
// Price makes a higher high, RSI makes a lower high
bearDiv = not na(pricePivotHigh)
     and not na(rsiPivotHigh)
     and currPriceHigh > prevPriceHigh
     and currRsiHigh < prevRsiHigh
     and (prevRsiHigh - currRsiHigh) >= minRsiDiff
     and volOk

// ─── Plot Signals ────────────────────────────────────
// Offset by -lookback to place the signal on the actual pivot bar
plotshape(bullDiv, title="Bullish Divergence",
     style=shape.triangleup, location=location.belowbar,
     color=color.new(color.green, 0), size=size.small,
     offset=-lookback, text="Bull Div")

plotshape(bearDiv, title="Bearish Divergence",
     style=shape.triangledown, location=location.abovebar,
     color=color.new(color.red, 0), size=size.small,
     offset=-lookback, text="Bear Div")

// ─── Draw Divergence Lines on Price Chart ────────────
if bullDiv and showLines
    line.new(x1=prevLowBar, y1=prevPriceLow,
         x2=currBar, y2=currPriceLow,
         color=color.green, width=2, style=line.style_solid)

if bearDiv and showLines
    line.new(x1=prevHighBar, y1=prevPriceHigh,
         x2=currBar, y2=currPriceHigh,
         color=color.red, width=2, style=line.style_solid)

// ─── Alerts ──────────────────────────────────────────
alertcondition(bullDiv, "Bullish RSI Divergence",
     "Bullish RSI divergence detected — price lower low, RSI higher low")
alertcondition(bearDiv, "Bearish RSI Divergence",
     "Bearish RSI divergence detected — price higher high, RSI lower high")

How the Swing Detection Works

The core of any divergence indicator is pivot detection. A pivot low is a bar whose low is lower than the lows of the surrounding bars. A pivot high is a bar whose high is higher than the highs of the surrounding bars. The lookback parameter controls how many bars on each side must be lower (or higher) for a point to qualify as a pivot.

With a lookback of 5, a pivot low at bar N means that bars N-5 through N-1 all have higher lows, and bars N+1 through N+5 also all have higher lows. This is why pivots are inherently lagging — you cannot confirm a pivot low until 5 bars after it occurs, because you need those future bars to validate that the low held.

This is where the repainting issue lives. Pine Script’s ta.pivotlow() returns the pivot value at the current bar when the pivot is confirmed (which is lookback bars after the actual pivot bar). If you plot a signal at the current bar, it appears lookback bars late on the chart. If you plot it at the pivot bar using a negative offset, it appears on the correct bar — but only after confirmation. This is not repainting because the signal never disappears; it just appears with a delay. On a live chart, you will see the signal pop up on a bar that is already lookback bars in the past.

The ta.valuewhen() function is the other critical piece. It retrieves the value of a series the last time a condition was true. By using occurrence=1, I get the previous pivot value — not the current one. This lets me compare consecutive pivots: “Is the current pivot low lower than the previous pivot low?”

Configuration Options Explained

ParameterDefaultWhat It Controls
RSI Period14Standard RSI lookback. 14 is the textbook default. Shorter periods (9-10) make divergences more frequent but noisier. Longer periods (20-25) produce fewer but more reliable signals.
Pivot Lookback5How many bars on each side define a swing point. Higher values (7-10) find major swings only. Lower values (2-3) catch minor swings but produce many more signals.
Sensitivity3Minimum RSI point difference between consecutive pivots. At 1 (strict), the two RSI pivots must differ by at least 5 points. At 5 (loose), a 1-point difference qualifies.
Volume FilterOffWhen enabled, divergence signals only fire if volume on the pivot bar exceeds the 20-period volume SMA. Reduces false signals in low-liquidity conditions.
Draw LinesOnWhether to draw connecting lines between the diverging pivot points. Useful for visual confirmation but can clutter the chart on busy timeframes.

My default setup for BTC/USDT on the 4H chart is RSI Period 14, Pivot Lookback 5, Sensitivity 3, Volume Filter on. For altcoins with less liquidity, I set the lookback to 7 and sensitivity to 2 to filter out noise.

Real Examples: What This Indicator Catches

I ran this indicator on BTC/USDT across several months of 4H data. Here are specific examples that illustrate both successful signals and failures.

Bullish Divergence Example

A classic setup occurs when BTC drops to a support zone, makes a lower low in price, but RSI prints a higher low. In practice, I observed this pattern when BTC tested a key level around $58,000 twice over the course of a week. The first touch printed RSI at 24. The second touch pushed price about $600 lower, but RSI bottomed at 29 — a clear higher low. The indicator fired a bullish divergence signal. Price reversed and rallied over $4,000 in the following three days.

The divergence line drawn on the chart connected the two price lows (sloping down) while the corresponding RSI lows sloped up. That visual mismatch is exactly what you are looking for.

Bearish Divergence Example

The inverse pattern shows up at local tops. During a rally phase, BTC pushed to a new high near $72,000 with RSI at 78. After a brief pullback, price pushed to around $73,500 — a higher high. But RSI only reached 71, a lower high. The indicator flagged bearish divergence. Over the following five days, price retraced roughly $5,000.

This is the kind of signal that is hard to spot manually in real-time. You are watching price make a new high and the natural instinct is to feel bullish. The divergence indicator mechanically identifies the weakening momentum that your eyes might miss.

A False Positive

Not every signal works. During a strong trending move where BTC climbed from $62,000 to $69,000 over two weeks, the indicator flagged two bearish divergences that failed. Price made higher highs with lower RSI highs (textbook bearish divergence), but instead of reversing, price continued higher after brief 1-2% pullbacks. In a strong trend, divergence can signal temporary pauses rather than reversals. The trend was simply too strong for the divergence to mark a meaningful top.

This is the most common failure mode and the main reason you should never trade divergence in isolation.

Filtering False Positives

After running this indicator for several weeks, I developed a few rules to improve signal quality.

Rule 1: Trend Context Matters

Bullish divergence works best when the broader trend is either neutral or bullish (price above the 50 or 200 EMA). Bullish divergence during a strong downtrend often marks a temporary bounce, not a reversal. Similarly, bearish divergence in a strong uptrend frequently fails.

I added a 50 EMA to my chart as a simple trend filter. If price is above the 50 EMA and I see bullish divergence at a pullback low, that is a high-quality signal — a pullback within an uptrend showing momentum support. If price is well below the 50 EMA and I see bullish divergence, I treat it with much more skepticism.

Rule 2: Volume Confirmation

The optional volume filter in the indicator exists because divergences on low-volume bars are less meaningful. A pivot low on low volume might just be a quiet session where nothing happened, not genuine accumulation. When I enable the volume filter, the signal count drops by roughly 30-40% but the quality improves noticeably.

Rule 3: Timeframe Selection

On the 15-minute chart, this indicator fires constantly and the win rate is mediocre. On the daily chart, signals are rare but very reliable. My sweet spot is the 4H timeframe, which gives a few signals per month per pair and enough time to act on them.

TimeframeApproximate Signal Frequency (BTC)Observed Reliability
15mMultiple per dayLow — too many false positives
1HSeveral per weekModerate — usable with filters
4HA few per monthGood — my preferred timeframe
1DA few per quarterHigh — but too infrequent for active trading

Rule 4: Wait for Confirmation Candle

I do not enter immediately when the divergence signal appears. I wait for the next candle to close in the expected direction. For bullish divergence, I want to see a green candle close above the pivot low. For bearish divergence, a red candle closing below the pivot high. This patience filter costs me some upside on the entry but avoids jumping into signals that immediately invalidate.

Combining with Other Indicators

Divergence signals are strongest when they align with other technical factors. Here is how I layer them.

RSI Divergence + EMA Ribbon: If the Smart EMA Ribbon shows a trend transition from gray (choppy) to green, and a bullish divergence recently fired on the pullback before the transition, that is a strong confluence. The divergence says “momentum is shifting” and the ribbon says “trend is aligning.”

RSI Divergence + Volume Anomaly: A bullish divergence pivot low that coincides with a volume spike (detected by the Volume Anomaly Detector) suggests institutional accumulation at that level. This double confirmation has produced some of my best entries.

RSI Divergence + Support/Resistance: The most classic setup. Bullish divergence at a known support level, or bearish divergence at resistance. The divergence provides the “why now” and the support/resistance provides the “where.”

What I Got Wrong and Had to Fix

I want to be transparent about the iteration process because it is part of using AI for this kind of work.

Iteration 1 produced divergence signals that repainted. I would see a signal on a historical bar, scroll to the right, and realize the signal had appeared only after many subsequent bars had formed. The issue was that the pivots were being plotted at the confirmation bar rather than offset back to the actual pivot bar. Adding offset=-lookback to the plotshape() calls and explicitly referencing low[lookback] instead of low in the comparison logic fixed this.

Iteration 2 had a bug where the indicator detected divergence between unrelated pivots. If there was a pivot low 200 bars ago and another one 3 bars ago, it would compare them even though they had no meaningful relationship. I considered adding a maximum bar distance constraint but ultimately decided that the ta.valuewhen() approach with occurrence=1 (comparing only consecutive pivots) was sufficient. In practice, if pivots are far apart, the divergence is usually too stretched to be meaningful, but the sensitivity filter catches most of these cases because the RSI difference tends to be small.

Iteration 3 was the final version shown above. Claude Code got the logic right, but I manually adjusted the sensitivity mapping formula and changed the line drawing to use line.style_solid instead of line.style_dashed because the dashed lines were hard to see on dark chart themes.

The Honest Assessment

This indicator catches real divergences that lead to profitable setups. It also catches divergences that go nowhere. In my experience running it on BTC/USDT 4H with default settings and the volume filter enabled, roughly 55-60% of bullish divergence signals lead to a meaningful bounce (at least 2% move in the expected direction within 48 hours). Bearish divergence is slightly less reliable at around 50-55%, because crypto has a structural upward bias during bull markets.

Those numbers are not spectacular, but they do not need to be. The value is in identifying specific moments where momentum is shifting — moments you would likely miss staring at the chart. Combined with proper risk management and confirmation from other indicators or price levels, a 55% directional edge is tradeable.

What the indicator cannot do: it cannot tell you the magnitude of the coming move. A bullish divergence might precede a 1% bounce or a 15% rally. It signals the direction shift, not the extent. You need other tools — support/resistance levels, volume, broader trend context — to estimate the potential.

Adding It to TradingView

  1. Open TradingView and click Pine Editor in the bottom panel
  2. Delete the default code and paste the full script above
  3. Click Add to Chart (see the Pine Script docs if you run into syntax issues)
  4. Open the indicator settings to adjust RSI Period, Pivot Lookback, and Sensitivity
  5. Set up alerts: click the alert icon, select the indicator, and choose “Bullish RSI Divergence” or “Bearish RSI Divergence” as the condition

I recommend starting on the 4H timeframe and scrolling back through historical data to see where the indicator fires. This gives you a feel for the signal frequency and quality before you trade with it.

Next Steps

  • See my full indicator stack — The divergence detector is one piece of the puzzle. See all 3 AI indicators I actually use and how they work together.
  • Try Cursor for Pine Script — If you prefer an IDE workflow over CLI, our Cursor Pine Script tutorial walks through generating indicators with Cursor’s AI chat.
  • Try Gemini instead — See how Google Gemini handles Pine Script generation (including analyzing chart screenshots) in our Gemini Pine Script tutorial.
  • Combine with a trading bot — If you want to automate divergence signals into actual trades, check out our Claude Code grid trading bot tutorial for the bot-building workflow.
Disclaimer: This article is for educational purposes only and is not financial advice. Trading cryptocurrencies involves substantial risk of loss. Past performance does not guarantee future results. Always do your own research before making any trading decisions. Read full disclaimer →
Alpha Guy
Alpha Guy

Founder of VibeTradingLab. Ex-Goldman Sachs engineer, 2025 Binance Top 1% Trader. Writes about using AI tools to build trading systems that actually work. Currently nomading between Bali, Dubai, and the Mediterranean.

Got stuck? Have questions?

Join our Telegram group to ask questions, share your bots, and connect with other AI traders.

Join Telegram