fire-planner/docs/adr/0001-fire-number-monte-carlo-threshold.md
Viktor Barzin edb4d11352
Some checks are pending
Build and Push / lint-and-test (push) Waiting to run
Build and Push / build (push) Blocked by required conditions
Build and Push / deploy (push) Blocked by required conditions
Build and Push / notify-failure (push) Blocked by required conditions
feat(fire-target): per-Case FIRE-number solver for the retirement countdown
Add a Monte-Carlo "FIRE number" solver so the wealth dashboard can show a £
countdown to retirement across life-stage cases, in today's money.

Viktor wants to see, per country, how far his net worth is from being able to
retire for good under three cases — Solo (his spend ×1.5), Household (+Anca
×1.5), Family (+2 kids) — with cost-of-living re-scaling per country and a 99%
Guyton-Klinger success bar.

- spend_model: per-Case real-GBP spend, COL-scaled (rent + non-rent essentials
  scale by country; Holidays fixed), ×1.5 safety. Constants sourced live from
  actualbudget (Viktor) / on-record (Anca).
- geo: city -> tax jurisdiction (nomad fallback).
- fire_target: binary-search the smallest LIQUID net worth where GK reaches the
  bar; pension modelled as a tranche unlocking at ~57, kids ramp + optional home
  as cashflows. New fire_target table (migration 0007) + idempotent upsert.
- recompute-fire-targets CLI: solve every Case x country and persist for Grafana.
- CONTEXT.md glossary + ADR-0001 (why MC-threshold on liquid NW, not 25x spend).

Reuses the existing simulator unchanged (its cashflow hooks already supported
pension/kids/home). 345 tests pass; mypy + ruff clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 11:49:23 +00:00

30 lines
1.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# FIRE number via Monte-Carlo NW-threshold on the liquid pot
We compute each Case's target net worth (its "FIRE number") by searching net
worth for the smallest value at which Guyton-Klinger reaches a 99% Monte-Carlo
success rate — **not** a fixed safe-withdrawal-rate multiple (e.g. 25× spend).
A fixed multiple cannot honour the structure the engine already models: the
rising 30→70 equity glide, per-jurisdiction taxes drained from the portfolio,
the kids-cost ramp, an optional one-time home purchase, and a workplace pension
that is locked until ~57. Our block-bootstrap's empirical perpetual SWR is also
~2.53%, materially below the textbook 4%, so a 25× multiple would understate
the number anyway.
The solver seeds on **liquid** net worth — it excludes the Fidelity workplace
pension (inaccessible until ~57) and injects that pension as a grown lump at age
57. Early-retirement sequence risk is funded only by spendable assets, so seeding
total net worth would overstate safety exactly where the 99% bar is decided.
## Consequences
- A vectorised NW search (binary search over `initial_portfolio`, monotone
because the GK year-0 draw is an absolute real amount) populates a
`fire_target` table, one row per (Case × country × with-home).
- Targets vary by country through **both** COL-scaled spend and the destination
tax regime (the simulator drains tax from the portfolio since 2026-05).
- The Grafana countdown reads `fire_target` for the selected country and diffs
it against current liquid net worth from `account_snapshot`.
- Pension growth to age 57 is modelled deterministically (current value
compounded at an assumed real rate), not per-path — a conservative
simplification, revisitable if it ever binds.