All articles
Tradingview Pine ScriptOctober 1, 202614 min read

8 Step TradingView Pine Script Backtest to Catch Repaint and Fill Bugs

An 8 Step TradingView Pine Script backtest checklist to avoid repaint, fill, and trailing stop bugs. Export to CLI for reproducible analysis and deeper...

!Isometric backtest validation title card

To backtest a Pine Script strategy, write a script using the strategy() declaration, apply it to a chart, open Strategy Tester, and run it against historical bars. The tearsheet that appears, covering the Overview, Performance Summary, and the closed-trade ledger, tells you whether the rules held up. From there you can export the trade list or move to tools built for deeper statistical review.


TL;DR:

  • Ensure your account tier and chart setup support the necessary lookback period and indicator count before running any backtest.
  • Structure your Pine Script with one strategy.exit call per position, use input() for tunable parameters, and trigger signals on confirmed bars to prevent lookahead bias.
  • Apply scripts to appropriate timeframes, set realistic initial capital and position sizes, and verify proper strategy() declaration to generate meaningful backtest tearsheets.
  • Review the Performance Summary for risk metrics like maximum drawdown and balance profit with profit factor, especially when monthly returns fluctuate wildly or trade count is low.
  • Use external tools like the pinerun CLI for reproducible, automated backtests and consider Backtestify for comprehensive strategy comparison beyond TradingView's tearsheet.

Table of Contents

Prerequisites and setup before you run a backtest

A clean backtest starts with the right account tier and chart setup, not the script itself. TradingView's free plan limits intraday history and the number of indicators per chart, which matters if your strategy needs several years of 5-minute bars to produce a meaningful sample. Paid plans extend that historical depth and raise the bar count available in Strategy Tester, so check your plan's limits before concluding a strategy "doesn't work."

Once you know your data ceiling, open the Pine Editor from the bottom panel of any chart and start a new script using the strategy template rather than an indicator template. A strategy() declaration (not indicator()) is what unlocks the Strategy Tester tab and the trade simulation engine; scripts built with indicator() can plot signals but never generate a tearsheet.

Next, pick your symbol and timeframe deliberately. A strategy tested on 50 trades over three months tells you far less than one tested across multiple market regimes. Consider the Bar Magnifier feature when your strategy logic depends on intrabar price action, since it replays lower-timeframe data to refine fill accuracy, and keep calc_on_order_fills in mind if your exits depend on same-bar execution.

Before you run anything, confirm the basics:

  • Your account tier supports the lookback period your strategy needs to test.
  • The script compiles using strategy(), not indicator().
  • The chart symbol and timeframe match what you intend to trade live.
  • The script is saved and added to the chart before you open Strategy Tester.

With those four boxes checked, you're ready to write the actual trading logic.

Pine Script patterns that produce a valid backtest

The way you structure a strategy script determines whether its backtest results mean anything. Start the declaration with sensible defaults: set initial_capital to a realistic account size, and choose a qty type (percent of equity, fixed contracts, or cash value) that matches how you'd actually size positions. A strategy tested with one contract per trade regardless of account growth will understate both compounding gains and drawdown risk.

Entries and exits run through a small set of calls: strategy.entry opens a position, strategy.close or strategy.close_all exits it, and strategy.exit handles stop-loss and take-profit logic in one statement. Trailing stops are where many scripts go wrong. A common mistake, visible across troubleshooting threads on trailing-stop implementations in Pine Script, is calling strategy.exit multiple times for the same position, which can create duplicate or conflicting exit orders instead of one trailing mechanism. Use a single strategy.exit call with trail_points and trail_offset, and avoid layering a separate strategy.close condition on top of it unless you intend a manual override.

Parameterize every rule that might need tuning with input() instead of hardcoding values. This lets you adjust moving average lengths, stop distances, or filter thresholds directly from the Strategy Tester settings panel without touching code, which is the fastest way to test sensitivity across a range of values.

Lookahead bias is the quiet killer of backtest credibility. Signals should trigger on closed bars, using barstate.isconfirmed where needed, rather than reacting to intrabar price that might reverse before the candle closes. TradingView's Pine Script execution model documents how realtime bars recalculate repeatedly until they close, and how a rollback process restores the last confirmed state when a script reloads. If you don't account for this, a strategy can look flawless in historical testing and then produce different signals once it runs live on the same bar.

  • Set initial_capital and qty type to match realistic position sizing.
  • Use one strategy.exit call per position for trailing stops, not stacked exit conditions.
  • Wrap tunable values in input() so testers can override them without editing code.
  • Trigger signals on confirmed, closed bars to avoid lookahead distortion.

Pro Tip: Plot small shapes or labels at your entry and exit conditions during development so you can visually confirm the backtest fired trades where you expected, before trusting the numbers in the tearsheet.

Running the backtest in TradingView's Strategy Tester

Once your script compiles, apply it to the chart from the Pine Editor by clicking "Add to chart." A new tab labeled Strategy Tester appears at the bottom of the screen, split into Overview, Performance Summary, List of Trades, and Properties.

Before trusting any numbers, open the script's settings (the gear icon) and review the Inputs tab. This is where you override default parameter values without rewriting code, useful for quick sensitivity checks on stop distances or filter lengths. After changing an input, TradingView recalculates automatically, but if results look stale, reloading the script or briefly switching timeframes forces a full recalculation.

Timeframe choice changes what you're actually testing. A strategy on the 1 hour chart over two years produces a very different sample size than the same logic on the daily chart over the same period, so match the timeframe to how the strategy is meant to trade and make sure the available history covers enough bars to be meaningful.

To run a clean test from scratch:

  1. Add the compiled strategy script to the chart.
  2. Open the Strategy Tester tab and select the Overview panel.
  3. Open script settings and set inputs, position size, and commission assumptions.
  4. Confirm the chart timeframe and historical range match your intended strategy.
  5. Let the script recalculate fully, reloading if needed after changing inputs.
  6. Review the Performance Summary panel for aggregate statistics.
  7. Open the List of Trades tab to inspect individual entries and exits.
  8. Export the trade list to CSV where that option is available, or use Deep Backtesting to generate a more extensive report.

Deep Backtesting mode, referenced directly in TradingView's execution model documentation, extends the testable history and bar count beyond standard limits and includes an explicit "Generate report" action, which is worth using once you've settled on a parameter set you want to examine more closely.

Reading the tearsheet without fooling yourself

The Performance Summary panel groups results into three rough categories: returns, risk, and trade quality, and each one answers a different question. Net profit and gross profit show raw dollar performance, while comparing the strategy's return to simple buy-and-hold tells you whether the added complexity actually earned its keep.

Risk metrics matter more than the headline return. Max drawdown shows the worst peak-to-trough decline the strategy would have forced you to sit through, and a strategy with a high return but a 40% drawdown is a much harder thing to hold than one with a moderate return and a 12% drawdown. Volatility and risk-adjusted measures like Sharpe or Sortino ratios give a sense of how bumpy the ride was relative to the reward.

Trade-level statistics round out the picture:

  • Win rate alone says little without profit factor and average win/loss size alongside it.
  • Profit factor (gross profit divided by gross loss) above 1 means the strategy is net profitable, but a figure close to 1 implies fragility.
  • Expectancy per trade tells you what you'd earn on average on the next signal, which matters more for sizing decisions than win rate does.
  • Average bars in trade and winning or losing streaks reveal how patient the strategy requires you to be.

The pinerun backtest tearsheet organizes exactly these categories, returns, risk, and trades, alongside monthly return and trade grids and a list of the largest drawdown episodes, which is a useful structure to mentally apply even when you're reading TradingView's own Performance Summary. A monthly returns grid that shows profits concentrated in two or three months out of a multi-year test is a signal the strategy may be regime-dependent rather than consistently edge-positive. If a backtest shows fewer than a few dozen trades, or monthly results swing wildly between large gains and large losses, treat the result as preliminary and plan for further validation before increasing position size.

Common pitfalls and a debugging checklist

Most "broken" backtests trace back to one of four issues. The first is repainting, where a signal that looked valid on a closed bar shifts or disappears once new bars arrive. TradingView's execution model explains how realtime bars recalculate on every tick and how the rollback process restores prior confirmed values, which is exactly the mechanism behind many "it worked yesterday, not today" complaints. Testing signals strictly on closed, confirmed bars avoids most of this.

!Illustration of repainting and fill checks

The second is order fill behavior. Check whether calc_on_order_fills is enabled, since it changes whether a script recalculates mid-bar after an order fills, and verify commission, slippage, and minimum tick settings reflect something close to real trading costs.

The third is trailing stop and multiple-exit bugs, a frequent theme in community troubleshooting around trailing-stop implementations. Duplicated or conflicting exit calls can show up in the trade ledger as exits that don't match what you see plotted on the chart.

The fourth is sample size and overfitting: a handful of trades or parameters tuned too tightly to one historical period rarely survive contact with new data.

A reproducible debug sequence:

  1. Reproduce the suspicious trade visually on the chart using plotted markers.
  2. Verify the actual fill price in the trade ledger against what the chart shows.
  3. Toggle calc_on_order_fills and commission settings to isolate the cause.
  4. Export the trade ledger and check it line by line against your assumptions.

Pro Tip: When a single trade looks wrong, isolate it by narrowing the chart's date range to just that trade and rerunning the test, which makes fill price and timing discrepancies far easier to spot.

Exporting results and running backtests from the command line

The Strategy Tester UI is good for quick iteration, but a full statistical review needs the raw trade ledger, equity curve, and drawdown series exported for use outside TradingView. This is where a CLI tool like pinerun becomes useful. The pinerun backtest documentation describes commands that accept flags for symbol, timeframe, and history length, along with input overrides for parameter sweeps and output flags for CSV, JSON, and plot artifacts.

A typical workflow:

  • Run the strategy with flags such as --symbol, --tf, and --limit to define the test window.
  • Override script inputs directly from the command line using --input name=value, which pinerun validates against the script's declared inputs.
  • Export results with --csv, --plot, or --json to get the full tearsheet (returns, risk, trades, monthly grids, and drawdown charts) as reusable files.
  • Feed the exported data into spreadsheet tools or statistical packages for parameter sweeps or Monte Carlo analysis.

Prefer this approach over manual UI checks when you need reproducibility, scheduled reruns, or the ability to automate testing across many parameter combinations at once.

How Backtestify complements Pine Script backtesting

There are platforms built around the same metrics a TradingView tearsheet surfaces: win rate, profit factor, and maximum drawdown, with rigorous, evidence-based reports designed for closer scrutiny. Once you've exported results from TradingView or pinerun, you can bring those same rules into Backtestify to compare an original strategy against an improved version side by side on the same historical data. Some platforms publish real test results for strategies drawn from popular trading creators, including a Tori Trades trendline strategy, so users can see how published rules actually performed rather than taking a creator's claims at face value.

Realistic expectations after a promising backtest

A backtest confirms that a rule set behaved a certain way on historical data. It never guarantees the same behavior going forward, since markets change regime, liquidity shifts, and the exact conditions that produced past profits may not repeat.

Treat a strong backtest as a starting point. Check whether results hold up when you shift parameters slightly, set aside a portion of history for out-of-sample testing, and size positions conservatively during an initial stretch of paper or small live trading before committing real capital at scale.

— WAJDI

Try Backtestify to go beyond the Strategy Tester

Exporting a trade ledger from TradingView is a good first step, but turning it into a rigorous, side-by-side comparison of your original rules against an improved version takes more than a spreadsheet. Backtestify builds that comparison for you, along with a published library of tested strategies you can study before writing a single line of Pine Script.

Backtestify

Read the step-by-step backtesting guide to see the full workflow, or head to Backtestify to check plan options and start testing your own rules.

Sources

FAQ

How to backtest Pine Script for free?

TradingView's free plan lets you write and run strategy scripts in the Strategy Tester at no cost, though it limits available historical bars and intraday depth compared to paid tiers. For a free command-line option, the pinerun backtest CLI can export full tearsheets without a TradingView subscription.

Can ChatGPT backtest a trading strategy?

ChatGPT can help you write or debug Pine Script code and explain strategy logic, but it cannot execute a backtest itself since it has no access to historical market data or a simulation engine. You still need to run the script through TradingView's Strategy Tester or a tool like the pinerun CLI to get real results.

What trading strategy has a 90% win rate?

Win rate alone also says little without profit factor and average win and loss size alongside it.

Is TradingView free for backtesting?

TradingView offers a free plan that includes basic Strategy Tester access, though with reduced historical data depth and fewer indicators per chart than paid plans. Traders who need longer lookback periods or Deep Backtesting features typically need a paid TradingView subscription.

What causes a Pine Script backtest to repaint?

Repainting usually happens when a signal reacts to an unconfirmed, realtime bar that later recalculates as new price data arrives. TradingView's execution model documentation explains how realtime bars and the rollback process can cause this, and testing signals on closed, confirmed bars is the standard fix.

Recommended

Read next

Backtest ICT Without Code: Walk Forward Workflow for ICT Traders

Continue

Want these checks applied to your own rules automatically?

Run a backtest