Backtesting
How Portfolio Lab replays actual historical price and dividend data month by month — the data, portfolio construction, rebalancing, the return metrics, and what a backtest deliberately does not model.
Overview
Portfolio Lab is a separate engine from the retirement projection. Instead of assumed return rates, it replays actual historical security price and dividend data period by period to compute what a portfolio would have done over a chosen past window. It is a deterministic historical replay — not a forecast, not a Monte Carlo simulation, and not a probability of success. Past performance does not predict future results.
Historical data
- Daily price and dividend history is sourced from a financial data provider (Yahoo Finance), stored server-side, and refreshed periodically. On a symbol’s first use about five years of history is loaded, then extended further back as a longer backtest requires it.
- Adjusted closing prices account for stock splits and other corporate actions. There are two valuation modes: Total Return values holdings via the dividend-adjusted close (dividends already reflected in price), and Dividend Tracking (the default) values via the raw close and applies each cash dividend explicitly per your Dividend Handling choice.
- Each symbol’s history begins wherever the provider’s data begins — there is no single earliest supported date, and different holdings in one portfolio can have different history lengths.
- Exact provider semantics (survivorship treatment, how far back each series reaches, how the provider itself computes adjusted close) are outside SmartRetireCalc’s control and are not independently reconstructed here.
Building the portfolio
Each portfolio is a list of holdings with a target weight entered as a percentage. Holdings must be individual stocks, ETFs, or mutual funds — each symbol is verified against a market-data provider before the backtest runs, and an option, futures contract, cryptocurrency, currency, individual bond, or market index is rejected with a message naming the symbol. (A market index can still be added as a benchmark.) The weights must total 100% (within 0.01) — the engine does not renormalize a list that sums to something else; it rejects it. A CASH holding is supported: its dollars are held at face value for the whole backtest, are counted in total portfolio value, and participate in every derived return and risk figure as a 0%-return sleeve (no money-market or T-bill yield is modeled) — this is true under both dividend-handling modes. Contributions are split across every holding at its target weight, so the share routed to a CASH holding is retained as portfolio cash, not lost. Limits: up to 20 portfolios per comparison, 50 holdings each, 10 benchmarks. The design is for long-only, unleveraged portfolios.
When a holding’s history doesn’t reach the start date
A holding counts as fully invested when its real data begins within about a week (five trading days) of the requested start; a longer gap is resolved in order: first its real history, then an approved substitute’s history (see Historical Proxy below), and finally — when neither reaches back far enough — by starting the whole portfolio later, at the latest date every holding can be fully invested from. A portfolio started this way is not flagged Incomplete: it is Backtest period adjusted, and the requested start, the actual start, and the affected holding(s) are disclosed in the results. It still isn’t included in the Portfolio Rating comparison, comparison badges, or profile classification for this backtest, since it now covers a different, shorter period than portfolios that weren’t adjusted — comparing across different periods isn’t supported yet.
A holding only remains genuinely Incomplete when starting later can never fix it — an unknown or delisted ticker with no stored data at all, or one with no data anywhere at or after the requested start. Rather than drop it and scale the other weights up (which would misrepresent the allocation you asked for), Portfolio Lab holds that slice as identifiable uninvested cash at its own requested weightfor the life of the backtest and flags the portfolio Incomplete, excluded from the Portfolio Rating, comparison badges, and profile classification. That reserved starting slice is never deployed later, even once the security’s history appears inside the backtest window, and rebalancing never buys an incomplete holding on your behalf. Scheduled contributions do still route their normal share to the holding once it has a price, so new money can flow into it over time even though the reserved starting slice stays in cash. No pre-inception price or return is ever fabricated.
Historical Proxy (Synthetic History)
When a security’s own history is too short to reach the requested start date, Portfolio Lab may fill the earlier period with a substitute security’s realhistorical returns (an older share class, the same benchmark, or a closely matching index), chained backward to align with the target’s price where its real history begins. That earlier portion approximates how the selected holding might have behaved — it is modelled from the substitute’s actual returns, not the selected fund’s own record, which did not exist yet. Actual history always takes precedence — a proxy is only considered once a holding’s own real data, within the normal gap tolerance, does not cover the request.
Some pairings are curated and reviewed by an administrator in advance. Portfolio Lab can also select a proxy automatically at the time of the backtest, where that option is enabled. Either way a candidate substitute must first pass the same checks a reviewer applies — an economic-compatibility screen (same broad asset class and category; leveraged, inverse, and money-market mismatches are rejected) and a statistical validation against the overlapping period of real history (correlation, beta, and tracking-error thresholds). A candidate that does not clearly pass every check is not used. This is not a comprehensive database of every security — when a security cannot be classified with confidence, or no compatible substitute with enough of its own history exists, no proxy is applied.
Proxy history is only constructed for a Monthly backtest; a Weekly or Daily run never fills missing history with a proxy. A proxy is used only when it can provide gap-free monthly coverage; internal gaps are never interpolated and proxy chains are never built. A holding’s proxy period is disclosed in the results (labelled Synthetic history). A proxy that exists but can’t provide full coverage is treated the same as having no proxy at all — the portfolio falls through to the period-adjustment behavior above rather than a partial or interpolated substitute. Every proxy mapping that is used, including one selected automatically, is recorded and can be reviewed — and deactivated — by an administrator.
Backtest period
- You choose a start and end date; the span may not exceed ~100 years and the start must be before the end.
- Performance is measured from the effective investment start — the date holdings were actually able to begin investing, which can be a few days after the requested start if a security’s data begins slightly later — through the last simulated observation. The return in that first partial window is included, not dropped.
- When holdings have different history lengths, all portfolios and benchmarks are compared as of a single common effective end date so the comparison is like-for-like.
- The simulation frequency can be Monthly (default), Weekly, or Daily. Quarterly and Yearly are reserved and not implemented.
- Weekly places one observation on each Friday within the period (a Friday start is its own first observation; otherwise the opening days up to the first Friday are the initial partial window described above and are still counted). If a Friday is a market holiday the last prior trading price is carried to it. When the end date is not a Friday, one final observation is added at the end date so the closing partial week is never dropped. Monthly observes each calendar month-end and Daily observes each trading day, following the same start/end rules. Contributions, dividends, and rebalances are applied on these observation dates.
How each period’s portfolio return is calculated
PortfolioReturn = Σ (Weighti × HoldingReturni)
Valuet = Valuet−1 × (1 + PortfolioReturn) + Dividendst + Contributionst
Weights apply at the start of the period. Within each period the engine applies that period’s dividends, then any scheduled contribution, then a rebalance if one is due. A dividend is credited only once its holding was actually held before the ex-dividend date. Fractional shares are supported; no transaction costs, spreads, or taxes are modeled on any trade.
Dividend handling
- Reinvest (default) — the dividend buys fractional shares of the same holding at that period’s price.
- Cash — the dividend accumulates in a 0% cash balance and is not redeployed until the next rebalance, if any.
Where dividend data comes from
Per-share cash dividend events are sourced from the market-data provider and refreshed alongside a symbol’s price history — a new distribution is picked up on the next market-data refresh, and older events are kept. Each symbol’s dividend history is requested back to the same start date its price history covers. Where the provider has no explicit event for a period a portfolio’s date range reaches into, the engine estimates the distribution for that period from the relationship between the dividend-adjusted and raw closing prices; a real provider event always takes precedence over an estimate. These estimates are approximate and are used only to fill genuine gaps.
Rebalancing
Rebalancing is off by default. With rebalancing set to None, the portfolio is buy-and-hold — weights drift with performance and are never reset. Set to Monthly, Quarterly, or Annually, the portfolio is reset to its target weights at each interval:
This is the distinction between a fixed-weight periodically rebalanced portfolio and a drifting-weight buy-and-hold one — they can produce materially different results over a long window. Rebalance trades incur no modeled cost.
Growth: annualized & cumulative return
The headline performance figures are computed from a cash-flow-neutral return series: each period’s external contribution is netted out before returns are chain-linked, so a deposit never inflates reported performance (a $10,000 contribution in a flat market contributes 0%, not +10%).
Wealth0 = 1, Wealtht = Wealtht−1 × (1 + PeriodReturnt)
CumulativeReturn = Wealthfinal − 1
AnnualizedReturn = Wealthfinal 1 / Years − 1
This is a time-weighted annualized return over the backtest’s own simulated period — a standard portfolio-performance convention, not a claim of conformance to an external accounting standard such as GIPS.
EndingValue / StartingValue raised to 1 / Years) computed from raw nominal dollars is retained internally for backward compatibility but is not the primary figure shown — unlike Annualized Return it is not cash-flow-neutral, so a contribution can inflate it. All figures are nominal; Portfolio Lab does not produce inflation-adjusted (real) returns.Calendar Year Returns
Every calendar year the backtest touches is reported. Each year’s return is the compounded product of the cash-flow-neutral period returns whose dates fall in that year — not a comparison of the year’s beginning and ending dollar value (which a January contribution would distort). A first year that doesn’t start on January 1, and a final / year-to-date year that doesn’t end on December 31, are each flagged as partial; a partial year’s figure is the real return over the months actually covered, never scaled up to a full-year equivalent. “Best / Worst Calendar Year” and loss-frequency counts use the complete-year subset only.
Trailing Returns
Trailing returns are reported for fixed horizons of 3, 5, 10, 15, and 20 years (there is no YTD or 1-year trailing figure). Each is the annualized (CAGR) return over that many years ending at the backtest’s last observation date, computed from the same cash-flow-neutral wealth index. A horizon is shown as unavailable (not estimated, not silently shortened) when the portfolio’s own history doesn’t reach back far enough to cover it.
Best / Worst 12-Month Periods
These are rolling one-year windows, not calendar years. For every observation on the wealth index, the engine looks back to the observation on or before the same date one year earlier and computes the simple return between the two wealth values. The windows overlap (one per observation). The best and worst such windows are reported with their own start and end dates — which will usually straddle a year boundary rather than being Jan 1–Dec 31. Windows are considered only once an observation reaches a full year back.
Drawdowns and volatility
Drawdown and volatility, like every risk figure, are computed from the same cash-flow-neutral wealth index — “what would $1 invested at the start be worth now, ignoring every deposit” — never from raw nominal dollars. A drawdown is the percentage decline from the wealth index’s running peak, and is only “recovered” once the index itself regains that peak. The Drawdown chart plots this same per-point series, so the curve, the headline Max Drawdown, and the recovery figures all share one basis and a deposit made during a decline never makes the charted drawdown look shallower.
AnnualizedVolatility = SampleStdDev(periodic returns) × √(periods per year)
Volatility uses the sample (n−1) standard deviation of the periodic returns, annualized by √12 for Monthly, √52 for Weekly, √252 for Daily. A separate canonical monthly volatility resamples to complete calendar months so the same portfolio reports the same volatility whichever frequency you ran it at. Deeper risk analytics — downside deviation, Sharpe and Sortino ratios (both computed with a 0% minimum acceptable return / no risk-free rate), historical Value-at-Risk and Expected Shortfall, Ulcer Index, Calmar ratio, drawdown duration and recovery, the risk-vs-return chart, and the Portfolio Rating and badges — are documented in Risk Analytics.
What the charts show
- Growth of portfolio — the simulated account value over time (which includes your deposits, not just market performance), plotted against a single shared Total Contributions reference line (initial investment plus every contribution booked to date) so contributed capital can be read separately from investment gain or loss. Dragging horizontally across this chart zooms the view into a date range (the y-axis and the historical-event bands rescale to the visible period); this changes only what the chart shows — every return, risk, drawdown, and annual-result figure on the page is still computed over the full backtest.
- Historical Events — a small, fixed, curated list of widely recognized market-stress periods (for example the COVID crash, the 2022 inflation and rate-hike bear market, and the 2023 regional-banking stress). Each is an explicit start-to-end period, defined at month resolution, and is listed only when its window overlaps your backtest period. It is context for interpreting the results, not a comprehensive timeline, and nothing in it changes any calculation.
- Calendar Year Returns, Trailing Returns, and the Best / Worst 12-Month panel, as described above.
- Risk vs. Return — a scatter plot with one point per portfolio and benchmark: x = annualized volatility, y = annualized return. It is a plot of observed historical risk and return — there is no efficient-frontier optimization and no optimizer anywhere in Portfolio Lab.
- Benchmarks default to VOO (S&P 500), QQQ (Nasdaq-100), and DIA (Dow Jones Industrial Average).
What backtesting does not model
- Taxes — no capital gains, dividend, or interest tax; no tax-drag; no account-type treatment.
- Fees — no fund expense ratios, advisor fees, transaction costs, or spreads.
- Withdrawals — the backtest supports periodic contributions but not retirement withdrawals, inflation-adjusted spending, percentage withdrawals, cash buffers, or a decumulation / sequence-risk drawdown. For withdrawal-era sequence risk use the Sequence of Returns Risk Calculator.
- Inflation — all outputs are nominal. The main projection’s inflation assumption does not apply here.
- Forward returns — nothing here is a forecast or an expected return.
Relationship to the retirement projection
The retirement projection is forward-looking and deterministic: you supply return, inflation, and spending assumptions and it steps through future years across three scenarios. Backtesting is backward-looking: it replays one actual historical return sequence for a portfolio you specify. They share no data path. A backtest result never changes the retirement projection, and a projection assumption never changes a backtest. See also Safe Withdrawal Rate and Accounts.
Important limitations
- A backtest is a single historical path — it shows what did happen for those holdings over that window, not a range of outcomes or a probability.
- Results assume perfect execution at period-end prices, no costs, and no taxes, so a real investor’s outcome would have been lower.
- Available history varies by security; a short or proxy-filled history is disclosed but still limits how far back a comparison is meaningful.
- Past performance does not guarantee — or predict — future results.
Background
- Time-weighted return (GIPS concept) — the chain-linked, cash-flow-neutral return convention the Annualized/Cumulative figures follow — SmartRetireCalc does not claim GIPS conformance
- SEC Investor Bulletin — “Past performance” — why historical results are descriptive, not predictive
Related calculators
Related guides: Sequence of Returns Risk Guide