RSI Trading Strategy: Thresholds and Trend Filters
An RSI trading strategy needs an entry event and an exit rule. Buying when RSI first falls below 30 is different from waiting for it to recover above 30. This guide compares both rules, adds an optional EMA trend filter, and provides a TradingView strategy with stops and a maximum holding period. An overbought or oversold reading alone does not establish that price will reverse.
Choose the RSI entry event before testing
RSI measures momentum on a 0 to 100 scale. A 14-bar RSI with 30 and 70 thresholds is a starting convention, not a calibrated trading edge. This page focuses on executable rules; see the RSI indicator reference for the calculation and the TradingView strategies hub for other approaches.
Three rules with different tradeoffs
- Enter the extreme: buy when RSI crosses from at or above 30 to below 30; short when it crosses from at or below 70 to above 70. This takes exposure while momentum is still moving against the trade. Remaining below 30 is a state, not a new crossing each bar.
- Wait for recovery: buy when RSI crosses back above 30; short when it crosses back below 70. This waits for a change in RSI direction across the threshold, but the price can resume its prior move after the signal.
- Filter either event: allow longs only when the signal bar closes above an EMA, and shorts only below it. The example uses 200 bars. This rejects some countertrend entries and some early reversals; it does not establish which remaining trades will succeed.
Illustrative sequence: 34, 28, 24, 31
These are hypothetical RSI readings at four consecutive closes. With a lower threshold of 30, the first rule signals at 28; the recovery rule signals at 31. Neither fires again at 24. With the trend filter enabled, a long is rejected if that signal bar closes at or below its EMA. If price later moves above the EMA while RSI stays above 30, the missed crossing is not replayed.
Entry timing and risk rules
The script evaluates completed chart bars, takes entries only while flat, and ignores opposite signals during an open trade. Under its supplied execution settings, a market entry is normally filled at the next bar's open. The signal marker therefore marks the decision bar, not the fill.
At each signal, the script converts 1.5% of the signal close into a fixed tick distance for the stop and 3% for the target. Both distances are anchored to the eventual entry fill. They are not exact percentages of that fill if price gaps. For example, an illustrative signal close of 100 and tick size of 0.01 gives 150 stop ticks and 300 target ticks. A long filled at 102 would have planned levels of 100.50 and 105.00, before any exit slippage.
If the trade survives through the close of its twentieth holding bar, counting the entry bar as one, it requests a market exit for the next available tick. Stops can fill worse than their planned price, and a time exit does not cap loss. The 10% equity allocation is position size, not a promise to risk 10% or 1.5% of the account.
Sources and scope
Mechanics checked on October 16, 2026: TradingView RSI documentation, strategy execution and broker emulator, strategy exit FAQ, and repainting documentation. Threshold comparisons and the numerical sequence above are illustrative design choices, not historical results. This is educational material, not investment advice.
| Component | Description | Role |
|---|---|---|
| Momentum | RSI of chart closes; evaluate only confirmed bars. | 14 bars; 30/70 |
| Entry mode | Select Enter extreme or Recovery cross for both directions. | Recovery by default |
| Trend gate | Long above EMA; short below EMA; equality rejects entry. | Optional; off by default |
| Position rule | One trade at a time; no reversal on an opposite RSI signal. | Flat entries only |
| Exit rule | Fixed stop and target distances, plus a maximum holding time. | Bracket or time exit |
Pine Script v6 Implementation
//@version=6
strategy("RSI Threshold Strategy Example", overlay=true, initial_capital=10000, default_qty_type=strategy.percent_of_equity, default_qty_value=10, pyramiding=0, commission_type=strategy.commission.percent, commission_value=0.1, slippage=1, calc_on_every_tick=false, calc_on_order_fills=false, process_orders_on_close=false)
rsiLength = input.int(14, "RSI Length", minval=2)
lowerLevel = input.int(30, "Oversold Level", minval=1, maxval=49)
upperLevel = input.int(70, "Overbought Level", minval=51, maxval=99)
entryMode = input.string("Recovery cross", "Entry Mode", options=["Recovery cross", "Enter extreme"])
useTrendFilter = input.bool(false, "Use EMA Trend Filter")
emaLength = input.int(200, "Trend EMA Length", minval=2)
stopPercent = input.float(1.5, "Stop Distance (% of signal close)", minval=0.1, step=0.1)
targetPercent = input.float(3.0, "Target Distance (% of signal close)", minval=0.1, step=0.1)
maxHoldingBars = input.int(20, "Maximum Holding Bars", minval=1)
rsiValue = ta.rsi(close, rsiLength)
trendEma = ta.ema(close, emaLength)
// Evaluate each crossing on every bar, before combining conditions.
enterOversold = ta.crossunder(rsiValue, lowerLevel)
leaveOversold = ta.crossover(rsiValue, lowerLevel)
enterOverbought = ta.crossover(rsiValue, upperLevel)
leaveOverbought = ta.crossunder(rsiValue, upperLevel)
longEvent = entryMode == "Recovery cross" ? leaveOversold : enterOversold
shortEvent = entryMode == "Recovery cross" ? leaveOverbought : enterOverbought
ready = not na(rsiValue[1]) and close > 0 and (not useTrendFilter or bar_index >= emaLength - 1)
longSignal = barstate.isconfirmed and ready and strategy.position_size == 0 and longEvent and (not useTrendFilter or close > trendEma)
shortSignal = barstate.isconfirmed and ready and strategy.position_size == 0 and shortEvent and (not useTrendFilter or close < trendEma)
// Freeze signal-close distances and anchor each bracket to the entry fill.
stopTicks = math.max(1, math.round(close * stopPercent / 100 / syminfo.mintick))
targetTicks = math.max(1, math.round(close * targetPercent / 100 / syminfo.mintick))
if longSignal
strategy.entry("Long", strategy.long)
strategy.exit("Long bracket", "Long", loss=stopTicks, profit=targetTicks)
else if shortSignal
strategy.entry("Short", strategy.short)
strategy.exit("Short bracket", "Short", loss=stopTicks, profit=targetTicks)
// Entry bar counts as the first holding bar. Market close fills next tick.
if barstate.isconfirmed and strategy.opentrades > 0
heldBars = bar_index - strategy.opentrades.entry_bar_index(0) + 1
if heldBars >= maxHoldingBars
strategy.close_all(comment="Maximum holding period")
plot(useTrendFilter ? trendEma : na, "Trend EMA", color=color.orange)
plotshape(longSignal, title="Long decision", location=location.belowbar, style=shape.triangleup, color=color.green, size=size.small)
plotshape(shortSignal, title="Short decision", location=location.abovebar, style=shape.triangledown, color=color.red, size=size.small)What the script does at each bar close
- 1
The selected crossing defines the event. All four crossing calculations run on every bar, including bars when a trade is already open.
- 2
The flat-position and optional EMA gates decide whether that event can submit an order. A rejected event is discarded rather than saved for a later entry.
- 3
The bracket is submitted alongside the entry using tick distances. Its distance is frozen at the signal; it does not move every bar as price changes.
- 4
After the entry fills, the entry bar counts as holding bar one. A surviving position receives a market-close request at the close of holding bar 20 by default.
- 5
The supplied strategy uses 0.1% commission and one tick of slippage as illustrative cost assumptions. Change Properties to match the intended market before comparing results.
Backtest Assumptions and Metrics
No measured backtest is supplied for this script. Paste it into TradingView Pine Editor and add it to a standard candlestick chart. Record the exchange symbol, timeframe, date range, session, inputs and strategy Properties. The table below lists simulation assumptions, not investment results.
| Metric | Value | Interpretation |
|---|---|---|
| Starting capital | 10,000 | Simulation amount; record the account currency. |
| Position allocation | 10% of equity | Not a fixed account-risk percentage. |
| Commission | 0.1% per order | Illustrative cost on entries and exits; replace it. |
| Slippage | 1 tick | Illustrative assumption; also test worse fills. |
| Stop / target | 1.5% / 3% | Signal-close distances converted to ticks from the fill. |
| Time exit | 20 bars | Close request at bar 20; next available tick fills it. |
| Return / drawdown | Not measured | No profitability or risk estimate is claimed. |
Compare four runs: extreme entry with and without the EMA gate, then recovery entry with and without it. Keep costs, exits, symbol and dates identical. Separately inspect persistent uptrends, downtrends and ranges; record rejected signals as well as completed trades. Compare net results, drawdown, trade count and average win/loss, including long and short results separately. Reserve a later period before choosing settings and test the chosen rules there unchanged. A better result on the tuning period can reflect overfitting.
Build and compare your RSI rules with Pineify
Use the Pine Script AI Coding Agent to draft or revise the strategy from a written specification. Include the entry mode, bar-close timing, trend gate, flat-position rule, bracket distances and time exit. Inspect the output before testing it.
The Visual Pine Script Editor offers RSI indicators and condition-based strategy building. For custom holding-period logic, use the code workflow and verify the generated rules. The Strategy Optimizer compares strategy input combinations on TradingView. Keep a reserved period outside parameter selection; a top-ranked backtest is not evidence of future returns.
Strategy Optimization Suggestions
Test persistent extremes explicitly
In a sustained decline, the first oversold crossing can be followed by further losses. A recovery cross can also fail when RSI briefly rebounds before falling again. Inspect these trades rather than assuming 30 marks a price floor.
Measure what the EMA gate removes
Compare accepted and rejected signals. The gate can miss a recovery that begins below the EMA; price can also cross the EMA repeatedly in a range. Keep its effect separate from changing RSI thresholds.
Limit the parameter search
Write down the small set of lengths, thresholds and holding periods you intend to compare. Log unsuccessful settings too. Adding trials after seeing results increases the chance of choosing a historical coincidence.
Review stop and time exits together
A shorter holding limit may close a trade before a delayed rebound; a longer limit leaves exposure open. Examine exit reasons and adverse price moves, not just the percentage of winning trades.
Frequently Asked Questions
Turn your RSI rules into a testable strategy
Give Pineify the entry event, trend gate, stop distance and holding limit. Review the generated code, test it with realistic costs, and keep the validation period separate from parameter selection.
Disclaimer: Trading involves significant risk. The strategies and code provided are for educational purposes only and do not constitute financial advice. Past performance is not indicative of future results.
Related Strategy Tutorials
Best RSI Settings for 1 Minute Charts
Compare RSI 5, 7, 9, and 14, copy Pine Script v6, and test 70/30 or 80/20 crossover rules.
Mean Reversion Strategy Tutorial
Learn how to build, backtest, and optimize a Mean Reversion Strategy on TradingView using Bollinger Bands and RSI with Pine Script v5.
Bollinger Bands Breakout Strategy Tutorial
Master the Bollinger Bands Squeeze and Breakout strategy on TradingView. Learn the Pine Script v5 code and professional analysis with Pineify.
MACD Crossover Strategy Tutorial
Learn how to build, backtest, and optimize a MACD crossover strategy on TradingView using Pine Script v5 and Pineify Deep Report.
VWAP Strategy Tutorial
Learn how to build and backtest a professional VWAP mean reversion strategy on TradingView with full Pine Script v5 code.