How Axfolio computes the risk-return frontier for your portfolio: the inputs we trust, the inputs we shrink, the constraints we honor, and the gaps we don't paper over.
The Axfolio Efficient Frontier shows the set of risk-return outcomes achievable by reweighting your client's current holdings — no new tickers introduced. Each grey dot in the scatter is one hypothetical reweighting; the upper envelope of the cloud is the frontier. Three target portfolios are computed analytically: the highest-return portfolio at the current volatility, the lowest-volatility portfolio at the current return, and the portfolio with the highest Sharpe ratio.
We are explicit about what this is and what it is not. It is a fast, transparent, advisor-facing portfolio optimizer with institutional-grade statistical estimators (Ledoit-Wolf shrinkage, Black-Litterman blending) and a real quadratic-program solver under realistic constraints (long-only, position cap, asset-class limits). It is not a multi-factor risk model, a tax-aware optimizer, or a robust-optimization engine. We tell you exactly which estimators are running in the diagnostics line on the chart, and we list every limitation in section 11.
There is no single "optimal" portfolio. Optimality depends on the client's risk tolerance, liquidity needs, tax situation, and IPS bands. The frontier reframes the question from "what's optimal?" to "what's achievable?" — making the conversation about the trade-off, not the answer.
asset_class field on each position.The advisor selects the lookback window (3 years, 5 years, 10 years, or all available history). Returns prior to the window are excluded before computing means and covariance. This lets you test stability — a frontier that shifts dramatically between a 3-year and 10-year window is a warning sign about input noise, and you should see that.
Minimum data requirement: each ticker must have at least 60 aligned trading observations for the frontier to render at all.
The sample covariance matrix Σ̂ from a finite return series is an unbiased but high-variance estimator of the true covariance. In a portfolio optimizer this is a known disaster — small sampling noise produces wildly different "optimal" portfolios. This is the canonical Markowitz error-maximization problem: the optimizer concentrates weight in tickers whose pairwise covariance estimates happened to be misleadingly low.
We replace the sample covariance with a convex combination of the sample and a structured target matrix F:
Σ_shrunk = δ · F + (1 − δ) · Σ̂
where F has the same diagonal as Σ̂ but every off-diagonal entry is replaced with
r̄ · σᵢ · σⱼ — that is, the constant-correlation target where r̄ is the average pairwise
correlation across all ticker pairs. This is the well-known "constant-correlation target" of
Ledoit and Wolf (2003).
The shrinkage intensity δ ∈ [0, 1] is computed analytically per portfolio using the Ledoit-Wolf optimal formula:
δ* = clip( π̂ / (γ̂ · T) , 0 , 1 )
When the sample covariance is already close to the target, γ̂ is small and δ* shrinks toward 0 (we trust the sample). When the sample is noisy and far from the target, δ* is larger (we trust the prior). The diagnostics line shows the active δ as a percentage.
Historical mean returns are the noisiest input to Markowitz optimization. Five years of AAPL daily data produces a 95% confidence interval on AAPL's annual expected return that's wider than ±10% — essentially uninformative. This is why pure mean-variance optimization with sample means is so unreliable in practice.
For each ticker i, we replace the sample mean with a convex combination of historical and a forward-looking prior derived from the ticker's asset class:
μ_i = (1 − τ) · μ̂_i + τ · μ_prior(asset_class_i)
with τ = 0.5 by default — half-weight to historical, half to prior.
We use the 2025 vintage of JP Morgan's Long-Term Capital Market Assumptions, an industry-standard 15-year forward expected-return projection used by institutional consultants. Asset-class values:
| Asset Class | Expected Return (annual) | Expected Vol (annual) |
|---|---|---|
| Equity | 7.8% | 15.0% |
| Fixed Income | 5.1% | 5.5% |
| Alternatives | 8.5% | 14.0% |
| Cash | 4.2% | 0.5% |
Full Black-Litterman (1992) requires equilibrium implied returns derived from market-cap weights and a P matrix encoding investor views with an Ω uncertainty matrix. The full machinery is most useful when the advisor wants to express explicit tactical views (e.g. "I think tech will outperform energy by 200bps").
Our use case is different: we want to tame noise, not express views. Convex shrinkage toward an institutional prior captures that need with far less implementation overhead and more transparency. We say "Black-Litterman style" rather than claim full Black-Litterman.
We draw 4,000 random portfolios from the feasible region defined by all constraints, compute (volatility, return, Sharpe) for each, and plot them as the grey scatter. This is what the advisor and client see as the visual cloud of "what's possible."
wᵢ ∝ -log(Uᵢ), then normalize.Each draw is checked against the position cap (clipped and redistributed) and asset-class constraints (rejection sampling). The diagnostics line reports the fraction of draws that survived constraint checks — a low acceptance rate (under 30%) signals that the constraint set is tight and the cloud may be sparse.
The random number generator is seeded deterministically from a fingerprint of the ticker list and current weights (FNV-1a hash → Mulberry32 PRNG). The same portfolio always produces the same scatter — flipping between cards or refreshing the page doesn't cause the cloud to "jitter."
Sampling shows the feasible region; for the three target portfolios we want the exact
analytical optimum. We solve the Markowitz quadratic program using the
Goldfarb-Idnani active-set algorithm via the quadprog JavaScript port,
running server-side as a Vercel serverless function at /api/efficient-frontier.
minimize: ½ · wᵀ Σ w − λ · μᵀ w
subject to: Σᵢ wᵢ = 1 (full investment)
wᵢ ≥ 0 (long-only)
wᵢ ≤ cap (position limit)
cᵢ_min ≤ Σ_{j ∈ class i} wⱼ ≤ cᵢ_max (asset-class limits)
μᵀ w ≥ r_floor (return floor — sameReturn target)
wᵀ Σ w ≤ v_cap (variance cap — sameVol target)
The parameter λ traces out the entire frontier as it sweeps from 0 (minimum-variance portfolio) to large positive values (return-maximizing portfolio). For each target we use a different search strategy:
λ = 0 and the return floor as a linear inequality. One QP solve.QP solves with constraints can take 50–500ms even for small problems. Running on Vercel keeps the browser thread responsive and lets us scale to richer constraint sets (sector limits, factor exposure caps, etc.) without browser-CPU concerns. The frontend renders sampled targets immediately, then upgrades to analytical results when the API responds — typically in under 500ms warm. If the API is unreachable, the UI silently falls back to sampled targets and the diagnostics badge reads "Sampled (fallback)".
+1e-10 ridge on the diagonal to guarantee positive-definiteness for the Cholesky factorization inside quadprog.After identifying the best sampled candidate for each target, we run a pairwise coordinate-ascent refinement as a sanity-check layer on top of (or in place of, when the QP API is unreachable) the analytical solver:
{5%, 2%, 1%, 0.5%, 0.2%}, in order:This converges to a local optimum on the frontier. For Markowitz under linear inequality constraints (a convex problem), the local optimum equals the global optimum modulo numerical precision. The complexity is O(N² × iterations) — fast for typical RIA portfolios with under 50 holdings.
The "How to reach the frontier" panel below the chart shows three portfolios. Each is a recommendation for how the current holdings could be reweighted — no new tickers added.
The portfolio with the highest expected return whose volatility does not exceed the current portfolio's volatility (within a ±2% tolerance band, widened to ±4% if no candidate is found). Answers: "If I'm comfortable with the current risk level, what's the most I can earn?"
The portfolio with the lowest volatility whose expected return is at least the current portfolio's return (within a ±1% tolerance band, widened to ±2%). Answers: "If I want to keep my expected return, how much can I de-risk?"
The portfolio with the highest Sharpe ratio across the entire feasible region. Answers: "Ignoring my current portfolio, what's the most efficient mix of these holdings?"
All constraints are advisor-configurable via the controls panel above the chart. They are enforced uniformly during sampling, refinement, and the analytical QP solve.
3 years / 5 years / 10 years / All available. Controls the slice of daily returns used for mean/covariance estimation.
25% / 40% / 60% / no cap. Default 40% — matches typical IPS-driven concentration limits.
Per-class lower and upper bounds for equity, fixed income, alts, and cash. Leave blank for no constraint. Useful for IPS-coupled optimization and conservative or growth-tilted mandates.
Toggle between exact analytical QP (default) and sampled-only mode. The sampled mode can be useful for fast offline demos or when the API endpoint is unavailable.
Every render produces a diagnostics line below the controls panel. It is intentionally verbose — a CFA reviewer should be able to reproduce or stress-test what's running without guesswork.
Analytical (QP) · Window: 5.0y (1260d) · Cov shrinkage (Ledoit-Wolf): 18% · Mean shrinkage: 50% to JPM prior · 73% of samples passed constraints
We list these explicitly because every quantitative model has them, and a methodology sheet that doesn't list them isn't really a methodology sheet.