Inspectable Arithmetic for the TFSA vs RRSP vs FHSA Calculator (Canada)
Version 1.1
Last verified: May 2026
Transparent arithmetic is the operating system of this calculator.
This document publishes the formulae, computational structure, and assumptions used to generate the outputs displayed on the calculator page.
No opinions. No hidden assumptions. Just arithmetic.
Purpose
This calculator compares the after-tax future value of contributing a fixed cash amount to different Canadian registered accounts:
TFSA, RRSP, and FHSA. It models recurring or lump-sum contributions, simple net investment growth, and explicit tax treatment on
contribution and withdrawal under marginal tax rates you set or that are estimated from your inputs.
Definitions
Let:
- C = contribution amount per period (monthly, annual, or one-time lump)
- T = investment horizon in years
- r = expected annual return before fees (percent)
- f = annual fee drag (percent)
- i = annual inflation rate (percent, optional)
- tnow = current marginal tax rate on contributions (percent)
- tret = marginal tax rate at withdrawal (percent)
- rnet = (r − f)/100 (net nominal annual return, decimal)
- id = i/100 (annual inflation in decimal form)
- rm = monthly nominal rate
- rm,real = monthly real rate (if real mode enabled)
- BTFSA,t, BRRSP,t, BFHSA,t = account balances at month t
- Brefund,t = refund bucket balance at month t (when refunds are reinvested)
Core Equations
1. Net return and monthly rate
Net annual nominal return (after fees):
rnet = (r − f) / 100
Nominal monthly rate:
rm = (1 + rnet)1/12 − 1
If “Show results in real dollars” is enabled, the calculator converts to a real annual rate first:
rreal = \(\dfrac{1 + r_{\text{net}}}{1 + i_d}\) − 1
and then to a real monthly rate:
rm,real = (1 + rreal)1/12 − 1
This is the same pipeline summarized on the calculator’s real-dollars mode: first the annual real return in decimal form,
\((1+r_{\text{net}})/(1+i_d)-1\) — equivalently \((1+r_{\text{net}})/(1+i/100)-1\) when \(i\) is your inflation input as a percent —
then that annual rate is converted to a monthly rate with the 12th-root step above.
The engine uses a single monthly rate for all accounts. There is no asset-location modeling (no different returns per account).
2. Contributions and horizon
Time horizon in months:
N = 12T
Contribution schedule:
- Monthly mode: C is contributed each month (C per month).
- Annual mode: C per year, internally modeled as C/12 contributed each month.
- Lump-sum mode: a single contribution C at month t = 0; no further contributions.
3. Refund arithmetic
For any RRSP or FHSA deposit d in a month, the modeled refund is:
refund = d × tnow/100
Refund handling modes:
- Spend refund (default): refund is ignored in the projection (treated as consumed).
- Reinvest refund: refund is added to a global refund bucket Brefund for that strategy in the month it occurs and compounds at the same monthly rate as other balances.
There is one refund bucket per strategy. The calculator does not separately label which portion of Brefund originated from RRSP vs FHSA contributions.
4. Monthly evolution (per strategy)
For each month t = 0,…,N−1, the engine:
- If t ∈ {12, 24, …} (first month of simulation years 2, 3, …), increases remaining TFSA and RRSP room per the TFSA/RRSP multi-year rules above, before allocating that month’s contribution.
- Computes the intended gross contribution Gt for that month based on mode (monthly, annual/12, or lump at t = 0).
- Allocates Gt between TFSA, RRSP, and FHSA according to the strategy and room constraints (TFSA/RRSP remaining room, plus FHSA rules in the next section).
- Applies refunds on RRSP/FHSA deposits into the refund bucket when “reinvest refund” is selected.
- Applies growth to all balances using the monthly rate.
Growth step (using either rm or rm,real):
BTFSA,t+1 = BTFSA,t(1 + rm)
BRRSP,t+1 = BRRSP,t(1 + rm)
BFHSA,t+1 = BFHSA,t(1 + rm)
Brefund,t+1 = Brefund,t(1 + rm)
TFSA and RRSP contribution room (multi-year)
The calculator takes opening TFSA contribution room and RRSP deduction room (totals available “today,” including unused carry-forward from prior years). Each deposit reduces the corresponding remaining room. No top-up is applied in month 0: your opening inputs are treated as the starting caps for simulation year 1.
At the beginning of simulation years 2, 3, … (i.e. at months 12, 24, …, before that month’s contribution is allocated), the model adds:
- TFSA: ATFSA dollars of new room, from the “new TFSA room each January” input (default aligned with the current statutory annual limit).
- RRSP: min(0.18 × I, M) dollars of new deduction room, where I is “current taxable income” from the tax section (used as an earned-income proxy) and M is a fixed indexed dollar cap in the engine (update periodically from canada.ca to match the RRSP 18% rule ceiling).
Unused room carries forward inside the simulation: whatever remains after contributions in a year is still available next year, plus the January top-ups above. Eventually, if contributions are large enough for long enough, carry-forward can be fully used and only the recurring annual top-ups remain—then further savings spill to non-registered once both registered rooms for that month are exhausted. This is a simplified calendar (one January refresh per simulation year, monthly contributions); it does not model CRA posting lags, pension adjustments, or employer plans.
FHSA Room and Allocation Rules
5. FHSA annual room and lifetime contribution cap
Let:
- R0 = FHSA annual contribution room in year 1 (user input; default matches the current $8,000 annual limit)
- R = FHSA annual room in subsequent years (same as input by default)
- L = lifetime FHSA contribution cap (default 40,000 in contribution dollars, aligned with current rules)
- CFHSA,tot,t = cumulative FHSA contributions deposited from month 0 through the end of month t (principal only)
For each simulation year y = 1,…,⌈T⌉, FHSA room at the start of the year is:
room1 = R0
roomy = R for y ≥ 2
At each month, any amount assigned to FHSA reduces roomy for that calendar year. Independently, cumulative contributions cannot exceed the lifetime cap:
CFHSA,tot,t ≤ L
The dollar amount that may be deposited to the FHSA in a month is therefore capped by both the remaining annual roomy and the remaining lifetime headroom (L − CFHSA,tot before that month’s deposit). Investment growth inside the FHSA increases the account balance but does not increase CFHSA,tot and does not count toward L.
When a strategy allocates to FHSA first, the engine:
- Contributes up to the minimum of remaining annual room, remaining lifetime room, and that month’s gross allocation.
- Spills any remainder of that month’s contribution to TFSA or RRSP, depending on the strategy.
Unused FHSA contribution carry-forward (year to year) is not modeled; only the annual room series above and the lifetime cap L are enforced. Verify current limits at canada.ca.
6. Strategies
Each strategy is a fixed priority order for filling TFSA, RRSP, and (when eligible) FHSA from each month’s gross contribution.
Account room and the FHSA lifetime cap are enforced at each step; any amount that cannot be placed in those three buckets goes to non-registered (last).
If FHSA is not eligible, the engine runs two strategies only:
- ALL_TFSA: TFSA → RRSP → non-registered
- ALL_RRSP: RRSP → TFSA → non-registered
If FHSA is eligible, the engine runs all six permutations of the three registered accounts (non-registered always last):
- ALL_TFSA: TFSA → RRSP → FHSA → non-registered
- TFSA_FHSA_RRSP: TFSA → FHSA → RRSP → non-registered
- ALL_RRSP: RRSP → TFSA → FHSA → non-registered
- RRSP_FHSA_TFSA: RRSP → FHSA → TFSA → non-registered
- ALL_FHSA: FHSA → TFSA → RRSP → non-registered
- FHSA_FIRST_THEN_RRSP: FHSA → RRSP → TFSA → non-registered
The headline optimal result is whichever of the simulated strategies (two or six, depending on FHSA eligibility) maximizes total after-tax value at the horizon.
The UI ranks every simulated strategy from highest to lowest after-tax total.
Withdrawals and After-Tax Values
7. Withdrawal tax treatment at horizon
At the end of the horizon (month N), balances are:
BTFSA,N, BRRSP,N, BFHSA,N, Brefund,N
After-tax values by account:
- TFSA: tax-free withdrawals
VTFSA = BTFSA,N
- RRSP: withdrawals taxed at tret
VRRSP = BRRSP,N(1 − tret/100)
\(\displaystyle
V_{\text{FHSA}} =
\begin{cases}
B_{\text{FHSA},N} & \text{if FHSA is eligible and “plan to buy using FHSA” is checked (home-qualified)} \\
B_{\text{FHSA},N}(1 - t_{\text{ret}}/100) & \text{otherwise (FHSA behaves like RRSP)}
\end{cases}
\)
- Refund bucket: always treated as tax-free in this version
Vrefund = Brefund,N
Total after-tax value for a given strategy is:
V_{\text{total}} = V_{\text{TFSA}} + V_{\text{RRSP}} + V_{\text{FHSA}} + V_{\text{refund}}
Allocation Summary
The calculator reports a human-readable “optimal split” sentence based on the simulated strategy that maximizes Vtotal:
- annualContribution: annualized contribution amount under the selected mode (12 × monthly for monthly mode, C for annual, C for lump treated as a one-year contribution).
- fhsaUsedAnnual: estimated FHSA contributions deposited in year 1 (capped by modeled annual room and lifetime cap).
- remainderAnnual: annualContribution − fhsaUsedAnnual.
- remainderDestination: “TFSA” or “RRSP”, a short label for explanatory copy tied to the winning priority order (not a full routing map).
Worked Example (Using Your Last Inputs)
The example below substitutes the last inputs you used on the calculator page (if available from this browser). Values are rounded for readability.
Open the TFSA vs RRSP vs FHSA calculator, enter your assumptions, and then click “Inspect the Arithmetic” to see a worked example here with your values.
Horizon T ≈ years,
nominal return r ≈ ,
fees f ≈ ,
so net annual rnet ≈ .
Monthly rate used in the simulation:
With contribution mode and contribution amount C ≈ ,
the engine simulates N = 12T ≈ monthly steps and allocates up to
per year to FHSA before spilling the remainder to
.
Assumptions and Limitations
- All simulations use monthly time steps with deterministic compounding and fixed contribution schedules.
- TFSA and RRSP room use opening user-entered balances plus January top-ups from simulation year 2 onward (new TFSA dollars and 18%-of-income RRSP room capped by a modeled dollar limit); unused room carries forward until used.
- Investment returns, fees, and (optionally) inflation are modeled as constant over the full horizon.
- RRSP and FHSA refunds are either treated as immediately spent (default) or reinvested in a TFSA-like bucket; actual tax timing and withholding are more complex in practice.
- Tax rates tnow and tret are either estimated from modeled employment income and province using the same tax engine as the Canada Personal Income Tax Calculator, or set directly via manual override; they are held constant over the horizon.
- FHSA modeling enforces the annual room you specify (default $8,000) and a $40,000 lifetime contribution cap per person; growth inside the FHSA does not count toward that cap. Contribution carry-forward and detailed withdrawal conditions beyond the home-qualified toggle are not modeled.
- Non-registered (taxable) accounts are not included in this version; it is an account-to-account comparison between registered options.
- All results are rounded for display; internal calculations use full floating-point precision.
If any discrepancy is identified between this documentation and the calculator output, the arithmetic in the engine governs.
What This Calculator Does Not Include
- Quebec-specific account labels and some provincial program interactions.
- Spousal attribution, estate, and successor-holder rules for registered accounts.
- Detailed FHSA first-home withdrawal conditions beyond the simplified qualified toggle.
- US persons, non-residents, and cross-border tax treaties.
- Behavioral contribution patterns (skipped years, lump-sum timing).
Sources and References