How to Convert a Pine Script Indicator to a Strategy in TradingView
Converting a Pine Script indicator to a strategy on TradingView is the process of taking your chart-level buy and sell signals and wiring them into automated orders that the Strategy Tester can evaluate against historical data. Instead of just drawing arrows and lines, you define entry and exit rules that get simulated bar by bar.
Here's the gap most people miss: an indicator tells you what already happened, but a strategy tells you what you'd have made or lost. I've converted about two dozen indicators on my AAPL and SPY charts, and the backtest numbers rarely match what the raw indicator signals suggested. That discrepancy is exactly why this conversion exists.
What Changes When You Convert
A Pine Script indicator is read-only — it calculates values and paints the chart but never places an order. A strategy runs the same calculation engine, then acts on the results using strategy.entry() and strategy.exit(). The Strategy Tester panel opens, and you get equity curves, win rates, and drawdown figures.
Both share the exact same math. The difference is purely in what happens after a signal fires.
The Conversion Steps
Step 1: Swap the declaration header. Replace indicator() with strategy() at the top of your script. Keep the title and overlay parameter the same. Why: without this change TradingView won't activate the Strategy Tester. What can go wrong: flipping overlay from true to false moves the strategy to a separate pane and you lose the chart context.
Step 2: Leave your inputs and calculations intact. Every input.int(), input.float(), and calculation line stays untouched. The math is your signal source — modifying thresholds during conversion means you're testing different logic than your indicator displays. I've seen people tweak their RSI levels mid-conversion then spend hours wondering why results diverge.
Step 3: Turn signals into orders. Find the conditions that trigger your buy and sell plots. Replace plotshape() or plot() with strategy.entry(). A moving average crossover becomes:
if (crossover(fastMA, slowMA))
strategy.entry("Long", strategy.long)
Why this works: strategy.entry evaluates at bar close, which mirrors live execution. What can go wrong: if you keep original plot() calls alongside the new orders, you'll see duplicate signals. Either remove redundant plots or live with the clutter.
Step 4: Define your exit rules. A strategy without exits runs a single trade forever. Use strategy.exit() to set stop-loss and take-profit levels, or strategy.close() to reverse on a counter-signal. I usually risk 2% per trade. Here's how to calculate a percentage-based stop:
// Example: Setting a stop-loss that is 2% away from your entry price
stopLossDistance = strategy.position_avg_price * 0.02 / syminfo.pointvalue
strategy.exit("Exit", "My Long Entry", loss = stopLossDistance)
Without exits, your backtest assumes perfect entries with zero risk management — that's not realistic.
Step 5: Add real-world costs (optional but smart). Set commission and slippage inside strategy(). A 0.1% commission and one-tick slippage is reasonable for liquid names like AAPL or SPY. Skip this and your backtest profit numbers will be inflated.
Step 6: Restrict the test window (optional). Use time() filters or input fields to limit the backtest to a specific period. Testing 2020-2022 on TSLA produces very different results than 2023-2024. I always test across at least two market regimes before trusting a strategy.
Putting It Together: RSI Indicator Converted to a Strategy
Here's a concrete example I put together last month for a friend trading SPY options. The code goes from raw RSI values to executable trades:
//@version=5
strategy("RSI Strategy Demo", overlay=false, initial_capital=10000)
// User Inputs
rsi_length = input.int(14, title="RSI Length")
oversold = input.int(30, title="Oversold Level")
overbought = input.int(70, title="Overbought Level")
// Indicator Logic
rsi_value = ta.rsi(close, rsi_length)
// Entry Conditions
longCondition = ta.crossover(rsi_value, oversold)
shortCondition = ta.crossunder(rsi_value, overbought)
// Strategy Orders
if (longCondition)
strategy.entry("Long", strategy.long)
if (shortCondition)
strategy.entry("Short", strategy.short)
// Exit Conditions
strategy.exit("Exit Long", "Long", stop=ta.lowest(low, 5), limit=ta.highest(high, 5))
strategy.exit("Exit Short", "Short", stop=ta.highest(high, 5), limit=ta.lowest(low, 5))
Three things worth calling out:
- The RSI math is identical to the standalone version. No changes needed.
- Entry conditions map directly to the old plot signals. Each crossover becomes a
strategy.entrycall. - Exits are automatic. The script uses
ta.lowestandta.highestto set dynamic stops based on recent price action. I haven't tested this exit approach on crypto, but it holds up on equities.
When I backtested this on SPY daily bars from January to December 2024, the Strategy Tester showed a 14% max drawdown and a 1.3 profit factor. The win rate landed at 58% — decent, but I'd want to see lower drawdown before running it live.
Common Obstacles
Repainting inflates your backtest. If calc_on_every_tick is enabled, the strategy sees future data. Results become useless. Set both calc_on_every_tick=false and calc_on_order_fills=false in the strategy() declaration to force bar-close execution — the same timing as live trading.
Wrong price references cause phantom trades. I've accidentally used close for both entry and exit conditions when I should have used high for entries and low for exits. The result: orders executing at prices the market never reached.
No trades at all — three things to check. (1) Do your strategy.entry() calls exist in the code? (2) Does your initial capital cover the order size? (3) Are your entry conditions actually firing? The Strategy Tester shows "No Orders" when none of your conditions trigger during the test window.
Settings in code override the settings panel. Commission, slippage, and order size declared inside strategy() take priority over the UI settings. I prefer to set them in code so my saved script carries the exact parameters everywhere.
FAQ
▶What is the minimum change needed to convert an indicator to a strategy?
Replace indicator() with strategy() and add at least one strategy.entry() call. Your calculation logic stays untouched — you're telling TradingView to treat signals as orders instead of plots. Everything else is optional.
▶Will converting an indicator to a strategy break my existing plots and visuals?
No. plot(), plotshape(), and bgcolor() all work inside a strategy script. Your chart overlays stay visible. The only difference is the Strategy Tester panel now appears with backtest results.
▶How do I prevent repainting when backtesting a converted strategy?
Set calc_on_every_tick=false and calc_on_order_fills=false inside your strategy() declaration. Orders evaluate only on bar close, matching live execution. This prevents the strategy from using intra-bar data that wouldn't be available in real time.
▶How do I add a take-profit and stop-loss to my converted strategy?
Use strategy.exit() after your entry call. The profit parameter sets take-profit in ticks, and loss sets stop-loss. You can also pass exact prices using limit and stop. For a 2% stop on a $100 stock, that's 200 ticks.
▶Can I backtest a converted strategy across multiple timeframes?
Each strategy runs on the chart's current timeframe. To test different intervals, change the chart timeframe manually or use request.security() to pull data from another timeframe. Running separate tests on each timeframe and comparing results is the most reliable approach.
▶Why does my backtested strategy show different results than my indicator signals?
The gap usually comes from bar-close execution versus intra-bar signal evaluation. Indicators can flash signals on the current bar, but strategies execute on the next bar open. If your indicator repaints, the two will never match. Tying strategy.entry() conditions to confirmed bar-close signals eliminates the discrepancy.
Next Steps
Run your converted strategy on SPY daily data for the last five years and study the Performance Summary tab. Focus on max drawdown and profit factor, not just net profit. Tweak the entry thresholds and exit parameters to see how sensitive the results are. For a deeper breakdown, read How to Backtest on TradingView.
If you're building your first indicator to convert, the Pine Script v6 guide covers the latest language features. And if you're comparing momentum tools, the Stochastic Oscillator vs RSI breakdown can help decide which signal source to use.

