Tools › Investing › Portfolio and Risk › Portfolio Backtest › Method
Portfolio Backtest: Method
Open the Portfolio Backtest tool
Portfolio Backtest: the Method
What it does
A backtest asks: if I had held these assets in these proportions over this stretch of history, what would have happened to my money? You paste the price history (or the returns) of the assets, enter the target weights, the starting amount, any money added or withdrawn each period and a rebalancing rule. The page follows the portfolio one period at a time and reports where it ended, what it earned a year, how much it swung and fell, how often it was rebalanced, how the other rebalancing rules would have done with the same money, and how much each asset added. A backtest describes the past sample only. It is not a forecast.
The method
Returns. The return of an asset in a period is rt = Pt / Pt−1 − 1, so n prices give n − 1 periods. Prices should include dividends and interest (an "adjusted close" or "total return" series); otherwise income is left out.
Following the money. With wj the target weight of asset j (the weights add to 1) and V0 the starting amount, asset j starts with wj V0. In every period, in this order:
1. Each holding grows: hj becomes hj (1 + rj,t).
2. (Advanced) The fee is taken: with f the annual fee, every holding loses the fraction fp = 1 − (1 − f)1/m, m being the number of periods in a year.
3. The money of the period, C, is added (or withdrawn when C is negative). If the rule calls for rebalancing, every asset is bought or sold so that it is again wj of the new total. If not, the money is split in proportion to what each asset is worth, which leaves the weights as they have drifted.
4. (Advanced) The trading cost, c times the money traded in step 3, is taken from the portfolio.
Nothing is added or traded at the end of the last period, and there is no trading cost on the first purchase.
Rebalancing rules. Never: the weights drift freely. Every period: the weights are restored at each period end. Every N periods: at the end of periods N, 2N, 3N, … When a weight drifts X points: at the end of any period in which some asset's weight is more than X percentage points above or below its target.
Period return. Rt = (value at the end of period t before the money of the period moves) / (value at the end of period t − 1 after its money moved) − 1. Money added is not a gain, so it is kept out of the return. Fees and trading costs are inside it: the returns are net of them.
Time-weighted return. The period returns are linked: G = (1 + R1)(1 + R2)…(1 + RT) is the growth of 1 left in the portfolio. Over Y = T / m years the yearly rate is Rtw = G1/Y − 1. Because each Rt is measured between flows, the result does not depend on the amounts added or their timing. This is the sub-period linking of the GIPS Guidance Statement on Calculation Methodology, and the definition used by the Personal Rate of Return tool.
Money-weighted return. The yearly rate r that solves V0 (1 + r)T/m + Σt C (1 + r)(T − t)/m = VT, the sum running over the periods t = 1 … T − 1 in which money moved. It is the internal rate of return of the investor's own cash flows and is found by trial (a bracketed Newton iteration). With no flows it equals the time-weighted return.
Volatility. The sample standard deviation s of the Rt (divisor T − 1), annualised as σ = s √m.
Maximum drawdown. With Ut the growth of 1 after t periods, the drawdown at t is Ut divided by the highest U reached so far, minus 1. The maximum drawdown is the lowest value; the page gives the dates of the high and of the low.
Best and worst year. The compounded return of every run of m consecutive periods (overlapping windows, each one year long); the highest and the lowest are reported with their dates.
Turnover. For one rebalancing, half the sum over the assets of |target weight − weight just before|: the share of the portfolio that changes hands. The page reports the number of rebalancings, the total and the average per year.
Contribution of each asset. Gj = Σt (value of asset j at the start of period t) × rj,t, in money. The amounts account for the whole result: VT = V0 + (sum of the money added) + Σj Gj − fees − trading costs.
Real values (Advanced). With i the yearly inflation rate, the ending value in the money of the starting date is VT / (1 + i)Y, and the real time-weighted return is (1 + Rtw) / (1 + i) − 1.
Benchmark (Advanced). The same starting amount and the same flows are followed in the benchmark column alone, without fee or trading cost, and set beside the portfolio.
What it assumes
Every trade is made at the pasted price of the period end, in any amount, including fractions of a share. Money moves at period ends only. Without the Advanced inputs there are no costs, fees or taxes; with them, the cost is one percentage of the money traded and the fee a constant percentage of the value. Taxes on rebalancing sales are not modelled. Inflation is one constant rate. Volatility is annualised by √m, which treats the returns of separate periods as unrelated.
When it misleads
A backtest is one path through one period. Change the starting date by a year and the ending value, the drawdown and the order of the rebalancing rules can all change; a difference between two rules in one sample is not evidence that one is better.
The assets were chosen today, knowing how they did. Funds that closed and companies that failed are missing from most price files, and anything picked because it did well will look good in its own backtest. Trying many weights or rules on the same history and keeping the best one fits the noise of that history.
Prices not adjusted for dividends understate returns. Period-end prices hide what happened inside the period: a monthly series cannot show a fall and recovery within a month, so the true maximum drawdown is at least as deep as the one shown. Real trades move prices and cost more in falling markets than a flat percentage suggests, and a tax on gains makes frequent rebalancing dearer than it appears here.
The money-weighted return depends on when money was added; it describes this pattern of flows, not the portfolio's weights. A short history gives a poorly determined average return: with a yearly volatility of 10 %, ten years leave an uncertainty of about ±3 points a year.
Worked example
The default data are illustrative: 120 months of made-up prices for three assets and a benchmark column, drawn from a random-number generator (numpy, seed 348) and labelled with month-end dates. They are not market data. Weights 60 / 30 / 10 %, starting amount 10,000, 100 added at the end of every month, rebalanced every 12 months.
Start: 6,000 / 3,000 / 1,000. In the first month the stock fund returned −2.77 %, so it is worth 6,000 × (1 − 0.0277) = 5,833.80; with the other two the portfolio is worth 5,833.80 + 2,992.80 + 992.80 = 9,819.40, and R1 = 9,819.40 / 10,000 − 1 = −1.806 %. The 100 is added, so month 2 starts with 9,919.40; it ends at 9,305.51 before the next addition: R2 = 9,305.51 / 9,919.40 − 1 = −6.189 %.
Linking the 120 monthly returns gives G = 1.6967, so the time-weighted return is 1.69671/10 − 1 = 5.43 % a year. The portfolio ends at 34,958.09 after 10,000 + 119 × 100 = 21,900 was put in, a gain of 13,058.09. The rate that grows the 10,000 and each of the 119 additions to 34,958.09 is 6.35 % a year, the money-weighted return. It is higher than 5.43 % because the later months, when more money was invested, were the better ones.
The monthly returns have a standard deviation of 2.959 %, so the volatility is 2.959 × √12 = 10.25 % a year. The growth of 1 peaked at 1.7166 on 2023-06-30 and fell to 1.3325 on 2024-12-31: a maximum drawdown of 1.3325 / 1.7166 − 1 = −22.37 %. The best 12 months in a row returned 37.46 % and the worst −17.43 %.
The portfolio was rebalanced 9 times with a total turnover of 39.8 % (4.0 % a year). With the same money the other rules end at 33,214.93 (never), 34,280.48 (every month) and 34,588.93 (when a weight drifts more than 5 points). The three assets added 9,024.21, 2,509.81 and 1,524.06: 10,000 + 11,900 + 13,058.09 = 34,958.09.
In Advanced mode, a trading cost of 0.1 %, a fee of 0.2 % a year and inflation of 2.5 % give an ending value of 34,386.97 (fees 383.17, costs 25.68), a time-weighted return of 5.20 %, a real ending value of 34,386.97 / 1.02510 = 26,863.04 and a real return of 1.0520 / 1.025 − 1 = 2.64 % a year. The same money in the benchmark column ends at 39,247.94.
A calculator for education and analysis, not investment advice.