Skip to content

How the Numbers Work

brookie edited this page Nov 6, 2026 · 2 revisions

How the Numbers Work

Every formula the app uses, in plain language with the math. The code is in web/src/model.ts (projections) and src/financial_planner/summary.py (averages), and is covered by tests.

Contents

Signs and the data window

  • Internally, money out is positive and money in is negative.
  • The window is plan.months calendar months (12 by default) ending at plan.last_month, or at the newest counted transaction if that isn't set. ignore categories don't move the window.
  • Today is plan.today, or the month after the window.

Averages

For each category: average = total over the window ÷ number of months. Refunds inside a spending category reduce it. Credit averages are shown as positive amounts to subtract. One-time categories use the same formula for their "per month" set-aside.

The monthly budget

spending   = Σ planned regular categories
           − Σ planned credits that are ticked (not nested under a one-time cost)
           + Σ ticked non-tax one-time costs (each net of its ticked nested credits)
tax        = Σ ticked tax one-time costs (each net of its ticked nested credits)
savings    = Σ 529 contributions + Σ savings + Σ investment contributions
left over  = take-home income − spending − savings − tax

Compound growth

Yearly rates are applied monthly with the equivalent monthly rate so a year of growth is exactly the yearly rate:

i = (1 + r)^(1/12) − 1
balance after n months = P·(1+i)^n + m·((1+i)^n − 1)/i      (P = start, m = monthly addition)

College 529s

For each child, with return r, college-cost growth g, n = months until high-school graduation, Y = whole years until then, C = cost per year today, N = years of college:

529 at graduation = growth(P = balance today, m = monthly contribution, n, r)
cost of college   = Σ_{j=0..N−1} C·(1+g)^(Y+j)
covered           = 529 at graduation ÷ cost of college
surplus/shortfall = 529 at graduation − cost of college
…in today's $     = surplus/shortfall ÷ (1+g)^(n/12)
monthly needed    = (cost − balance·(1+i)^n)·i ÷ ((1+i)^n − 1)       (0 if already covered)

Retirement income

All in today's dollars. Let a be the primary partner's retirement age, yrs = a − their age today, r the return, f inflation, w the yearly withdrawal rate. Every other partner's age at retirement is their age today plus yrs.

Accounts and investments

balance at retirement = growth(balance today, monthly addition, round(yrs·12), rate)
monthly income        = balance at retirement ÷ (1+f)^yrs × w ÷ 12

Retirement accounts use the general return r; each investment uses its own return_pct, with its monthly addition taken from the planner.

Pensions

From the estimates (age → monthly):

before the first age        → 0
between two ages            → straight-line interpolation
after the last age L        → flat, or, with years of service S today:
                              estimate(L) × (S + age − age today) ÷ (S + L − age today)
grows_with_raises           → × (1 + raise)^max(0, age − age today − 1.5)

The 1.5 years reflects pensions based on the highest three-year average pay. A flat monthly pension is paid as is.

Social Security

claim age = claim_age set ? min(70, max(claim_age, age at retirement))
                          : max(62, age at retirement)
benefit   = amount at 67 × factor(round(claim age))
factor    = 62: 70% · 63: 75% · 64: 80% · 65: 86.67% · 66: 93.33% · 67: 100% · 68: 108% · 69: 116% · 70: 124%
starts    = the year the partner reaches the claim age

A benefit that starts after retiring isn't in "income at retirement", but is in "once all Social Security starts".

Totals and the gap

after tax                     = (pensions + accounts + investments + Social Security started) × (1 − tax rate)
once all Social Security starts = the same with every benefit included
gap / surplus                 = after-tax income − projected spending in the first retired year

The first full retired year is today's year − primary age today + 1 + a.

Spending over time

For calendar year y (using mid-year, y + 0.5):

children home  = children whose graduation (year + month/12) is later than y + 0.5
share gone     = (all children − children home) ÷ all children      (0 with no children)
category       = planned × max(0, 1 + share gone × kids-gone %)
                 × max(0, 1 + retired %)          (once retired)
living         = Σ categories + ticked non-tax one-time costs − ticked credits
                 (only those marked in_retirement once retired)
spending       = living + tax set-aside (in_retirement ones once retired) + health insurance (once retired)
savings        = 529s for children still home + savings (unless stopped by retirement)
                 + investment contributions (until retirement)

Income over time

before retirement: Σ take-home × (1 + raise)^(y − today's year) + other income
after retirement:  retirement income after tax, adding each Social Security benefit from its start year

Today's dollars vs. with inflation

The yearly view can show amounts "with inflation": each year's figure × (1 + inflation)^(y − today's year). Everything else on the page is in today's dollars.

Clone this wiki locally