FIRE simulator / US returns 1871 to 2022 / browser only

October 2026 upgrade: real market history

One plan, three models of the market: 82%, 85% and 93%

The simulator used to draw every year's return from a bell curve. It now runs on 152 years of US stock and bond returns built from Robert Shiller's data, and can replay a plan through every retirement year in the record, resample that record in blocks, or keep the bell curve for comparison. The default plan (age 32, $150k saved, $40k a year saved, $60k a year spent from 50 to 95, 75% stocks) lasts in 82% of normal draws, 85% of bootstrap paths and 84 of 90 historical retirement years.

At a glance

  1. QuestionDoes a savings plan last to 95, and what single change gets it to 90%?
  2. DataShiller's US stock, CPI and 10-year Treasury series, 1871 to 2022: 152 years of real returns.
  3. MethodThree engines on the same plan: normal draws and 10-year block bootstrap (5,000 paths each), and replay through all 90 complete historical retirement years.
  4. HoldoutEngines fitted on 1871 to 1945, scored on 48 retirements from 1946 to 1993 at 4%: bootstrap 96.4%, normal 92.6%, actual 91.7%.
  5. Baseline4% rule, 1926 to 1966 starts: 92.7% at 50/50 against Trinity's 95%. The Python port and engine.js agree on all 18 test cases.
  6. ResultDefault plan: 82.2% normal, 84.8% bootstrap, 84 of 90 historical years. The old single-bell-curve assumption gave 54.3%.
  7. LimitOne country's unusually good market; both random engines overstated post-war success; no taxes or fees.
Default plan, retirement ages 40 to 65engine.js, 5,000 paths per point

Success by retirement age under each engine

Age 32, $150k saved, $40k a year saved until retirement, $60k a year spent after, plan until 95, 75% stocks and 25% 10-year Treasuries rebalanced yearly. All in today's dollars.

50
historical replayblock bootstrap, 10-year blocksnormal draws, same mean and spread

Computing 52 runs of 5,000 paths and 26 historical replays in your browser.

Computed on this page by the app's own engine (engine.js) on data/returns.json, with the app's fixed seed, so each point matches what the app shows for that age. The historical line moves in steps of about one window in ninety.

Test log

What moved when the bell curve went

The old app's default assumed a 5.0% real return with 13.0% volatility for the whole portfolio and gave the same plan 56% in a run recorded in the README (54% with the seed used here). Most of the jump to the new figures comes from the return assumption, not the model: US stocks returned 6.9% a year after inflation from 1871 to 2022 (8.4% arithmetic mean, 17.9% standard deviation), and a 75/25 mix with 10-year Treasuries comes out well above 5%. Holding the mean and spread fixed and changing only how years are drawn moves the result from 82% to 93%.

Default plan, retire at 50, plan until 95data/validation.json
EngineSuccessRunsMedian at 95
Loading data/validation.json

From python3 scripts/check_engine.py --js, which runs the Python port and engine.js on the same cases and checks that they agree to the dollar. The first row is the old app's assumption, 100% in one asset, kept for comparison. Superseded on 2026-10-28: the old headline of 3% at 40, 56% at 50 and 90% first at 59 came from that assumption.

Historical start years

1929 and 1966 survive; 1973 to 1977 do not

The historical engine lines the whole life up with history: "retire in 1929" means saving from 1911 to 1928 and drawing down from 1929. For a 30-year retiree with a fixed pot, 1929 and 1966 are the classic failures. For this plan they are not, because the decades before them built large balances: the 1966 retiree arrives with $2.77 million after saving through 1948 to 1965, when the 75/25 mix returned 10.7% a year after inflation. The 1973 to 1977 retirees saved through weaker years, reach retirement with $0.85 to $1.5 million, and then meet 6.6 to 8.7% a year inflation in their first decade. They run out between 83 and 95. The 1917 retiree runs out at 92.

Default plan, one cell per retirement yearhistorical engine

Every retirement year from 1889

Each cell is the year the plan retires. Retirement years after 1978 have not finished 45 years of drawdown by 2022 and are shown with their balance in 2022.

lasted to 95ran outstill running when the data ends

Select a year to read its balance at retirement and its outcome. The same strip sits above the fan chart in the app and redraws for any plan.

Why history is kinder here

Long runs of years carry information that single draws throw away

The bootstrap draws runs of consecutive real years, stock and bond together. With one-year blocks it is close to the normal engine (82.6% against 82.2%), so fat tails alone do little to this plan. Longer blocks raise the success rate, and full historical replay raises it most. Over a 63-year plan, bad decades in US history have tended to be followed by better ones, and independent draws cannot reproduce that.

Default plan, success by engine and block lengthdata/validation.json
The historical figure rests on 90 overlapping windows, which amount to about two independent 63-year lives, so the gap between 85% and 93% is not precise. The app defaults to 10-year blocks for that reason: long enough to keep some of the clustering, short enough to mix decades into new orders.

Holdout

Fitted on 1871 to 1945, both random engines were too hopeful about the post-war years

To see whether the random engines are calibrated, I fitted them on 1871 to 1945 only and asked them about a 30-year retirement on a 75/25 mix, then compared their answers with what actually happened to the 48 retirements that started from 1946 to 1993. At 4% withdrawals the bootstrap said 96% and the normal engine 93%; 92% of those retirements lasted. At 5% they said 88% and 81%, and 73% lasted. From 4% up, both engines overstated success in the post-war sample, and the bootstrap missed by more.

30-year retirement, 75/25, constant real withdrawalsdata/validation.json
what happened, 1946 to 1993 startsbootstrap fitted on 1871 to 1945normal fitted on 1871 to 1945
The 48 holdout windows overlap heavily (1966 to 1969 share 27 of their 30 years), so they hold only a few independent outcomes. The direction of the miss is clear; its size is not.

Benchmark

The 4% rule on this data lands a few points under the Trinity study

Before trusting the engine I ran the textbook case: $40,000 a year from $1 million, adjusted for inflation, for 30 years, replayed through every start year. The Trinity study (Cooley, Hubbard and Walz, 1998) reported 95% success at 50/50 and 98% at 75/25 for start years 1926 to 1966. Bengen (1994) found 4.15% the highest rate that survived every 30-year period with 50 to 75% stocks.

4% rule, 30 years, historical windowsscripts/check_engine.py
StocksTrinity 1998This data, 1926 to 1966Failed start yearsAll 123 windowsSafe maximum
Loading data/validation.json

The safe maximum is the highest starting rate, to 0.01%, that lasted 30 years from every start year. Damodaran's calendar-year series (Dec 31 to Dec 31) gives the same failing years at 50/50 and 75/25, so January-to-January timing is not the cause.

This data fails about one more start year than Trinity at each mix: 1965 and 1966 at 75/25, 1964 to 1966 at 50/50. They run out late, in their 25th to 29th year (the 1965 retiree at 94, a year short), and the safe maximum comes out at 3.75% for 75/25 against Bengen's 4.15%. Both studies used different bonds from mine: Trinity long-term corporate bonds and Bengen intermediate Treasuries, where I use 10-year Treasuries derived from yields. I have not tested how much of the gap that explains.

Spending rules

Flexible spending buys success with lower spending in bad stretches

The app has three spending rules. Constant spending withdraws $60k every year. The percentage rule spends 4% of the portfolio, held between a floor of 75% and a ceiling of 150% of the target. Guardrails, after Guyton and Klinger, start at $60k and cut 10% when the withdrawal rate rises 20% above where it started (except in the last 15 years) or raise 10% when it falls 20% below, within the same floor and ceiling. A pension or Social Security payment reduces what the portfolio has to cover from the age it starts.

Default plan, retire at 50computed on this page
RuleHistoricalBootstrapLowest year, median pathLowest year, 10th pctAverage spending, median
Computing

Spending columns are from the bootstrap engine, in today's dollars. The percentage rule rarely runs out, by construction; its cost shows in the spending columns.

Under the bootstrap, guardrails lift the default plan from 84.8% to 90.0%. The price is that about a quarter of the paths spend at least one year at the $45,000 floor. In history neither flexible rule ran out in any of the 90 windows, but the percentage rule's median path dropped to the floor at some point.

Solver

What gets the plan to 90%

For the plan on screen, the solver searches each lever on its own: the first later retirement age that reaches the target, the highest spending (to $500), the lowest yearly saving (to $500), and the fixed stock share closest to the current one. Under the bootstrap the default plan needs one of: retire at 52, spend $51,500, or save $48,500 a year. No fixed mix gets it there; 100% stocks reaches 88%. Under historical replay it already clears 90%, and the solver reports the slack instead: spending can rise to $62,500 or saving fall to $38,000. Normal and bootstrap searches reuse the same 5,000 seeded paths for every candidate, so the comparison is between plans, not between random draws, and the search runs in a Web Worker in under a second.

Method

Data and engine

scripts/build_returns.py reads Shiller's monthly ie_data.xls. Stock returns chain his monthly total return, (Pm+1 + Dm/12) / Pm, from January to January. Bond returns are a constant-maturity approximation: buy a 10-year bond at par at January's yield, collect a year's coupon, and sell it as a 9-year bond at the next January's yield. Before 1953 the yield column is Shiller's long-term government rate. Each series is deflated by the change in January CPI. Shiller's file runs to September 2023, with estimated CPI for its last two months, so the last full year is 2022.

Against Damodaran's histretSP.xls for 1928 to 2022, the series agree on average (real stocks 8.33% against 8.26% a year, real bonds 1.88% against 1.87%) and correlate at 0.97 year by year. Single years differ because Damodaran uses December 31 closes and Shiller monthly averages: 1987 is -6.2% here and +1.4% there, because a sharp rally in January 1987 put that month's average 6% above December's, so this window starts higher. The bond approximation matches Shiller's own monthly bond-return column to 0.34 points a year on average.

The simulator at desktop width with the default plan in historical mode: inputs on the left; on the right a 93% success rate, a grid of retirement years from 1889 with 1917 and 1973 to 1977 marked as running out, and a fan chart.
The app at 1380px, default plan, historical engine, captured 2026-10-28.
The simulator on a 390 pixel wide phone: the engine switch, a 93% success rate and the start-year grid with two-digit year labels.
At 390px the inputs stack above the results.
Data
Shiller, S&P Composite, CPI and GS10, 1871 to 2022 (152 years), real, January to January
Normal
Independent bivariate normal stock and bond draws with the data's means, standard deviations and correlation (0.19); stock mean and volatility adjustable
Bootstrap
Moving blocks of consecutive years with wraparound, stock and bond drawn together; block length 1 to 20, default 10
Historical
One window per retirement year; working years use the years just before it; windows that pass 2022 are shown but not counted
Timing
Savings added at year end while working; spending withdrawn at the start of each retirement year; rebalanced yearly
Checks
scripts/engine.py ports the engine to Python; scripts/check_engine.py --js runs both and the benchmarks
Stack
Static files, vanilla JavaScript and a Web Worker, no libraries, no backend, no analytics

Limitations

What this still leaves out

The data is one country's history, and the US had one of the best stock markets of the period. Every engine here inherits that, and the holdout shows the random engines were too optimistic about the post-war years even with US data.

There are no taxes, fees, one-off costs, or changes in spending with age. Bonds are a single 10-year Treasury series with no TIPS, cash or international assets. Contributions stay fixed in real terms through the working years. The historical engine for a long plan has few complete windows: 90 for the default plan, heavily overlapping.

Use it to compare plans against each other. It is an educational tool and does not give financial advice.

Related

Built like its sibling

The EPUB reading-level analyzer is built the same way: static files, everything client-side. The full narrative and the October 2026 changes are in writeup.md.

Try it with your own numbers