The Thurstone race
Weights are winning probabilities. What happens when you add a near-duplicate?
A classic test of a choice model is the red bus / blue bus problem: split one option into two near-identical copies and see whether the model treats them as one option or two. Portfolios face the same test. Universes contain near-duplicates — share classes, an ETF and its top holding, two miners of the same commodity — and an allocator has to decide how much a near-copy of something it already holds is worth.
The Thurstone portfolio answers by simulation:
weights are the winning probabilities of a race among the assets, run under the estimated
correlation. A clone at correlation ρ = 1 can only split its original's wins, so
the pair inherits the original's weight. At ρ = 0 the clone is a genuinely new
asset and earns a full weight of its own. In between, the race prices how new the
asset really is, continuously in ρ.
Try it: clone a Dow stock
Twelve Dow names, daily returns 2010–2024, with abilities calibrated so the race under the
empirical correlation reproduces equal weight. Pick a stock, and drag ρ — the
correlation of a synthetic clone (same volatility, same ability, correlation to everything
else scaled by ρ). The race below re-runs live in your browser on a fixed
ensemble of 131,072 scenarios — the same common-seed transport the streaming estimator uses,
which is why the bars move smoothly as you drag rather than flickering with sampling noise.
Two standard allocators run alongside on the same inputs.
What to look at
Equal weight is blind to the duplication: the pair gets 2/13 of the portfolio at
every ρ. Adding enough copies of one asset would concentrate the whole portfolio
in it.
The race de-duplicates: as ρ → 1 the pair's combined weight falls
back to what the original had alone, and the other eleven names barely move. At
ρ = 0 the clone earns a genuine weight, funded pro-rata. The interpolation
between those endpoints is smooth, because winning probability is a smooth function of the
correlation.
Minimum variance responds to ρ too, but through
Σ⁻¹, and near-duplication makes Σ nearly singular. The direction
"long the clone, short the original" costs almost nothing, so the inverse is free to take
large opposite positions in two economically identical assets — and the split it picks is
decided by whatever noise is in the inputs. Press the nudge buttons: a 0.1% change
in the clone's volatility flips the sign of the split at high ρ. The race
weights cannot move under that nudge — the Gaussian race depends on the correlation and the
abilities, not the volatilities — but the deeper difference is that no inverse is taken
anywhere, so there is no ill-conditioned direction for input noise to be amplified into.
The same singularity that breaks the inverse is what the race uses as a signal: duplication shows up as shared wins, not as an unstable matrix. That is the property the paper calls redundancy consistency, and it is what lets the estimator run on universes where near-duplicates are the rule rather than the exception.
Reproducible: experiments/gen_thurstone_race_data.py builds the
embedded data (tickers, correlation, calibrated abilities) with the actual
allocation package; the in-browser race is the forward pass of
ThurstonePortfolio with target="equal". Estimator:
allocation/thurstone.py.