TradingView Backtest Date Range Design: Warm-Up, Start Dates and Data Coverage
“Tested from 2022” can mean that calculation began in 2022, or that earlier bars prepared the indicators while orders began in 2022. Those are different experiments. Separate the TradingView history boundary, Pine warm-up, order-eligible window and treatment of the final open trade before comparing results. This guide establishes that foundation; it does not teach OOS or walk-forward design.
Who this guide is for: Pine developers fixing a test start date, unexplained period sensitivity or non-comparable Strategy Tester exports
Key points to understand first
- Record accessible data, warm-up, order eligibility and closure as distinct ranges rather than calling all of them the test period.
- Calculate indicators before the start date and gate only order creation when earlier bars are needed for preparation.
calc_bars_countcan constrain recent bars available to the script; it does not manufacture older market data.- Regular Strategy Tester and Deep Backtesting can use different history and need not return identical results.
- Attach actual first/last trade times, trade count and open-trade treatment to every comparison export.
Bars before the start date still have a job
- 01
The history Pine can access
- 02
Prepare values; no orders
- 03
Orders may be created
- 04
Separate open and closed samples
Separate the calculation range from the trading range
A reproducible date setup needs more than one start and end field. Record at least four layers: the history Pine could access, the bars used to prepare dependent series, the range where new orders were eligible, and the rule applied to positions at the end.
| Layer | What starts it | What ends it | Effect |
|---|---|---|---|
| Accessible data | Symbol, timeframe, plan and regular/deep mode | Execution date and data limits | The calculable dataset |
| Warm-up | First calculation bar | All dependencies become usable | Initial na and state sensitivity |
| Order-eligible window | An input.time start gate | The end gate | Candidate entries and trade count |
| Closure boundary | Final entry or close rule | Last exit | Closed versus open trade sample |
The label “2022–2025” is ambiguous until you identify which layer it describes.
Visible chart history is not a universal test boundary
A regular strategy executes sequentially over historical bars accessible in its current dataset. The first bar can depend on symbol, timeframe, data availability, plan and execution date. If that starting point moves later, accumulated state and early trades can change even with identical source and inputs.
Deep Backtesting is a separate report mode that can use available stored history beyond the bars currently loaded on the chart and lets the user select a date range. Its dataset can differ from the regular test. Intraday coverage also varies by symbol and timeframe, and current official bar and trade limits still apply.
| Factor | What changes | Record |
|---|---|---|
| Symbol | Listing start, gaps and exchange history | Full ticker ID |
| Timeframe | Bar count and reachable calendar span | Timeframe string |
| Regular / Deep | Underlying history used for the report | Test mode |
| Plan / execution date | Bar entitlement and moving start | Run date and plan context |
| calc_bars_count | Recent bars exposed to the script | Calculated bars setting |
Measure the first and last accessible bars; do not write only “all history”.
Audit the dependency graph, not only the largest input length
A 50-period simple average is na on early bars, but “warm-up equals the largest length” is not a universal rule. An ATR passed into another average and then a percentile has a dependency chain. Recursive averages and state machines can emit a value before their sensitivity to the initial condition has faded.
minimum readiness ≠ always max(input lengths)usable evaluation bars = accessible bars − warm-up bars − end buffercoverage ratio = usable evaluation bars ÷ desired evaluation bars × 100Code readiness is not the same question as statistically adequate trade count.- Are all series used by the entry condition non-na?
- Is the first confirmed higher-timeframe value available?
- Did persistent state begin from the intended neutral condition?
- Are there pre-window positions or pending orders?
- Is the first eligible trade an outlier in quantity or price?
Calculate before the start and gate only order creation
Use input.time() and compare it with time to mark eligible bars. Calculate moving averages, ATR and other dependencies on every bar outside the entry conditional. Then add the date boolean to the order condition. Earlier history prepares the series without creating historical orders.
Define the end as carefully as the start. You can stop new entries and allow a normal exit later, or close the position after the end boundary. Neither is universally correct. The error is comparing runs that use different end treatments without recording them.
| Method | New entries | Open position | Caveat |
|---|---|---|---|
| Entry cutoff | Stop at the end | Wait for ordinary exit | The final close can occur outside the window |
| Forced close | Stop at the end | Market close after boundary | Adds an artificial boundary exit |
| Closed-trades only | Any gate | Record open trades outside the sample | Reconcile screen and external aggregation |
Include the selected treatment in the export name and assumptions ledger.
Plot warm-up readiness and date eligibility separately
This script uses ready for non-na dependencies and inWindow for the configured date range. The crossover is a mechanism demo, not a claim of edge. After the boundary, it stops entries and closes an open position once.
//@version=6
strategy("Warm-up and date-window audit", overlay = true,
initial_capital = 100000, margin_long = 100, margin_short = 100)
int fastLength = input.int(20, "Fast length", minval = 1)
int slowLength = input.int(100, "Slow length", minval = 2)
int startTime = input.time(timestamp("01 Jan 2020 00:00 +0000"), "Entry start")
int endTime = input.time(timestamp("31 Dec 2024 23:59 +0000"), "Entry end")
float fast = ta.sma(close, fastLength)
float slow = ta.sma(close, slowLength)
bool ready = not na(fast) and not na(slow)
bool inWindow = time >= startTime and time <= endTime
bool mayEnter = ready and inWindow
if mayEnter and ta.crossover(fast, slow) and strategy.position_size == 0
strategy.entry("Long", strategy.long)
if ready and ta.crossunder(fast, slow) and strategy.position_size > 0
strategy.close("Long", comment = "Rule exit")
if time > endTime and time[1] <= endTime and strategy.position_size != 0
strategy.close_all(comment = "Window end")
bgcolor(not ready ? color.new(color.gray, 86) :
not inWindow ? color.new(color.orange, 90) : color.new(color.green, 92))
plot(fast, "Fast", color.aqua)
plot(slow, "Slow", color.orange)Freeze the date, timezone and end treatment. Test behavior when the dataset does not contain the exact boundary bar.
Use gray for not ready, orange for calculated but ineligible, and green for eligible. Save the visual with the settings. Confirm that changing only the date does not unexpectedly change the readiness bar and that the window-end close appears only once.
Count usable bars after preparation—not the requested calendar label
A configured date does not create missing bars. If accessible history minus warm-up and an end buffer is shorter than the intended evaluation length, the sample is arithmetically short even when its calendar label looks long. The calculator visualizes that shortfall; it does not decide whether the resulting trade count is statistically adequate.
- Capture the Properties date range
Record simulated-trade dates and the available backtesting range.
- Capture the first ready bar
Display when all dependent series first become usable.
- Capture first and last entry
Use actual List of Trades timestamps, not only configured dates.
- Classify open trades
Record natural exit, forced boundary exit or excluded open trade.
- Attach assumptions to the CSV
Save mode, symbol, timeframe, run date, window, warm-up and trade count.
Freeze the four boundaries in a reproducibility manifest
- Did you record symbol, timeframe, regular/deep mode and execution date?
- Are configured start and actual first trade stored separately?
- Is the warm-up rationale and first ready bar documented?
- Is end-of-window entry and open-position behavior explicit?
- Did you check first/last trade, closed count and open count?
- Were inputs, sizing and costs held constant while changing the window?
A date box alone is not reproducible, so build a four-boundary manifest with one row each for accessible data, warm-up, order eligibility and closure. Store observed first and last bar or trade timestamps beside configured dates so the requested window and realized sample never collapse into one label.
Include version ID, symbol, timeframe, regular/deep mode, run date, timezone, first accessible bar, first ready bar, first/last eligible order and the end-of-window open-position policy. CSV files whose manifest keys differ do not belong in the same comparison.
Evaluation bars after warm-up
Subtract preparation and end-buffer bars from accessible history and compare the remainder with the intended evaluation length.
Formula: usable=max(a−b−d,0); coverage=min(usable÷c×100,100); shortfall=max(c−usable,0). Does not assess gaps, indicator stabilization or statistical trade sufficiency.
Frequently asked questions
Is the backtest start date the same as the data start date?
Not necessarily. Data and calculations can begin earlier while order creation starts at the configured date. Earlier bars can then prepare the indicators without creating trades.
Is warm-up always equal to the longest indicator length?
No. Nested calculations, higher-timeframe requests, recursive series and persistent state can require a wider dependency audit. The first non-na value is not always a fully stabilized state.
Does increasing calc_bars_count create more historical data?
No. It controls historical bars made available to the script within existing limits. It cannot create market history unavailable for the symbol, timeframe or plan.
What should happen to an open position at the end date?
There is no universal single policy. You can stop entries early and await a natural exit, close explicitly at the boundary, or retain it as a separately reported open trade. Choose before comparison, apply the same rule to every version and record it in the manifest.
Primary sources and verification links
- TradingView Pine Script — Execution modelOfficial accessible-bar, calc_bars_count and historical execution behavior.
- TradingView Pine Script — Strategies FAQOfficial date/time filtering and moving-history-start guidance.
- TradingView Pine Script — StrategiesOfficial Strategy Tester Date Range, Properties and testing concepts.
- TradingView Help — How Deep Backtesting worksOfficial selected-range and report-mode behavior.
- TradingView Help — Deep Backtesting data availabilityCurrent coverage differences and limits by symbol and timeframe.
Edited and published by: SG Group · Editorial approach: We prioritize official TradingView Help Center and Pine Script documentation, then use exchange, regulator and other primary materials for market and product context. Features, data, pricing and connection terms change, so verify the current interface and linked sources before use.
Important notice: This article provides general education about TradingView interfaces, charts, alerts, screeners, paper trading and Pine Script. It is not investment advice, a trading signal, a recommendation of any instrument, data source or broker, or a guarantee of future price or profit. Features, pricing, data, exchange coverage, notifications, order integrations and Pine Script behavior vary by plan, region, connection and date and may change. Before risking money, verify current TradingView documentation and the terms of the relevant data source and connected provider, then rehearse the workflow with fictional data or paper trading.

