Translated from the Spanish original. Where they differ, the Spanish one holds.
- App: Horalis Growth · Reviewed: 3 October 2026
- Code (in
projects/wealth-lens/):src/lib/simulation.ts(wealthPercentiles,wealthSamples),src/lib/normal.ts(normalReturns),src/lib/projections.ts(bandsFor,samplesFor,FUTURES),src/lib/mix.ts(mixes),src/lib/monte-carlo.ts(mulberry32)
The question it answers
"What if the years do not turn out like the average?" It is "If it goes badly" (in 1 in 10 possible futures you end below €X), "If it goes well" (in 1 in 10, above €Y), the shaded band of 8 in 10 on the chart and the view "Where do these futures come from?".
The formula, in plain words
1,000 possible futures are written. Each future is built year by year by drawing at random a real year from the data (1988–2022) and applying what grew that year; a year can come out several times. Then the 1,000 results of each year are sorted: the one in place 100 is "if it goes badly", the one in place 500 is the middle one and the one in place 900 is "if it goes well".
Exact:
- Yearly steps. Each year, half of the year's contributions go in at the start and the other half at the end: balance ← (balance + 6·Y)·(1 + r) + 6·Y, with r the real return drawn.
- 1,000 paths, drawn with replacement and independently each year (i.i.d. bootstrap), a generator with a fixed seed (Mulberry32, seed 20260929): the same data always give the same futures.
- Percentiles 10, 50 and 90 of the 1,000 balances of each year, interpolating between neighbours.
- What is drawn:
- an asset: its 35 real years;
- a mix: the same year for all its parts at once, so they move together as they did (see mixes);
- an own growth or own swings: there is no history, so each year comes from a lognormal distribution, log(1 + r) ~ Normal(log(1 + g), σ²), represented by 2,000 equally spaced quantiles (from 0.025 % to 99.975 %, ±3.5 σ). The median year grows exactly g;
- the starting own growth: g = 5 % and σ = 16.39 % (the swing of US shares from 1988 to 2022).
- The futures view draws 50 of those 1,000 paths, spread evenly among them.
Assumptions
- Each year is independent of the one before: there are no runs, no rebounds after a fall, no cycles.
- The 35 years from 1988 to 2022 contain everything that can happen: a year worse than the worst in the data never comes out (US shares: −35.7 % in 2008).
- The average and the swing are known without error.
- For one's own: lognormal returns (thin tails), with US shares' swing if no other is written.
Sources (dated)
- The same yearly data as growth (the common period 1988–2022, compiled on 29 September 2026).
- Method: Efron's bootstrap (1979), applied to retirement portfolios since Bengen (1994) and Cooley, Hubbard and Walz (1998, the Trinity study), which use historical or resampled sequences.
- Inverse of the normal: Acklam's approximation (relative error < 1.2·10⁻⁹).
Validation (tests)
src/lib/simulation.test.ts(6): the percentiles interpolate between neighbours; if every year yields the same, they match the growth formula; with real history they open up (low < middle < high); same seed, same result; the cache gives the same with any amount.src/lib/normal.test.ts(5): the inverse of the normal against known quantiles; the typical year of the own group is g and its spread σ; no more than everything is ever lost; at equal growth, a larger swing lasts less.src/lib/monte-carlo.test.ts(17): the generator, reproducible and in [0, 1).src/lib/mix.test.ts(24): a mix's joint draw (2022, with shares and bonds falling at once).src/lib/findings.test.tsandsrc/components/plain-language.test.ts: how it is said ("in 1 in 10 possible futures…"), no percentages without euros.
Limits
- In the explanatory view, if the bad decade is selected, the thick line is that historical scenario and is labelled so. The thin lines and the band are still futures without that decade imposed; a text beside the chart says so. It is a comparison, not a distribution conditioned on living through that crisis. The "1 in 10" figures describe only the simulated lines, not the probability of the historical scenario.
- It is a way to imagine uncertainty, not the real uncertainty. The probabilities hold only inside the model.
- With 1,000 paths, the 10th percentile has a sampling error of a few percentage points; the fixed seed makes it stable, not exact.
- The band does not include what is not in the data: long wars, hyperinflation, the Great Depression (1929–1932 is outside the period).
What is debatable
- Year-to-year independence. The i.i.d. bootstrap erases mean reversion and runs. There is a debate: Siegel argues that in the long run shares are less risky because of reversion; Pástor and Stambaugh (2012, Journal of Finance, "Are stocks really less volatile in the long run?") conclude that, counting the uncertainty of the parameters, they are more risky. Cost: a block bootstrap (drawing spans of 3–5 years) and comparing.
- The average is treated as known. Not adding the uncertainty of the average narrows the band, the more so the longer the term: with 35 years, the error of the average is ~3 points a year. Cost: also draw the average in each path (a simple Bayesian approach).
- A short, truncated sample. Nothing worse than the worst year of 1988–2022. For the S&P 500, the series since 1928 exists and has worse years (1931: −38.0 % real). Cost: tied to the period decision of the growth sheet.
- Thin tails in one's own. The lognormal underestimates the extremes against real data (kurtosis). Cost: a Student's t or resampling historical residuals.
- "1 in 10" sounds like an objective probability. It is a frequency inside the model. The app explains it in the futures view, but the result's sentence does not say it. Cost: a text.
- Two time steps. The simulations go by years and the big number by months (see growth, point 6).
History
- 2026-10-03: first sheet (no change to the calculation).
- 2026-10-05: the EN/ES legend and explanation tell the bad decade apart from the unconditioned futures. Rendering tests in both languages; no change to the simulations or their probabilities.
- 2026-10-09 (phase A2): the starting own growth uses the swing of US shares (16.39 %) instead of the World's (17.82 %), withdrawn because its data are not open. No My portfolio.