AI Pine Script RSI Indicator Mistakes
How to prompt an AI for RSI, MACD, stochastic and divergence indicators in Pine Script v6, then audit its code for the syntax and repainting mistakes common in this category.
Marketing
An ai pine script rsi indicator can compile cleanly and still produce unreliable signals. The main failure points are skipped oscillator calculations, invalid pivot conditions, markers shifted into the past, and alerts that fire before the realtime bar closes. The broader Best AI for Pine Script guide explains how to choose and supervise a coding assistant.
The practical goal is to give the model an exact Pine Script v6 specification, then audit its output before using the indicator. The process below covers RSI, MACD, stochastic oscillators, divergence detection, confirmed-bar alerts, and a corrected RSI divergence example.
What This Indicator Category Covers
RSI, MACD And Stochastic Basics
J. Welles Wilder presented RSI in his 1978 book, New Concepts in Technical Trading Systems. His default calculation uses 14 periods, with 70 commonly treated as overbought and 30 as oversold.1
MACD was developed by Gerald Appel in the late 1970s. Its standard construction subtracts a 26-period EMA from a 12-period EMA, applies a 9-period EMA as the signal line, and plots the difference between MACD and the signal line as a histogram.2
A stochastic oscillator compares the current close with a recent high-low range, producing a raw %K line and a smoothed %D line. In Pine v6, ta.stoch(source, high, low, length) returns only the raw %K. A slow or full stochastic needs ta.sma() to smooth %K and a second ta.sma() for %D, so a call such as ta.stoch(close, 14, 3, 3) does not match the function at all.
All three are momentum indicators, but their Pine implementations have different signatures, return values and smoothing requirements. Those details give an AI assistant more ways to go wrong than the simpler trend and moving average indicators do.
Divergence Detection Defined
Bullish divergence means price records a lower low while the oscillator records a higher low. Bearish divergence means price records a higher high while the oscillator records a lower high. RSI documentation also warns that bearish divergences can recur during strong uptrends and bullish divergences can recur during strong downtrends.1 MACD has the same limitation, with divergences described as commonplace during strong trends.2
Why AI Struggles With Oscillators
Divergence code must confirm swing points, retain previous pivots, compare price and oscillator values, and distinguish a pivot bar from its later confirmation bar. Generated code often collapses those separate steps into one condition.
TradingView's repainting page notes that MACD and RSI show confirmed values on historical bars but fluctuate on a realtime, unconfirmed bar until it closes.3 A prompt must therefore say whether signals should respond intrabar or wait for confirmation. Neither behavior is accidental, but only one may match your alert design.
Prompting AI For Oscillator Code
Pin Pine Script v6
State Pine Script v6 on the first line. TradingView's v6 migration guide lists three changes that matter for oscillators: "int" and "float" values are no longer implicitly cast to "bool", the and and or operators now evaluate conditions lazily, and the offset parameter of plot() and similar functions no longer accepts "series" values.4
Name Exact Inputs And Conditions
Specify the source, oscillator length, thresholds, pivot strength, and exact crossover or divergence rule. Do not ask for a generic RSI signal and assume the model will select your intended defaults.
- Source: close, open, hl2, or another named series
- RSI length: for example, 14
- Thresholds: for example, 70 and 30
- Pivot settings: separate left and right bars
- Signal rule: exact price and oscillator comparisons
Require Confirmed-Bar Logic Upfront
Ask the model to gate the final signal conditions with barstate.isconfirmed. TradingView's Bar states page defines it as true on all historical bars and on the last (closing) update of a realtime bar.5 Also require every alert() call to use alert.freq_once_per_bar_close.
Reusable Prompt Template
Pine version: Write Pine Script v6 only.
Indicator: Build an RSI divergence indicator, not a strategy.
Inputs: close source, RSI length 14, overbought 70, oversold 30, left pivot bars 3, right pivot bars 3.
Conditions: Bullish divergence requires price lower low and RSI higher low. Bearish divergence requires price higher high and RSI lower high.
Calculation: Compute ta.rsi() unconditionally on every bar.
Pivots: Test pivot values with not na(). Do not shift signal markers into the past.
Confirmation: Final signals must require barstate.isconfirmed.
Alerts: Use alert() with alert.freq_once_per_bar_close and include ticker, action, quantity, price, and RSI value.
Each line prevents a specific failure: version mixing, hidden defaults, skipped history, numeric conditions, misleading pivot placement, intrabar signal changes, or incomplete webhook messages.
Worked Example: RSI Divergence Indicator
The Prompt And Raw Output
A realistic request would use the template above and ask for both bullish and bearish divergence. The following safe review copy comments out two representative generated faults, allowing the surrounding script to compile while preserving the lines that require correction.
//@version=6
indicator("AI RSI Review Copy")
int rsiLength = input.int(14, "RSI Length", minval = 1)
int rightBars = input.int(3, "Right Bars", minval = 1)
float rsiValue = ta.rsi(close, rsiLength)
float pivotHigh = ta.pivothigh(high, 3, rightBars)
// Fault 1: RSI is conditionally evaluated.
// bool momentumUp = close > open and ta.rsi(close, rsiLength) > 50
// Fault 2: A float is used as a Boolean condition.
// if pivotHigh
// label.new(bar_index, pivotHigh, "High")
plot(rsiValue, "RSI", offset = 0)
Auditing The Generated Code
First, search for ta.rsi() inside an and, or, ternary expression, or local conditional block. TradingView's v6 migration guide uses close > open and ta.rsi(close, 14) > 50 to demonstrate how lazy evaluation can skip the RSI call.4
Second, find conditions such as if pivotHigh. A pivot function returns a price or na, not a Boolean, so v6 rejects it as an if condition. Third, inspect every offset. A fixed input or constant is acceptable, but a bar-by-bar series offset is not.
Corrected Pine Script V6 Version
//@version=6
indicator("Confirmed RSI Divergence", overlay = false)
int rsiLength = input.int(14, "RSI Length", minval = 1)
float source = input.source(close, "Source")
float overbought = input.float(70.0, "Overbought")
float oversold = input.float(30.0, "Oversold")
int leftBars = input.int(3, "Left Pivot Bars", minval = 1)
int rightBars = input.int(3, "Right Pivot Bars", minval = 1)
float quantity = input.float(1.0, "Alert Quantity", minval = 0.0)
float rsiValue = ta.rsi(source, rsiLength)
float priceLow = ta.pivotlow(low, leftBars, rightBars)
float priceHigh = ta.pivothigh(high, leftBars, rightBars)
float rsiLow = ta.pivotlow(rsiValue, leftBars, rightBars)
float rsiHigh = ta.pivothigh(rsiValue, leftBars, rightBars)
bool confirmedLowPair = not na(priceLow) and not na(rsiLow)
bool confirmedHighPair = not na(priceHigh) and not na(rsiHigh)
var float previousPriceLow = na
var float previousRsiLow = na
var float previousPriceHigh = na
var float previousRsiHigh = na
bool bullishDivergence = false
bool bearishDivergence = false
if confirmedLowPair
bullishDivergence := not na(previousPriceLow) and not na(previousRsiLow) and priceLow < previousPriceLow and rsiLow > previousRsiLow
previousPriceLow := priceLow
previousRsiLow := rsiLow
if confirmedHighPair
bearishDivergence := not na(previousPriceHigh) and not na(previousRsiHigh) and priceHigh > previousPriceHigh and rsiHigh < previousRsiHigh
previousPriceHigh := priceHigh
previousRsiHigh := rsiHigh
bool bullishSignal = bullishDivergence and barstate.isconfirmed
bool bearishSignal = bearishDivergence and barstate.isconfirmed
plot(rsiValue, "RSI", color = color.blue)
hline(overbought, "Overbought", color = color.red)
hline(oversold, "Oversold", color = color.green)
plotshape(bullishSignal, "Bullish Divergence", shape.triangleup, location.bottom, color.green, size = size.small, offset = 0)
plotshape(bearishSignal, "Bearish Divergence", shape.triangledown, location.top, color.red, size = size.small, offset = 0)
if bullishSignal
string message = "{\"ticker\":\"" + syminfo.ticker + "\",\"action\":\"buy\",\"quantity\":" + str.tostring(quantity) + ",\"price\":" + str.tostring(close) + ",\"message\":\"RSI " + str.tostring(rsiValue, "#.00") + "\"}"
alert(message, alert.freq_once_per_bar_close)
if bearishSignal
string message = "{\"ticker\":\"" + syminfo.ticker + "\",\"action\":\"sell\",\"quantity\":" + str.tostring(quantity) + ",\"price\":" + str.tostring(close) + ",\"message\":\"RSI " + str.tostring(rsiValue, "#.00") + "\"}"
alert(message, alert.freq_once_per_bar_close)
The RSI calculation now runs on every bar. Pivot availability is tested with not na(), signals remain on their confirmation bars, and alert execution waits for bar close.
Syntax Mistakes AI Makes Here
Lazy Evaluation Breaks RSI Calls
Pine v6 evaluates and and or lazily. If the left side settles the result, Pine skips the right side. The migration guide's own example is an RSI call: when close > open is false, ta.rsi() does not run on that bar, so its history has gaps.4 Compute the oscillator globally, then reference the stored result in conditions.
Boolean Casting Errors On Pivots
TradingView's CE10101 error page explains that as of v6, Pine no longer implicitly casts "int" or "float" values to "bool", so the condition of an if statement must already be a bool. Our guide to v6 Boolean changes covers the details. For pivots, the clearest fix is to test the result with not na(), since the function returns na on every bar without a confirmed pivot.6
Oscillator Function Argument Mix-Ups
Generated stochastic code may compress raw %K and both smoothing steps into one call with extra arguments, which does not compile. Ask for a separate named variable at each step: one for raw %K from ta.stoch(), one for smoothed %K, and one for %D. For MACD, ta.macd(source, fastlen, slowlen, siglen) returns three series (the MACD line, signal line and histogram), so check that the assistant unpacks them in that order.
Repainting Mistakes Specific To Oscillators
Pivots Confirm Several Bars Late
With left and right strengths of 3, ta.pivothigh() detects a pivot three bars after the pivot bar and returns na on other bars. TradingView's Plots page shows how a negative offset shifts the plotted value back to the pivot bar, even though the script only learned about it later.7
For automation, keep the alert and default marker on the confirmation bar. A negative offset can be offered as an optional visual aid, but it must not imply that the signal was available earlier. The same concern appears in support, resistance and pivot indicators.
Crosses Flip Before Bar Close
Historical bars contain fixed OHLC records, while realtime high, low, and close values can change repeatedly before the bar closes. TradingView's repainting page illustrates this with a cross on a realtime bar that still has 21 seconds to run, noting that anything could happen until then.3
Gating Signals On Bar Confirmation
Use barstate.isconfirmed on the final signal, not only on its plot. The Bar states page also warns that it will not work when used in a request.security() call.5 If the indicator requests higher-timeframe data, tell the AI to design confirmation for that requested context rather than inserting the bar-state check inside the request.
Review Checklist Before Using It
Four Checks For Any Oscillator
- Compute
ta.rsi(),ta.macd(), and other history-dependent functions before conditional filtering. - Test pivot values with
not na(), never with implicit truthiness. - Require
barstate.isconfirmedor an equivalent confirmed-bar test on final signals. - Use constants or inputs for offsets, never series values.
Testing Historical And Realtime Behavior
Run the indicator on a live chart and watch several realtime bars. Confirm that markers and alerts do not appear and disappear before the close. Then compare TradingView's alert log, which records the time and exact message of each alert that fired, with the signals TradersPost received for the strategy. Matching each log entry to a received signal shows quickly whether a webhook went missing or arrived altered.
Turning Confirmed Signals Into Alerts
Choose A Close-Only Frequency
alert() supports alert.freq_once_per_bar, alert.freq_once_per_bar_close, and alert.freq_all. With the close-only option, an alert triggers only when the realtime bar closes and an alert() call runs during that iteration. TradingView's Alerts page calls close-only triggering the simplest way to avoid alerts that repaint.8
Write Dynamic Alert Messages
alert() accepts a series string, so the message can include runtime values created with str.tostring(). It works in indicators and strategies. By comparison, alertcondition() works only in indicators and requires a constant message, although placeholders can be used.8
Send Confirmed Webhook Alerts
A TradersPost signal is JSON sent to a strategy's webhook URL. The payload can include ticker, action, quantity and optional order instructions; the example above also sends price and a free-text message. TradersPost then applies your subscription settings and routes the order to the broker account you connected. Build that message only after the confirmed-bar gate passes, then paper trade the corrected RSI or MACD alert before enabling automated live submission.
Enable live orders only after the chart marker, TradingView's alert log and the signal TradersPost received have agreed across several sessions on a paper account.
Bottom Line
- Prompt for Pine Script v6, exact inputs, explicit calculations, and confirmed-bar alerts.
- Calculate oscillators unconditionally so lazy evaluation cannot break their history.
- Treat pivots as delayed confirmations and test them with
not na(). - Keep automated alerts on the confirmation bar and use once-per-bar-close frequency.
- Apply the same audit process to volatility indicators and volume and VWAP indicators.
AI can accelerate Pine development, but it cannot replace version checks, realtime observation, and webhook verification. Return to the Best AI for Pine Script guide for the broader workflow, then test the corrected alert from chart to paper account before live deployment.
Frequently Asked Questions
Why Do Realtime RSI Values Differ?
Historical bars have fixed OHLC values. Realtime high, low, and close values remain fluid until the bar closes, so RSI and MACD can fluctuate on the unconfirmed bar. That behavior is expected rather than automatically indicating a coding bug.
What Is Lazy Evaluation?
Lazy evaluation skips the right side of an and or or expression when the left side already determines the result. If ta.rsi() is on the skipped side, it may not execute on every bar. Calculate RSI on its own line before using it in conditions.
How Do Pivots Avoid Repainting?
A pivot is only available after its right-side bars have elapsed. Plot and alert on that confirmation bar by default, avoid relocating the operational signal into the past, and require barstate.isconfirmed. Remember that this bar-state check does not work inside request.security().
How Do RSI And MACD Differ?
RSI divergence compares price swings with a bounded oscillator commonly interpreted around 70 and 30. MACD divergence compares price swings with a line that moves around zero and has no fixed upper or lower boundary. Both can generate repeated divergence signals in strong trends.
How Do I Automate Confirmation?
Gate the signal with barstate.isconfirmed, call alert() with alert.freq_once_per_bar_close, and construct a dynamic JSON message containing the fields expected by the webhook endpoint. Verify the alert in a paper-trading workflow before using live automation.
References
1 Relative Strength Index
2 MACD Oscillator
3 Repainting
4 To Pine Script Version 6
5 Bar States
6 CE10101 Boolean Condition Error
7 Plots
8 Alerts