D14-F03-A02 / Released engineering topic

Resampled Efficient Frontier: Measure Weight Instability Without Losing Frontier Rank

A production-minded guide to Resampled Efficient Frontier.

Resampled Efficient Frontier: Measure Weight Instability Without Losing Frontier RankD14 / D14-F03

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.

Rank-matched resampled frontiers and the correct averaging direction

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:

  1. Select source rows with replacement.
  2. Calculate the replicate mean and population covariance (ddof=0).
  3. Solve the long-only GMV portfolio.
  4. Find the replicate maximum mean.
  5. Map every requested q to beta_b(q).
  6. Solve minimum variance subject to that return target.
  7. 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:

Plain text
[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:

Plain text
[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 questionStart withWhat changesWhat it does not solve
How should uncertain views modify a market prior?Black-LittermanExpected returns through a prior and viewsSampling stability by itself
How unstable are optimized weights across plausible samples?Resampled Efficient FrontierRows, replicate moments, and rank-matched frontiersStructural errors repeated in every sample
How should a bounded error in the mean affect allocation?Robust Mean-VarianceMean vector inside a declared ellipsoidResampling or posterior beliefs
Which portfolio ranks best under a declared distribution class and loss event?Distributionally Robust PortfolioThe admissible return distributionUniversal or assumption-free safety
Which scenario mix maximizes long-run log growth?Kelly AllocationObjective and scenario wealth factorsWeight-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.

resampled frontier flow

ReferencesPrimary sources and evidence notes

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.
resampled-efficient-frontier.ts
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);}));}
Full-height labplaygroundOpen full screen
Written by

Fintech engineer building market-data and financial systems, and the author of every article, glossary record, and reference implementation on The Fintech Builder.