A portfolio can look precise because its weights have many decimal places. That precision says nothing about stability. Change a few observations, and the mean-variance optimizer may send the portfolio somewhere else.
Resampled Efficient Frontier (REF) makes that sensitivity visible. We resample the return rows, estimate new moments, rebuild a frontier for each replicate, and average comparable portfolios. The last phrase is the heart of the method: we must preserve frontier rank. Minimum-variance portfolios are comparable to minimum-variance portfolios; middle-ranked portfolios are comparable to middle-ranked portfolios. Averaging every optimized weight together produces a number, but not a resampled efficient frontier.
This tutorial gives you a deterministic, inspectable version. You will see the exact sampled rows, moment estimates, rank targets, inner weights, correct average, and wrong global-average shortcut.
Why rebuild the optimizer?
Mean-variance weights depend on estimated means and covariances. Those estimates depend on the particular observations in the sample. REF treats the frontier as a statistical object: if plausible resamples produce very different portfolios at the same rank, the original weights deserve skepticism.
The method does not magically create information. It reorganizes information already in the sample and reveals how the optimizer reacts. A bad split, omitted cash dividend, impossible mark, stale security mapping, or inconsistent FX conversion will be resampled too. More replications can make a data error look consistently wrong.
What “same rank” means
Each replicate has its own global-minimum-variance (GMV) expected return and its
own maximum asset mean. For rank q between zero and one, define
beta_b(q)=beta_GMV,b+q(beta_max,b-beta_GMV,b).
At q=0, solve the replicate's GMV portfolio. At q=1, solve its maximum-mean
endpoint. At q=0.5, solve halfway through that replicate's feasible return
interval. This mapping lets us associate portfolios by economic position even
when raw expected returns move between samples.
The connecting guides run across matching ranks, not diagonally across whatever points happen to be close on the page.
The canonical algorithm
For each explicit bootstrap index row:
- Select source rows with replacement.
- Calculate the replicate mean and population covariance (
ddof=0). - Solve the long-only GMV portfolio.
- Find the replicate maximum mean.
- Map every requested
qtobeta_b(q). - Solve minimum variance subject to that return target.
- Store the rank label, target, weights, and diagnostics.
Then average only weights with the same q:
w_REF(q)=(1/B) sum_b w_b(q).
Because every inner portfolio lies in the same convex simplex, its rank-wise average also lies in the simplex. If a later layer imposes nonconvex cardinality or lot constraints, that property no longer guarantees feasibility and any repair must be named separately.
A fixture you can calculate
The example uses six synthetic two-asset decimal-return rows:
[0.00, 0.00]
[0.20, 0.00]
[0.10, 0.10]
[0.10, 0.00]
[0.05, 0.10]
[0.15, 0.05]
We do not ask a random generator to hide the evidence. The two resample index rows are stored explicitly:
[0,1,2,3]
[0,1,4,5]
For the first replicate, mu=[0.10,0.025] and
Sigma=[[0.005,0],[0,0.001875]]. The GMV weights are
[0.2727272727,0.7272727273]. For the second, mu=[0.10,0.0375] and
Sigma=[[0.00625,-0.000625],[-0.000625,0.00171875]]; the GMV weights are
[0.2542372881,0.7457627119].
Average those two rank-zero portfolios and we get
[0.2634822804,0.7365177196]. Both maximum-mean endpoints are [1,0], so the
rank-one average is [1,0].
Now consider the wrong shortcut: mix both endpoints and both GMV portfolios into one global average. The result no longer answers any named rank. It blends two different investor positions and discards the mapping that defines REF.
Reproducibility needs more than a seed
The reference package includes a small seeded bootstrap generator, but the fixture stores the full index matrix. That distinction matters. Different languages and libraries can turn the same integer seed into different streams. If you need exact replay, serialize the selected row indices, estimator convention, ranks, constraints, solver tolerance, and source-row identity.
Reordering the original return table while keeping the same numeric indices does not preserve a sample; the indices now select different observations. Either keep a stable row identifier or remap the indices to the same original rows.
The data contract comes first
In portfolio work, the return matrix is not just numbers. Every row needs an observation period and availability date. Every column needs a point-in-time security identity. The full panel needs a base currency, FX timestamp and quote direction, split/dividend treatment, missing-data policy, and survivorship rule.
I care about this because old portfolios often contain exactly the data defects that optimization amplifies: quantities entered with the wrong unit, marks that do not belong to that instrument or date, and holdings from several currencies compared before conversion to the portfolio's reporting currency. REF is a sensitivity tool after those checks—not a substitute for them.
Implementation without a mystery solver
The Python implementation and TypeScript implementation use a small active-set enumerator. For each candidate set of positive weights, they solve the equality-constrained minimum-variance equations, discard non-positive candidates, and keep the feasible minimum. This is readable and independently checkable for at most 12 assets.
Production universes need a reliable quadratic solver. Preserve per-cell solver statuses. One inaccurate inner solution does not become accurate because it is averaged with other solutions; an incomplete matrix of ranks and replicates must be reported as partial.
Learn by stepping through the lab
Open the rank-matching playground. The initial view already shows the full synthetic panel and final rank-zero result. Step through row selection, moment estimation, endpoint construction, rank alignment, and averaging. Switch to the comparison scenario to see the global mean lose its rank meaning. The failure case introduces an invalid index and shows the calculation stop before a frontier is drawn.
What to notice: the average is the final operation, not the first. Every member of an average must carry its rank and feasibility evidence.
What the tests prove
The shared JSON fixture reproduces both replicate means, covariances, GMV
weights, maximum-mean endpoints, and averaged weights. Tests cover B=1, seeded
determinism, invalid ranks and indices, the anti-global-mean regression, and
Python/TypeScript parity.
They prove that the implementation follows the selected algorithm. They do not prove that resampled weights have higher Sharpe ratio, lower realized risk, or better performance after costs. Those are empirical questions requiring point-in-time out-of-sample data.
Boundaries and historical evidence
The historical-example decision is deferred. A named market panel would need licensed data, point-in-time constituents, corporate-action and FX basis, an estimator record, and an out-of-sample comparison with costs. The public US patent record is useful for method history and rank/vector-averaging evidence; its public metadata currently labels the record “Expired - Lifetime.” That is not a statistical result or legal opinion. This package uses original code and short factual citations.
Summary
REF is valuable when it keeps the entire evidence chain: selected rows, replicate moments, replicate endpoints, common ranks, inner weights, and the rank-wise average. Its best lesson is not “averaging is safer.” It is that an optimized portfolio can be unstable, and stability must be measured without changing the object being compared.
Next, Robust Mean-Variance replaces repeated samples with an explicit set of possible mean vectors and asks for the best objective under the weakest member of that set.
Choose the family method by the decision you face
| Your real question | Start with | What changes | What it does not solve |
|---|---|---|---|
| How should uncertain views modify a market prior? | Black-Litterman | Expected returns through a prior and views | Sampling stability by itself |
| How unstable are optimized weights across plausible samples? | Resampled Efficient Frontier | Rows, replicate moments, and rank-matched frontiers | Structural errors repeated in every sample |
| How should a bounded error in the mean affect allocation? | Robust Mean-Variance | Mean vector inside a declared ellipsoid | Resampling or posterior beliefs |
| Which portfolio ranks best under a declared distribution class and loss event? | Distributionally Robust Portfolio | The admissible return distribution | Universal or assumption-free safety |
| Which scenario mix maximizes long-run log growth? | Kelly Allocation | Objective and scenario wealth factors | Weight-stability evidence |
Related concepts and learning handoff
The reviewed The Fintech Builder chapter KKT checks and limits of an optimality claim (17:33–18:43) supports the inner frontier solver review: a feasible target and a stationarity check matter before any replicate weight is averaged. It does not derive resampling or justify the rank grid.
Rendered from the canonical Mermaid sources linked by this article.
resampled frontier flow
ReferencesPrimary sources and evidence notesExpand the source trail, evidence role, and limitations behind the engineering choices.
Expand the source trail, evidence role, and limitations behind the engineering choices.
PATENT-6003018 — Portfolio optimization by means of resampled efficient frontiers
- Organization or authors: US patent record; inventors Richard O. Michaud and Robert Michaud.
- Source type: Official public patent record.
- Publication or effective date: 14 December 1999; priority 27 March 1998.
- Version: US6003018A, current record labels legal status “Expired - Lifetime”.
- URL or DOI: Google Patents record.
- Accessed: 2026-09-15.
- Jurisdiction: United States intellectual-property record.
- Supports: Recalculation on resampled inputs, index/rank association, and vector averaging of associated portfolios.
- Limitations: Legal-status labels include database caveats; the record does not prove statistical superiority or grant permission to copy protected text/code.
MOSEK-REF — Resampled optimization
- Organization or authors: MOSEK ApS.
- Source type: Maintained official technical documentation.
- Publication or effective date: Online edition accessed 2026-09-15.
- Version: Portfolio Optimization Cookbook, estimation-error chapter.
- URL or DOI: Resampled optimization section.
- Accessed: 2026-09-15.
- Jurisdiction: None.
- Supports: Parametric and nonparametric resampling, matching portfolios across simulated frontiers, averaging, and computational limitations.
- Limitations: Vendor documentation is a secondary technical explanation; package behavior is defined by the explicit contract and tests.
MICHAUD1998 — Efficient Asset Management
- Organization or authors: Richard O. Michaud.
- Source type: Original book-length method exposition.
- Publication or effective date: 1998.
- Version: Public author-hosted PDF copy; edition pagination should be checked before quoting.
- URL or DOI: New Frontier Advisors PDF.
- Accessed: 2026-09-15.
- Jurisdiction: None.
- Supports: Historical context for simulated efficient frontiers and rank-associated portfolio averaging.
- Limitations: No text or code is reproduced; the source does not make the package's synthetic fixture empirical evidence.
Full dependency-light reference implementations in both supported languages.
export class ContractError extends Error {}
type Vector=number[]; type Matrix=number[][];
function solve(a:Matrix,b:Vector):Vector{const n=b.length,aug=a.map((r,i)=>[...r,b[i]]);for(let c=0;c<n;c++){let p=c;for(let r=c+1;r<n;r++)if(Math.abs(aug[r][c])>Math.abs(aug[p][c]))p=r;if(Math.abs(aug[p][c])<=1e-14)throw new ContractError("singular linear system");[aug[c],aug[p]]=[aug[p],aug[c]];const z=aug[c][c];aug[c]=aug[c].map(v=>v/z);for(let r=0;r<n;r++)if(r!==c){const f=aug[r][c];aug[r]=aug[r].map((v,j)=>v-f*aug[c][j]);}}return aug.map(r=>r[n]);}
const dot=(a:Vector,b:Vector)=>a.reduce((s,x,i)=>s+x*b[i],0);const mv=(a:Matrix,x:Vector)=>a.map(r=>dot(r,x));
function* combos(n:number,k:number,s=0,p:number[]=[]):Generator<number[]>{if(p.length===k){yield p;return;}for(let i=s;i<n;i++)yield*combos(n,k,i+1,[...p,i]);}
function moments(rows:Matrix):[Vector,Matrix]{const t=rows.length,n=rows[0].length,mu=Array.from({length:n},(_,j)=>rows.reduce((s,r)=>s+r[j],0)/t);return[mu,Array.from({length:n},(_,i)=>Array.from({length:n},(_,j)=>rows.reduce((s,r)=>s+(r[i]-mu[i])*(r[j]-mu[j]),0)/t))];}
function minVariance(mu:Vector,sigma:Matrix,target:number|null):Vector{const n=mu.length;let best:{v:number,w:Vector}|undefined;for(let size=1;size<=n;size++)for(const active of combos(n,size)){const w=Array(n).fill(0);if(size===1){if(target!==null&&Math.abs(mu[active[0]]-target)>1e-9)continue;w[active[0]]=1;}else{const sub=active.map(i=>active.map(j=>sigma[i][j]));let invOne:Vector,subw:Vector;try{invOne=solve(sub,Array(size).fill(1));if(target===null){const den=invOne.reduce((a,b)=>a+b,0);subw=invOne.map(x=>x/den);}else{const invMu=solve(sub,active.map(i=>mu[i]));const a=invOne.reduce((x,y)=>x+y,0),b=active.reduce((s,asset,i)=>s+mu[asset]*invOne[i],0),c=active.reduce((s,asset,i)=>s+mu[asset]*invMu[i],0),det=a*c-b*b;if(Math.abs(det)<=1e-14)continue;const l1=(c-b*target)/det,l2=(a*target-b)/det;subw=invOne.map((x,i)=>l1*x+l2*invMu[i]);}}catch{continue;}if(Math.min(...subw)<=1e-11)continue;active.forEach((asset,i)=>w[asset]=subw[i]);}const v=dot(w,mv(sigma,w));if(!best||v<best.v-1e-14)best={v,w};}if(!best)throw new ContractError("frontier target is infeasible");return best.w;}
export interface Replicate{indices:number[];mean:Vector;covariance:Matrix;gmvReturn:number;maxReturn:number;weightsByRank:Vector[]}
export interface ResampledFrontierResult{ranks:Vector;averagedWeights:Vector[];replicates:Replicate[];status:"optimal"}
export function resampledEfficientFrontier(returns:Matrix,resampleIndices:number[][],ranks:Vector):ResampledFrontierResult{const rows=returns.map(r=>r.map(Number));if(rows.length<2||!rows[0]?.length||rows.some(r=>r.length!==rows[0].length)||rows.flat().some(v=>!Number.isFinite(v)))throw new ContractError("returns must be a finite rectangular matrix with at least two rows");if(!ranks.length||ranks.some(q=>!Number.isFinite(q)||q<0||q>1))throw new ContractError("ranks must lie in [0,1]");if(!resampleIndices.length)throw new ContractError("at least one resample is required");const replicates=resampleIndices.map(raw=>{const indices=raw.map(Number);if(indices.length<2||indices.some(i=>!Number.isInteger(i)||i<0||i>=rows.length))throw new ContractError("resample index is out of range");const[mean,covariance]=moments(indices.map(i=>rows[i]));const gmv=minVariance(mean,covariance,null),gmvReturn=dot(mean,gmv),maxReturn=Math.max(...mean);const weightsByRank=ranks.map(q=>minVariance(mean,covariance,gmvReturn+q*(maxReturn-gmvReturn)));return{indices,mean,covariance,gmvReturn,maxReturn,weightsByRank};});const averagedWeights=ranks.map((_,ri)=>Array.from({length:rows[0].length},(_,j)=>replicates.reduce((s,r)=>s+r.weightsByRank[ri][j],0)/replicates.length));return{ranks:[...ranks],averagedWeights,replicates,status:"optimal"};}
export function seededBootstrapIndices(rowCount:number,sampleSize:number,replications:number,seed:number):number[][]{if(Math.min(rowCount,sampleSize,replications)<=0)throw new ContractError("bootstrap sizes must be positive");let state=seed>>>0;return Array.from({length:replications},()=>Array.from({length:sampleSize},()=>{state=(Math.imul(1664525,state)+1013904223)>>>0;return Math.floor((state/4294967296)*rowCount);}));}
The embedded lab now expands to its full document height, keeping the article as the only scroll surface.
