QuantCalc Methodology

Technical Documentation v1.2 · Last updated: April 2026

Part I — Monte Carlo Simulation

1. Introduction

QuantCalc uses Monte Carlo simulation to model the uncertainty inherent in retirement planning. Unlike deterministic calculators that assume fixed returns, Monte Carlo methods generate thousands of possible future scenarios based on the statistical properties of financial markets.

The fundamental question we answer is: Given your savings, contributions, spending needs, and asset allocation, what is the probability that your portfolio will sustain your retirement?

Real vs nominal dollars

All dollar values shown in QuantCalc results — projection charts, percentile bands, success-gauge tooltips, withdrawal tables — are inflation-adjusted to today's dollars (real dollars). We deflate every simulated future dollar by the cumulative simulated inflation path so that "$2.4M in 2060" means "the purchasing power of $2.4M today," not the nominal dollar amount that would print on a future bank statement. We chose this convention because retirement planning decisions — "can I afford this lifestyle?", "can I cover this expense?" — are about purchasing power, not headline dollar counts. If a chart label ever reads (nominal $), that specific chart is the exception. This is a placeholder paragraph; a fuller treatment is forthcoming.

2. Monte Carlo Simulation Overview

Monte Carlo simulation is a computational technique that uses repeated random sampling to obtain numerical results. For retirement planning, we simulate many possible "paths" that a portfolio might take over time.

The Basic Algorithm

For each simulation s = 1, 2, ..., N:
    Initialize portfolio value V₀
    For each time period t = 1, 2, ..., T:
        Generate random asset returns
        Update portfolio value based on returns and cash flows
        Record portfolio value Vₜ
    Record final outcome (success or failure)

Calculate statistics across all N simulations

With N = 1,000 to 10,000 simulations, we obtain a distribution of outcomes that reflects the range of possibilities given market uncertainty.

3. Asset Return Modeling

Log-Normal Returns

Financial returns are commonly modeled as log-normally distributed. If $P_t$ is the price of an asset at time $t$, the continuously compounded return over one period is:

$$ r_t = \ln\left(\frac{P_{t}}{P_{t-1}}\right) $$

We assume these log-returns follow a normal distribution:

$$ r_t \sim \mathcal{N}(\mu, \sigma^2) $$

where $\mu$ is the expected (mean) return per period and $\sigma$ is the volatility (standard deviation) per period.

Converting Annual to Monthly Parameters

Capital Market Expectations are typically quoted as annual figures. For monthly simulation:

$$ \mu_{\text{monthly}} = \frac{\mu_{\text{annual}}}{12} \qquad \sigma_{\text{monthly}} = \frac{\sigma_{\text{annual}}}{\sqrt{12}} $$

The division by $\sqrt{12}$ for volatility follows from the property that variance scales linearly with time for independent returns.

Growth Factor

Given a monthly return $r_t$, the portfolio growth factor is:

$$ G_t = 1 + r_t $$

4. Generating Correlated Returns

The Challenge

Real asset classes don't move independently. Stocks tend to move together, bonds often move inversely to stocks during crises, etc. We must generate returns that respect these correlations.

Correlation Matrix

For $n$ asset classes, the correlation matrix $\mathbf{R}$ is an $n \times n$ symmetric matrix where $R_{ij}$ is the correlation between assets $i$ and $j$:

$$ \mathbf{R} = \begin{pmatrix} 1 & \rho_{12} & \rho_{13} & \cdots & \rho_{1n} \\ \rho_{12} & 1 & \rho_{23} & \cdots & \rho_{2n} \\ \vdots & & \ddots & & \vdots \\ \rho_{1n} & \rho_{2n} & \cdots & & 1 \end{pmatrix} $$

Covariance Matrix

The covariance matrix $\mathbf{\Sigma}$ combines volatilities and correlations:

$$ \Sigma_{ij} = \rho_{ij} \cdot \sigma_i \cdot \sigma_j $$

Or in matrix form: $\mathbf{\Sigma} = \mathbf{D} \cdot \mathbf{R} \cdot \mathbf{D}$, where $\mathbf{D} = \text{diag}(\sigma_1, \sigma_2, \ldots, \sigma_n)$.

Cholesky Decomposition

To generate correlated random variables, we use the Cholesky decomposition. Any positive-definite covariance matrix can be factored as:

$$ \mathbf{\Sigma} = \mathbf{L} \cdot \mathbf{L}^T $$

where $\mathbf{L}$ is a lower triangular matrix.

Algorithm to generate correlated returns:
  1. Generate $n$ independent standard normal variables: $\mathbf{z} = (z_1, z_2, \ldots, z_n)^T$ where $z_i \sim \mathcal{N}(0, 1)$
  2. Transform using Cholesky factor: $\mathbf{x} = \mathbf{L} \cdot \mathbf{z}$
  3. The resulting vector $\mathbf{x}$ has covariance matrix $\mathbf{\Sigma}$
  4. Add means to get final returns: $r_i = \mu_i + x_i$

5. Capital Market Expectations

QuantCalc references return assumptions derived from publicly available publications by major asset managers. QuantCalc is not affiliated with any of these firms. The data is sourced from publicly available reports, press releases, and financial media coverage.

Capital Market Expectations (CME) are forward-looking estimates of expected returns, volatilities, and correlations for each asset class. Major asset managers publish CMEs annually, and these forecasts are widely reported in public financial media.

QuantCalc's Asset Classes

Asset ClassDescription
US StocksLarge-cap US equities (S&P 500-like)
International StocksDeveloped market ex-US equities
BondsInvestment-grade fixed income
Real EstateREITs / Real estate securities
CashMoney market / Short-term treasuries

Source mapping: Each firm publishes forecasts at varying levels of granularity. Where a source provides separate forecasts for US Large Cap, Mid Cap, and Small Cap equities, QuantCalc uses the Large Cap figure for "US Stocks" as it most closely represents the S&P 500 universe. Similarly, "Bonds" uses investment-grade aggregate or core bond forecasts, and "International Stocks" uses developed-market ex-US figures. For exact sub-category details, consult each firm's published report linked below.

Volatility estimates: Most firms do not publicly publish volatility estimates for exactly QuantCalc's 5 asset classes. Where a source publishes volatility data (e.g., J.P. Morgan's LTCMA includes volatility estimates in their full report), those figures inform our estimates. For other sources, volatilities are representative estimates based on long-term historical realized volatility for each asset class. Typical ranges: US equities 15-17%, international equities 17.5-20%, bonds 5-6.5%, real estate 13-16%, cash ~1%.

Correlation estimates: Published correlation matrices vary by source and methodology. J.P. Morgan's LTCMA includes a comprehensive correlation matrix in their full report. For sources that do not publish complete correlation matrices for these specific asset classes, QuantCalc uses representative estimates consistent with long-term empirical relationships (e.g., US/Intl equity correlation of 0.75-0.85, equity/bond correlation of 0.05-0.15, as documented in Dimson, Marsh & Staunton and other academic research). All correlation matrices are verified to be positive semi-definite for valid Cholesky decomposition.

Real vs. nominal returns: Most sources publish nominal returns (before adjusting for inflation). GMO is a notable exception — they publish real returns (after inflation). QuantCalc converts GMO's real returns to nominal by adding an assumed 2.5% long-term inflation rate, as noted in the GMO source description below. This enables consistent comparison across all sources.

Independent Source Selection

QuantCalc allows you to select separate sources for each of the three CME components:

This separation is important because different firms have different strengths. For example, you might prefer GMO's bearish return outlook combined with JPMorgan's well-documented correlation structure and historical volatility estimates. The backend automatically recomputes the Cholesky decomposition of the correlation matrix whenever sources are mixed, ensuring mathematically consistent correlated return generation.

By default, QuantCalc uses JPMorgan for returns and correlations (their LTCMA is the most comprehensive publicly available dataset) and Historical for volatility (long-term realized volatility is a robust baseline).

Example CME Data (Illustrative — BlackRock, as of Sep 2025)

AssetExpected ReturnVolatility
US Stocks5.2%16.5%
Intl Stocks7.2%17.5%
Bonds4.1%5.5%
Real Estate6.8%14.0%
Cash3.1%1.0%

CME Sources

QuantCalc references return assumptions derived from publicly available publications by major asset managers. QuantCalc is not affiliated with any of these firms. The data is sourced from publicly available reports, press releases, and financial media coverage.

QuantCalc references Capital Market Expectations from six publicly available sources, each with distinct methodological approaches:

BlackRock Investment Institute

Source: BlackRock return assumptions as reported in Morningstar's annual Capital Market Expectations survey (Christine Benz, "Experts Forecast Stock and Bond Returns: 2026 Edition") and other public financial media.

Last Updated: September 2025 (data as of Sep 30, 2025)

BlackRock's CMAs use a building-block approach combining current yields, expected growth, and valuation adjustments. Their methodology emphasizes regime-based analysis and incorporates macro factors including demographic trends, productivity growth, and monetary policy normalization. 10-year nominal return estimates: US equity 5.2%, US aggregate bonds 4.1%.

J.P. Morgan Asset Management

Source: As published in J.P. Morgan's publicly available Long-Term Capital Market Assumptions (Annual). Available at am.jpmorgan.com and via public press releases.

Last Updated: November 2025

J.P. Morgan's LTCMAs provide 10-15 year forecasts using equilibrium models adjusted for current valuations. Their framework integrates global macro research with quantitative factor models, producing return estimates that account for mean reversion in valuations and yields.

Vanguard Investment Strategy Group

Source: As published in Vanguard's publicly available Economic and Market Outlook (Annual). Available at vanguard.com.

Last Updated: December 2025

Vanguard employs the Vanguard Capital Markets Model (VCMM), a proprietary Monte Carlo simulation tool. VCMM generates 10,000 simulations based on historical relationships, current market conditions, and forward-looking yield curves to produce return distributions rather than point estimates.

GMO (Grantham, Mayo, Van Otterloo)

Source: Headline figures from GMO's 7-Year Asset Class Forecasts (Quarterly), as widely reported in financial press (Reuters, Bloomberg, FT). The underlying GMO research library is at gmo.com/americas/research-library.

Last Updated: January 2026 (Q4 2025 data)

GMO's forecasts are explicitly mean-reverting, assuming asset prices return to historical fair value over a 7-year horizon. Their methodology adjusts current prices for profit margins, valuations (P/E, Shiller CAPE), and dividend yields relative to long-term averages, producing forecasts that often diverge significantly from consensus.

Important note on return type: GMO publishes real returns (after inflation), while all other sources in QuantCalc publish nominal returns. To enable apples-to-apples comparison, GMO's real return forecasts have been converted to nominal by adding an assumed 2.5% long-term inflation rate. For example, GMO's published -6.0% real return for US equities becomes -3.5% nominal. This conversion is approximate; actual future inflation may differ. Users should be aware that GMO's forecasts are notably more pessimistic than other sources, reflecting their mean-reversion methodology and current high equity valuations.

Charles Schwab

Source: As published in Schwab's publicly available Long-Term Capital Market Expectations. Available at schwab.com/learn.

Last Updated: January 2026

Schwab's CMEs provide 10-year forward-looking return estimates derived from their proprietary framework. Their 2026 forecasts project 5.9% for US large cap equities and 4.8% for bonds. Published on their consumer-facing Learn page, these estimates are widely cited in public financial media and press releases.

Invesco

Source: As published in Invesco's publicly available Capital Market Assumptions (Annual). Available at invesco.com as public PDFs.

Last Updated: December 2025

Invesco's Capital Market Assumptions provide long-term return forecasts across a broad range of asset classes. Their methodology combines macroeconomic analysis with valuation-driven models, producing estimates that are published in publicly downloadable PDF reports across multiple regional pages.

6. Portfolio Return Calculation

Weighted Portfolio Return

Given asset allocation weights $w_1, w_2, \ldots, w_n$ (summing to 1) and individual asset returns $r_1, r_2, \ldots, r_n$, the portfolio return is:

$$ r_p = \sum_{i=1}^{n} w_i \cdot r_i = w_1 r_1 + w_2 r_2 + \cdots + w_n r_n $$

Portfolio Statistics

The expected portfolio return: $\mathbb{E}[r_p] = \sum_{i=1}^{n} w_i \cdot \mu_i$

The portfolio variance:

$$ \text{Var}(r_p) = \sum_{i=1}^{n} \sum_{j=1}^{n} w_i w_j \sigma_i \sigma_j \rho_{ij} = \mathbf{w}^T \mathbf{\Sigma} \mathbf{w} $$

7. Cash Flow Modeling

Time Periods

QuantCalc simulates on a monthly basis from current age to end of plan. Total months:

$$ T = 12 \times (\text{End Age} - \text{Current Age}) $$

Cash Flow Components

At each month $t$, the net cash flow $C_t$ consists of:

$$ C_t = \text{Contributions}_t - \text{Withdrawals}_t + \text{Social Security}_t + \text{Pension}_t $$

Pre-Retirement Phase

Before retirement (month $t < t_{\text{retire}}$): $C_t = M_{\text{contribution}} \times I_t$

Post-Retirement Phase

After retirement (month $t \geq t_{\text{retire}}$):

$$ C_t = -M_{\text{withdrawal}} \times I_t + SS_t + P_t $$

Social Security and Pension

Social Security begins at the specified claiming age:

$$ SS_t = \begin{cases} SS_{\text{monthly}} \times I_t & \text{if } t \geq t_{SS} \\ 0 & \text{otherwise} \end{cases} $$

Inflation Adjustment

Cash flows are adjusted for inflation to maintain purchasing power:

$$ I_t = (1 + \pi_{\text{monthly}})^t = \left(1 + \frac{\pi_{\text{annual}}}{12}\right)^t $$

8. Simulation Execution

Portfolio Evolution

The portfolio value evolves according to:

$$ V_{t+1} = V_t \times G_t + C_t $$

where $V_t$ is portfolio value, $G_t = 1 + r_{p,t}$ is the growth factor, and $C_t$ is net cash flow.

Handling Ruin

If the portfolio value goes negative, it is floored at zero:

$$ V_{t+1} = \max(0, V_t \times G_t + C_t) $$

Once $V_t = 0$ during retirement, the simulation is marked as a "failure" (ruin).

9. Success Rate and Statistics

Success Rate

A simulation is "successful" if the portfolio never hits zero during retirement:

$$ \text{Success Rate} = \frac{1}{N} \sum_{s=1}^{N} \mathbf{1}[V_t^{(s)} > 0 \text{ for all } t \geq t_{\text{retire}}] $$

Percentiles

Confidence Interval

The standard error of the success rate estimate is:

$$ SE = \sqrt{\frac{p(1-p)}{N}} $$

For $p = 0.95$ and $N = 1000$: $SE \approx 0.007$, so the 95% CI is approximately $\pm 1.4\%$.

10. Quasi-Monte Carlo Methods

Sobol Sequences

Standard Monte Carlo uses pseudo-random numbers which can exhibit clustering. Quasi-Monte Carlo (QMC) methods use deterministic low-discrepancy sequences designed to fill the sample space more uniformly.

QuantCalc uses Sobol sequences, which provide:

Transformation to Normal

Sobol points $u \in [0,1]$ are transformed to standard normal via the inverse CDF:

$$ z = \Phi^{-1}(u) $$
Part II — Portfolio Optimization PRO

11. Optimization Problem Formulation

QuantCalc's portfolio optimizer finds the asset allocation that maximizes retirement success probability (or other objectives) subject to real-world constraints. Unlike simple mean-variance optimization, our approach directly optimizes the Monte Carlo simulation output—accounting for sequence-of-returns risk, cash flows, and the full distribution of outcomes.

General Form

$$ \begin{aligned} \max_{\mathbf{w}} \quad & f(\mathbf{w}) \\ \text{subject to} \quad & \sum_{i=1}^{n} w_i = 1 \\ & w_i \geq 0 \quad \forall i \in \{1, \ldots, n\} \end{aligned} $$

Decision Variables

Single-period: $\mathbf{w} = (w_{\text{US}}, w_{\text{Intl}}, w_{\text{Bonds}}, w_{\text{RE}}, w_{\text{Cash}})^T$ — 5 variables

Multi-period (glide path): For $k$ periods, we optimize $k \times n$ weights:

PeriodsVariablesDescription
15Static allocation
210Two-phase (accumulation/retirement)
315Three-phase glide path

12. Objective Functions

Maximize Success Rate

$$ f_{\text{success}}(\mathbf{w}) = \frac{1}{N} \sum_{s=1}^{N} \mathbf{1}\left[ V_T^{(s)} > 0 \right] $$

Maximize Median Final Value

$$ f_{\text{median}}(\mathbf{w}) = \text{median}\left\{ V_T^{(1)}, V_T^{(2)}, \ldots, V_T^{(N)} \right\} $$

13. Constraints

Equality: For each period $p$: $\sum_{i=1}^{n} w_{p,i} = 1$

Bounds: $0 \leq w_{p,i} \leq 1$ for all weights (no short selling)

14. Sequential Quadratic Programming (SLSQP)

We use SLSQP because it handles exactly the constraint structure we need: equality constraints (weights sum to 1), bound constraints (0–100% per asset), and a smooth but simulation-derived objective.

The Quadratic Subproblem

At each iteration $k$:

$$ \begin{aligned} \min_{\mathbf{d}} \quad & \nabla f(\mathbf{w}^{(k)})^T \mathbf{d} + \frac{1}{2} \mathbf{d}^T \mathbf{B}^{(k)} \mathbf{d} \\ \text{subject to} \quad & \text{linearized constraints} \end{aligned} $$

Gradient Estimation

We estimate gradients numerically using finite differences:

$$ \frac{\partial f}{\partial w_i} \approx \frac{f(\mathbf{w} + h \mathbf{e}_i) - f(\mathbf{w})}{h} $$

A fixed random seed is used for all objective evaluations to eliminate stochastic noise.

BFGS Hessian Update

$$ \mathbf{B}^{(k+1)} = \mathbf{B}^{(k)} - \frac{\mathbf{B}^{(k)} \mathbf{s} \mathbf{s}^T \mathbf{B}^{(k)}}{\mathbf{s}^T \mathbf{B}^{(k)} \mathbf{s}} + \frac{\mathbf{y} \mathbf{y}^T}{\mathbf{y}^T \mathbf{s}} $$

15. Multi-Period Optimization

For $k$ periods, we flatten the weight matrix into a single decision vector:

$$ \mathbf{x} = (w_{1,1}, \ldots, w_{1,n}, w_{2,1}, \ldots, w_{2,n}, \ldots, w_{k,1}, \ldots, w_{k,n})^T \in \mathbb{R}^{kn} $$
PeriodsVariablesEquality ConstraintsGradient Evaluations
1516
210211
315316

16. Initial Point Selection

Strategy 1: User's current allocation extended to all periods

Strategy 2: Balanced portfolio: $w_{p,i}^{(0)} = 1/n$ (20% each)

Strategy 3: Age-based heuristic: $w_{\text{stocks}}^{(0)} = 1 - \text{age}/100$

17. Convergence and Termination

The optimization terminates when any condition is met:

18. Practical Considerations

Simulation Noise

A fixed random seed is used for all objective evaluations within the optimization loop. The final optimized allocation is then validated with a fresh simulation run.

Computational Cost

$$ \text{Evaluations} \approx k_{\text{iter}} \times (kn + 1) \times N_{\text{sims}} $$

Flat Regions

When success rate is very high (>95%) or very low (<5%), the objective surface becomes flat. Switching to median value objective can help.

Part III — Tax-Aware Mode PRO

19. Tax-Aware Withdrawal Optimization

QuantCalc's Tax-Aware Mode optimizes retirement withdrawals across multiple account types to minimize lifetime tax costs. Unlike naive withdrawal strategies that draw from accounts proportionally or in a fixed sequence, the tax-aware optimizer evaluates hundreds of withdrawal combinations each year to find the mix that minimizes total tax burden while meeting spending needs.

The Tax Problem in Retirement

Retirees typically hold assets across three account types, each with different tax treatment:

Account TypeContributionsGrowthWithdrawals
Traditional IRA/401kPre-tax (deductible)Tax-deferredFully taxable as ordinary income
Roth IRA/401kAfter-tax (non-deductible)Tax-freeTax-free (qualified distributions)
Taxable BrokerageAfter-taxTaxed annually (dividends, interest)Long-term capital gains rate on appreciation

Choosing which accounts to withdraw from—and in what amounts—directly impacts:

A naive strategy—such as "withdraw from taxable first, then traditional, then Roth"—can cost tens of thousands of dollars in unnecessary taxes over a 30-year retirement.

Account Structure

The optimizer tracks three account balances:

$$ \mathbf{A}_t = \begin{pmatrix} B_{\text{trad}}(t) \\ B_{\text{roth}}(t) \\ B_{\text{tax}}(t) \end{pmatrix} $$

For the taxable account, we also track the cost basis ratio:

$$ \gamma = \frac{\text{Cost Basis}}{\text{Total Value}} $$

This determines what fraction of a taxable withdrawal is principal (not taxed) versus capital gains (taxed at preferential rates).

Withdrawal Decision Variables

In each year, the optimizer chooses amounts to withdraw from each account:

$$ \mathbf{w}_t = \begin{pmatrix} w_{\text{trad}} \\ w_{\text{roth}} \\ w_{\text{tax}} \end{pmatrix} \quad \text{such that} \quad w_{\text{trad}} + w_{\text{roth}} + w_{\text{tax}} = W_t $$

where $W_t$ is the target withdrawal amount needed to cover spending for year $t$.

Tax Cost Function

The total tax cost for a given withdrawal mix is:

$$ C(\mathbf{w}_t) = T_{\text{income}}(\mathbf{w}_t) + T_{\text{CG}}(w_{\text{tax}}, \gamma) + T_{\text{IRMAA}}(\text{MAGI}) + T_{\text{penalty}}(w_{\text{trad}}, \text{age}) $$

Income Tax Component

Ordinary income includes traditional IRA withdrawals, Social Security (if applicable), pensions, and interest/dividends from the taxable account:

$$ I_{\text{ord}} = w_{\text{trad}} + SS + P + D_{\text{taxable}} $$

Federal income tax is computed using the progressive bracket structure. For married filing jointly in 2026 (indexed for inflation):

Taxable IncomeMarginal Rate
$0 – $23,20010%
$23,200 – $94,30012%
$94,300 – $201,05022%
$201,050 – $383,90024%
$383,900 – $487,45032%
$487,450 – $731,20035%
Over $731,20037%

Capital Gains Component

When withdrawing from a taxable account, only the appreciated portion is subject to capital gains tax:

$$ G = w_{\text{tax}} \times (1 - \gamma) $$

Long-term capital gains rates (for assets held >1 year) are preferential:

Taxable IncomeLTCG Rate
$0 – $94,050 (MFJ)0%
$94,050 – $583,75015%
Over $583,75020%

Notably, the 0% capital gains bracket creates an opportunity: if ordinary income is low enough, retirees can sell appreciated assets and pay zero tax on the gains.

IRMAA Surcharges

Medicare Part B and Part D premiums increase for high-income beneficiaries based on Modified Adjusted Gross Income (MAGI) from two years prior. For 2026 (based on 2024 MAGI):

MAGI (MFJ)Part B SurchargePart D SurchargeTotal Annual
Under $206,000$0$0$0
$206,000 – $258,000+$70/mo+$12/mo+$1,968/yr
$258,000 – $322,000+$175/mo+$31/mo+$4,944/yr
$322,000 – $386,000+$280/mo+$50/mo+$7,920/yr
$386,000 – $750,000+$385/mo+$69/mo+$10,896/yr
Over $750,000+$420/mo+$77/mo+$11,928/yr

IRMAA creates income cliffs: earning $1 over a threshold can cost thousands in additional premiums.

Early Withdrawal Penalty

Traditional IRA/401k withdrawals before age 59½ incur a 10% penalty (with certain exceptions like Rule 72(t) SEPP):

$$ T_{\text{penalty}} = \begin{cases} 0.10 \times w_{\text{trad}} & \text{if age} < 59.5 \\ 0 & \text{otherwise} \end{cases} $$

Required Minimum Distributions (RMDs)

Starting at age 73 (for those born 1951-1959), the IRS requires minimum annual withdrawals from traditional accounts based on the Uniform Lifetime Table:

$$ \text{RMD}_t = \frac{B_{\text{trad}}(t)}{\text{Life Expectancy Factor}(\text{age})} $$

The optimizer enforces: $w_{\text{trad}} \geq \text{RMD}_t$ when RMDs apply. Failing to take RMDs results in a 25% penalty on the shortfall (recently reduced from 50%).

Optimization Algorithm: Grid Search

QuantCalc uses a brute-force grid search over possible withdrawal mixes. For computational efficiency, we discretize the search space:

This produces 66 unique combinations per year. For each combination, we compute total tax cost $C(\mathbf{w}_t)$ and select the minimum.

Why grid search instead of gradient-based optimization?
  1. Tax brackets create a non-smooth objective with discontinuities
  2. IRMAA thresholds introduce sharp cliffs
  3. The search space is small (66 points) and evaluation is fast
  4. Global optimum is guaranteed (no local minima trap)

Multi-Year Simulation

Each Monte Carlo simulation path now includes yearly tax optimization:

For each simulation s = 1, 2, ..., N:
    Initialize accounts: A₀ = (B_trad, B_roth, B_tax)
    For each year t = 1, 2, ..., T:
        Generate portfolio returns
        Apply returns to all accounts
        Determine target withdrawal W_t (spending need)
        Compute RMD_t if age ≥ 73
        Run grid search over withdrawal mixes
        Select mix w_t* that minimizes C(w_t)
        Deduct withdrawals from accounts
        Record tax cost, account balances
    Calculate success rate and tax metrics

Metrics Reported

Tax-Aware Mode adds these outputs:

Practical Impact

For a typical retiree with $2M split across account types, tax-aware optimization can save $100,000 to $300,000+ over a 30-year retirement compared to naive strategies. The savings come from:

20. ACA Subsidy Cliff Management

For early retirees (ages 55-64, before Medicare eligibility), the Affordable Care Act (ACA) subsidy cliff represents one of the most significant financial risks in retirement planning. The cliff creates a scenario where earning just $1 of additional income can eliminate $15,000 to $30,000 in annual health insurance subsidies—an effective marginal tax rate exceeding 1,000%.

QuantCalc's Tax-Aware Mode includes ACA cliff detection and optimization to help early retirees navigate this challenge.

What is the ACA Subsidy Cliff?

The ACA provides premium tax credits (subsidies) to reduce the cost of marketplace health insurance for individuals and families below certain income thresholds. Prior to 2026, enhanced subsidies phased out gradually. Starting in 2026, the subsidies revert to the original ACA structure with a hard cutoff at 400% of the Federal Poverty Level (FPL).

For 2026, the cliff occurs at:

Household Size400% FPL (MAGI Threshold)
1 (Single)$60,240
2 (Married)$81,760
3$102,400
4$123,040
+1 per additional+$20,880

If Modified Adjusted Gross Income (MAGI) exceeds the threshold by even $1, the entire subsidy disappears. There is no gradual phase-out.

Subsidy Calculation

ACA subsidies are calculated as the difference between the "benchmark plan" premium (second-lowest-cost Silver plan in your area) and a capped percentage of your income:

$$ \text{Subsidy} = \max\left(0, P_{\text{benchmark}} - \text{MAGI} \times r_{\text{cap}}\right) $$

where $r_{\text{cap}}$ is the income-based cap percentage:

MAGI as % of FPLCap (% of MAGI)
100% – 133%2.0%
133% – 150%3.0 – 4.0%
150% – 200%4.0 – 6.5%
200% – 250%6.5 – 8.5%
250% – 300%8.5 – 9.5%
300% – 400%9.5%
Over 400%No subsidy

Example: The $1 Cliff

Consider a 62-year-old married couple in Denver, Colorado:

Scenario A: MAGI = $81,000 (below 400% FPL)

Scenario B: MAGI = $82,000 (above 400% FPL by $240)

Result: Earning an extra $1,000 cost this couple $16,305 in lost subsidies—a 1,631% marginal tax rate.

MAGI for ACA Purposes

ACA subsidies are based on Modified Adjusted Gross Income (MAGI), which is AGI plus certain add-backs. Critically, not all retirement income counts toward MAGI.

Income that COUNTS toward ACA MAGI:

Income that DOES NOT count toward ACA MAGI:

Key insight: Roth IRA withdrawals are "invisible" to the ACA. A retiree can withdraw $50,000/year from a Roth IRA, have $50,000 in actual spending power, and report $0 MAGI for ACA purposes—qualifying for maximum subsidies.

QuantCalc's ACA Cliff Detection

When Tax-Aware Mode is enabled and the user's age is under 65, QuantCalc checks for ACA cliff risk:

  1. Determine household size from inputs
  2. Calculate 400% FPL threshold for the applicable year
  3. Monitor projected MAGI each year during simulation
  4. Flag cliff proximity: if MAGI is within 5% of the threshold, mark as "cliff risk"

Optimization Strategy

When the ACA cliff is detected, the withdrawal optimizer adjusts its strategy:

Priority 1: Maximize Roth Withdrawals

Since Roth withdrawals don't count toward MAGI, the optimizer prioritizes Roth over traditional accounts when ACA subsidies are at stake:

$$ w_{\text{roth}} = \min\left(W_t, B_{\text{roth}}\right) \quad \text{before considering traditional or taxable} $$

Priority 2: Harvest Taxable Gains at 0%

If MAGI is low enough to stay in the 0% long-term capital gains bracket (under ~$94,000 for married couples), the optimizer may recommend withdrawing from taxable accounts to "harvest" gains tax-free while staying under the ACA cliff.

Priority 3: Avoid Traditional Withdrawals

Traditional IRA withdrawals add dollar-for-dollar to MAGI. The optimizer minimizes traditional withdrawals except when:

Priority 4: Reduce Spending if Necessary

If reducing traditional withdrawals would keep MAGI under the cliff and the subsidy value exceeds the foregone spending, the optimizer may recommend reducing withdrawals (and thus spending) in that year.

Example: If crossing the cliff costs $18,000 in subsidies, it's better to spend $15,000 less that year (living on Roth or reducing discretionary expenses) than to lose $18,000 in subsidies.

Multi-Year Considerations

The ACA cliff is a multi-year optimization problem. Spending down Roth balances aggressively in early retirement (ages 55-64) preserves ACA subsidies but leaves less tax-free money for later years. The optimizer balances:

Cliff Avoidance Tactics

QuantCalc models several advanced tactics automatically or via user configuration:

1. Roth Conversion Ladder (Pre-Retirement)

Convert traditional IRA funds to Roth IRA in low-income years (ages 50-54, or immediately post-retirement). This builds a Roth "cushion" for the ACA years.

2. Tax-Loss Harvesting (Taxable Accounts)

Sell losing positions to offset capital gains from winners, keeping net realized gains (and thus MAGI) low.

3. Bunching Income into Non-ACA Years

If a large income event is unavoidable (stock options vesting, real estate sale), time it for:

4. Spending Flexibility

Model variable spending: reduce discretionary expenses during ACA years to stay under the cliff, then increase spending after Medicare eligibility.

Metrics Reported

When ACA cliff logic is active, QuantCalc reports:

Limitations and Assumptions

QuantCalc's ACA cliff modeling assumes:

References and Further Reading

For detailed guidance on ACA subsidy optimization, see QuantCalc's ACA Subsidy Cliff 2026 blog post and the ACA Subsidy Calculator.

Part IV — Advanced Modeling PRO

Part IV documents the PRO-gated modeling extensions. Each feature is off by default and preserves bit-for-bit output when disabled — the baseline Monte Carlo engine described in Parts I–III is a strict subset.

21. Gompertz Gender-Specific Mortality

By default, simulations run a fixed horizon from current_age to life_expectancy. Under the mortality model, we draw per-path terminal ages from a Gompertz distribution with gender-specific parameters, so outcomes reflect the joint distribution of portfolio performance and longevity.

$$ \mu(t) = \frac{1}{b} \exp\!\left(\frac{t - M}{b}\right) $$

where $M$ is the modal age at death and $b$ is the dispersion parameter. Calibration follows Milevsky (2020) using SSA period life tables:

GenderModal age $M$Dispersion $b$
Male86.09.5
Female89.09.0
Unisex (default)87.59.25

For joint-life scenarios (MFJ filers with a spouse), each simulation path draws two independent Gompertz death ages. Survivor status drives filing-status transitions and reduces Social Security in the year following the first death.

22. Fat-Tail Returns & Regime Switching

Student-t Variance Mixture (Fat Tails)

The Gaussian return model understates the empirical kurtosis of equity returns. When Fat-Tail Returns is enabled, each monthly shock is drawn from a Student-t variance mixture:

$$ z_t = \frac{\varepsilon_t}{\sqrt{W_t / \nu}}, \quad \varepsilon_t \sim \mathcal{N}(0,1), \; W_t \sim \chi^2_\nu $$

The result is Student-t distributed with $\nu$ degrees of freedom. Variance is rescaled by $\sqrt{(\nu-2)/\nu}$ so the marginal variance still matches CME inputs. Recommended: $\nu=5$ reproduces empirical equity kurtosis $\approx 7$.

2-State Markov Regime Switching (Bull / Bear)

A Markov chain with transition matrix $P$ governs monthly switching between a bull and bear regime. In the bear state, the vol of the joint shock is multiplied by regime_bear_vol_mult and the drift shifted by regime_bear_drift_shift:

$$ P = \begin{pmatrix} 1-p_{bb} & p_{bb} \\ p_{\bar b b} & 1-p_{\bar b b} \end{pmatrix} $$

Defaults ($p_{bb}=0.01$, $p_{\bar b b}=0.15$, vol multiplier $1.8\times$) imply mean bear duration $\approx 6.7$ months and long-run bear probability $\approx 6.3\%$ — consistent with post-war US equity data.

23. Stochastic Inflation

The default engine compounds a constant CPI rate. The stochastic-inflation module replaces this with one of three user-selectable calibrated processes. Cash flows are stored in real (2025-dollar) terms and multiplied by a per-path cumulative inflation factor inside the simulation loop; this preserves bit-identical output when the model is deterministic.

Method 1 — AR(1) on CPI

$$ \pi_{t+1} = \bar\pi + \varphi (\pi_t - \bar\pi) + \sigma\, \varepsilon_{t+1}, \quad \varepsilon_{t+1} \sim \mathcal{N}(0,1) $$

Calibrated on FRED CPIAUCSL monthly log-differences, 1947–present (backend/calibration/fit_inflation_ar1.py). Anchored fit (post-1985 sample): $\bar\pi = 2.53\%$/yr, $\varphi = 0.4495$, $\sigma = 0.80\%$/yr.

Method 3 — Multi-Category Correlated AR(1)

Retirement spending is not single-index CPI. Medical, education, and housing categories compound at different rates with imperfect correlations. The multi-category model runs four parallel AR(1) processes on:

CategoryBLS SeriesLong-run $\bar\pi$$\varphi$$\sigma$ (%/yr)
CPI (all items)CPIAUCSL2.53%0.450.80
Medical careCPIMEDSL3.48%0.551.20
EducationCUSR0000SAE4.54%0.601.50
HousingCUSR0000SAH3.01%0.651.00

Shocks are cross-correlated via a Cholesky factor $L$ of a user-overridable correlation matrix (defaults land in backend/calibration/fit_inflation_multi.py). Each life event has a inflationCategory tag that selects which factor compounds that line item — medical events ride the medical-CPI path, tuition rides education, etc.

Method 4 — 2-State Regime (Anchored / Unanchored)

The 1970s and 2021–23 episodes are poorly described by a single Gaussian AR(1). We fit a 2-state hidden Markov model (Hamilton 1989) via the EM algorithm on the full postwar sample:

StateMeanStdTransition to other state
0 — Anchored2.0%/yr0.6%/yr$p_{01} = 0.4\%$/mo
1 — Unanchored6.0%/yr2.2%/yr$p_{10} = 2.0\%$/mo

Stationary distribution gives $P(\text{unanchored}) \approx 17\%$, matching the empirical unanchored months in 1965–1982 + 2021–2023. Calibration is in backend/calibration/fit_inflation_regime.py.

Method 5 — Stationary Block Bootstrap (internal validation only)

Politis-Romano (1994) stationary block bootstrap on historical CPI returns. Blocks are drawn with Geometric lengths (default mean 30 months) and resampled with wraparound. Used as a non-parametric yardstick against which methods 1/3/4 are validated; not user-exposed.

24. Per-Asset Inflation Coupling (β)

Real assets don't respond neutrally to inflation surprises. When coupling is enabled, each asset's monthly log-return is shifted by its inflation beta times the current surprise:

$$ \log r_{t}^{(i)} \leftarrow \log r_{t}^{(i)} - \beta_i \cdot (\pi_t - \bar\pi) $$

Literature defaults (Ang & Piazzesi 2003; Fama & Gibbons 1984; Bekaert & Wang 2010):

Asset$\beta$Interpretation
US Equity-0.30Mildly negative; long-duration cashflows hurt by surprise
Intl Equity-0.20Smaller due to FX hedging
Bonds-5.00Nominal duration risk — large sensitivity
Real Estate+1.00Partial hedge; rents reset with CPI
Cash+0.00Near-neutral at monthly horizon

25. State Tax, Roth Conversion, QCD & IRMAA Refinements

State Tax Engine (51 jurisdictions)

Federal-only tax mode still accounts for most of QuantCalc's audience, but single-state filers see meaningful divergence (FL/TX 0% vs CA 13.3% top). The state_tax.c engine carries per-jurisdiction brackets, standard deductions, Social Security taxability rules, and senior exemptions for all 50 US states + DC. State-level AGI is computed after federal subtractions and added to the per-year tax bill.

Roth Conversion Optimizer

Two modes are supported:

Conversions add to ordinary income in the year they occur, raising tax and potentially IRMAA tier. The simulator captures this interaction by re-running the full federal+state+Medicare pipeline per year.

Qualified Charitable Distributions (QCD)

For filers aged $\geq 70\tfrac{1}{2}$, up to $108,000 (2025 cap, indexed annually) of IRA distributions can be directed to charity and excluded from gross income. QCD reduces AGI, lowering both federal tax and the IRMAA premium tier. The simulator satisfies the RMD first, then applies QCD to the remaining withdrawal allowance.

Medicare-Specific Inflation (IRMAA)

Medicare premiums and IRMAA thresholds have historically outpaced core CPI by 1–3 percentage points. Users can decouple the Medicare inflation rate from the headline rate (medicareInflationRate). Defaults use the Medicare Board of Trustees projections; empirical calibration lives in backend/data/medicare/.

26. Randomized QMC & Wilson CI

Cranley-Patterson Scrambling

Unscrambled Sobol sequences are deterministic — two runs with the same inputs produce identical output and give no Monte Carlo standard-error estimate. With Sobol Scrambling enabled, each dimension is rotated by a random offset $r_d \sim U[0,1)$:

$$ u'_{i,d} = (u_{i,d} + r_d) \bmod 1 $$

This preserves the low-discrepancy property while randomizing the realization (Cranley & Patterson 1976). Running $K$ independent scrambled replicates gives an unbiased estimate of the QMC error.

Wilson 95% Confidence Interval on Success Rate

With $N$ simulations and $k$ successes, the normal-approximation CI $\hat p \pm 1.96 \sqrt{\hat p(1-\hat p)/N}$ degrades badly when $\hat p$ is near 0 or 1. The Wilson score interval stays valid across the full range:

$$ \text{CI}_{95\%} = \frac{\hat p + \tfrac{z^2}{2N} \pm z\sqrt{\tfrac{\hat p(1-\hat p)}{N} + \tfrac{z^2}{4N^2}}}{1 + \tfrac{z^2}{N}} $$

where $z = 1.96$. QuantCalc displays this CI next to every success-rate metric.

Pre-Computed Sobol Cache

At container-build time we generate a 10,000-sample × 6,480-dim Sobol cache using QuantLib's Joe-Kuo D7 direction numbers. Dimensions: 9 per month × 720 months (5 asset-return dimensions + 4 inflation-category dimensions), covering the widest model configuration.

Appendix

27. Implementation Notes

For $N$ simulations over $T$ months with $n$ assets, random numbers needed: $N \times T \times n$. For 10,000 sims × 720 months × 5 assets = 36 million random numbers. Stochastic inflation adds up to $4 \times 720 \times N$ more when method #3 is active.

Optimizations: Pre-generate random numbers in batch, vectorized operations, pre-compute Cholesky factors (asset returns and inflation categories), fixed seed during optimization, OpenMP parallelization of the per-simulation loop.

28. References

  1. Glasserman, P. (2003). Monte Carlo Methods in Financial Engineering. Springer.
  2. Jorion, P. (2006). Value at Risk. McGraw-Hill.
  3. Nocedal, J. & Wright, S. (2006). Numerical Optimization. Springer.
  4. Kraft, D. (1988). "A software package for sequential quadratic programming." DFVLR-FB 88-28.
  5. Sobol, I.M. (1967). "On the distribution of points in a cube." USSR Comp. Math. & Math. Phys.
  6. Joe, S. & Kuo, F.Y. (2008). "Constructing Sobol sequences with better two-dimensional projections." SIAM J. Sci. Comput.
  7. Cranley, R. & Patterson, T.N.L. (1976). "Randomization of number theoretic methods for multiple integration." SIAM J. Numer. Anal.
  8. Hamilton, J.D. (1989). "A new approach to the economic analysis of nonstationary time series and the business cycle." Econometrica.
  9. Politis, D.N. & Romano, J.P. (1994). "The stationary bootstrap." J. American Statistical Association.
  10. Ang, A. & Piazzesi, M. (2003). "A no-arbitrage vector autoregression of term structure dynamics with macroeconomic and latent variables." J. Monetary Economics.
  11. Fama, E.F. & Gibbons, M.R. (1984). "A comparison of inflation forecasts." J. Monetary Economics.
  12. Bekaert, G. & Wang, X. (2010). "Inflation risk and the inflation risk premium." Economic Policy.
  13. Milevsky, M.A. (2020). Retirement Income Recipes in R. Springer.
  14. Wilson, E.B. (1927). "Probable inference, the law of succession, and statistical inference." JASA.
  15. US Bureau of Labor Statistics — CPI series CPIAUCSL, CPIMEDSL, CUSR0000SAE, CUSR0000SAH (FRED).

Ready to run your own simulation?

QuantCalc runs this entire methodology in your browser — no account, no data collection.

Open QuantCalc →