Réplication en Python, depuis le code et les données officiels des auteurs, du papier « Optimal versus naive diversification » (Review of Financial Studies, 22(5)) : quatorze règles d'allocation contre le portefeuille naïf 1/N, sur six jeux de données, fenêtre roulante de 120 mois.
Le même contenu en PDF : rapport/rapport.pdf.
Résultat en une phrase. Les tables 3 et 4 du papier sont reproduites cellule par cellule :
312 valeurs sur 312 identiques à la précision imprimée (84 ratios de Sharpe, le rendement gagné par
unité de risque pris ; 84 équivalents certains, le rendement sûr qui rendrait l'investisseur indifférent
au portefeuille ; 144 p-valeurs, la probabilité d'observer un écart au moins aussi grand si les deux
règles se valaient), et la réplication a mis au jour une cellule numériquement dégénérée de la table originale,
dont la valeur publiée dépend d'un comportement du solveur Matlab de 2009. Tous les chiffres viennent de
results/tables/ (synthese_ecarts.csv pour le bilan).
English summary. Exact Python replication of DeMiguel, Garlappi and Uppal (2009, RFS), from the authors' official Matlab code and data: 14 allocation rules versus 1/N on six datasets, 120-month rolling windows. All 312 printed cells of Tables 3 and 4 (Sharpe ratios, certainty equivalents, p-values) are reproduced exactly; Table 5's relative turnovers match except one 8th-significant-digit rounding. The replication also uncovered one numerically degenerate cell (BS-C on the international dataset) whose published value depends on Matlab's quadprog returning exact zeros where conic solvers return near-zeros; the repository documents and reproduces the convention. Extending the horse race to 2026 (636 out-of-sample months, HAC p-values, Ledoit-Wolf and volatility-timing additions) upholds the paper's verdict: mean-variance stays significantly below 1/N, a few covariance-only rules win on single universes, none wins consistently.
Celle du papier : les règles d'allocation « optimales », qui estiment moyennes et covariances pour placer au mieux, battent-elles hors échantillon, c'est-à-dire sur des mois que l'estimation n'a jamais vus, la règle la plus bête qui existe, mettre 1/N dans chacun des N actifs ? En mots simples : quand on croit optimiser, on optimise surtout les erreurs d'estimation ; DGU montrent qu'avec des fenêtres de 120 mois, aucune des quatorze règles ne bat 1/N de façon consistante. Ce dépôt vérifie chacun de ces chiffres, puis servira à poser la même question avec vingt ans de données de plus.
Le papier est un des plus cités de la gestion de portefeuille (l'argument central contre l'optimisation naïve des moyennes-variances), et les auteurs distribuent leur code Matlab et leurs données. Or une réplication indépendante, dans un autre langage, avec des solveurs modernes, est le seul moyen de savoir si les chiffres tiennent au protocole ou à l'implémentation. Ce que ce dépôt apporte :
- La réplication exacte, vérifiable en une commande (
eelab replicate), avec l'écart cellule par cellule contre le papier dansresults/tables/ecarts_*.csv. - Une spécification du protocole en français (
docs/SPEC_DGU.md), tirée d'une lecture ligne à ligne du Matlab : les trois covariances qui coexistent, les réglages non imprimés dans le papier (poids renormalisés sur les actifs risqués, aversion au risque de 1), et dix pièges d'implémentation documentés. - Une découverte de réplication : la cellule BS-C du jeu international dépend du solveur (section 6).
Toutes les données sont celles des auteurs, téléchargées par script (scripts/fetch_data.py), jamais
commitées. Le tableau reprend la Table 2 du papier ; tous les fichiers contiennent des rendements
excédentaires mensuels, le taux sans risque en deuxième colonne.
| Jeu | N actifs | Période | Source |
|---|---|---|---|
| Secteurs S&P | 10 + marché | 1981-01 à 2002-12 | zip officiel DGU (données de R. Wessels) |
| Industries | 10 + marché | 1963-07 à 2004-11 | Ken French, vintage 2004 du zip DGU |
| International | 8 pays + monde | 1970-01 à 2001-07 | MSCI, zip DGU |
| Mkt/SMB/HML | 3 facteurs | 1963-07 à 2004-11 | Ken French, zip DGU |
| FF 1 facteur | 20 + marché | 1963-07 à 2004-11 | Ken French, zip DGU |
| FF 4 facteurs | 20 + 4 facteurs | 1963-07 à 2004-11 | Ken French, zip DGU |
Les fichiers Ken French frais (jusqu'à 2026-06) sont aussi téléchargés, pour l'extension à venir ; les millésimes divergent (le Mkt-RF de novembre 2004 vaut 0,0468 dans le zip de 2004 et 4,53 % dans le fichier de 2026), c'est pourquoi la réplication exacte se fait sur les données d'époque.
- Quatorze règles. Le naïf 1/N ; moyenne-variance (MV) ; Bayes-Stein (BS, moyennes rétrécies vers
celle du portefeuille de variance minimale) ; « data-and-model » de Pástor (DM, un prior sur un modèle de
facteurs) ; variance minimale (MIN) ; le marché (VW) ; MacKinlay-Pástor (MP) ; les versions sous
contrainte de vente à découvert MV-C, BS-C, MIN-C et G-MIN-C ; et les mélanges de Kan-Zhou (MV-MIN) et
1/N-variance minimale (EW-MIN). Chaque formule est dans
docs/SPEC_DGU.md, transcrite du Matlab. - Fenêtre roulante de 120 mois. À chaque mois, moyennes et covariances sont estimées sur les 120 mois précédents, les poids calculés, et le portefeuille tenu un mois. La performance est donc entièrement hors échantillon (sauf la ligne « MV in-sample », affichée par le papier comme borne supérieure théorique).
- Poids « risky only ». Convention non imprimée dans le papier : les poids sont renormalisés par la valeur absolue de leur somme sur les seuls actifs risqués. Sans elle, aucun chiffre ne colle.
- Trois mesures. Le ratio de Sharpe mensuel ; l'équivalent certain (CEQ), avec une aversion au risque de 1 ; la rotation (la part du portefeuille rebrassée chaque mois). P-valeurs de Jobson-Korkie avec la correction de Memmel contre 1/N, unilatérales comme dans le code d'origine.
- Comparer au papier, cellule par cellule.
eelab replicateécrit nos tables, les écarts contre les valeurs imprimées (extraites du PDF et recoupées sur deux extractions indépendantes), et une synthèse.
| Table du papier | Cellules | Identiques à la précision imprimée | Écart maximal |
|---|---|---|---|
| Table 3, ratios de Sharpe | 84 | 84 | 0,0000 |
| Table 3, p-valeurs | 72 | 72 | 0,00 |
| Table 4, équivalents certains | 84 | 84 | 0,0000 |
| Table 4, p-valeurs | 72 | 72 | 0,00 |
| Table 5, rotations (niveau et relatif) | 78 | 77 | 0,01 |
Comment lire ce tableau, en trois constats : d'abord, les 312 cellules des tables 3 et 4 sont identiques,
p-valeurs comprises, ce qui valide à la fois le protocole du papier et notre transcription ; ensuite, la
seule cellule non identique de la table 5 est la rotation relative du MV sur les industries, 606 594,36 dans
le papier contre 606 594,35 chez nous, un écart au huitième chiffre significatif ; enfin, cette réplication
exacte n'a été possible qu'en reproduisant des conventions absentes du papier (renormalisation risky-only,
trois covariances différentes selon la règle, dérive des poids décalée d'un mois dans la rotation), toutes
documentées dans docs/SPEC_DGU.md.
Comment lire cette figure : dans les deux panneaux de gauche, chaque point est une cellule d'une table du papier, avec en abscisse la valeur imprimée en 2009 et en ordonnée notre valeur de 2026 ; un point sur la diagonale grise est une cellule parfaitement reproduite, et les 168 points y sont tous. Le panneau de droite rend le « 312/312 » vérifiable d'un coup d'œil : l'histogramme des écarts papier moins réplication (ratios de Sharpe, équivalents certains et p-valeurs des tables 3 et 4) n'occupe qu'une classe, la classe zéro, avec 312 cellules sur 312.
En route vers ces 312 cellules, une seule résistait : le Sharpe de BS-C (Bayes-Stein sous contrainte) sur le jeu international, 0,0848 dans le papier, 0,0958 avec notre premier solveur, 0,0662 avec un second, alors que les deux solveurs trouvaient le même optimum à 10⁻¹³ près. L'explication, mesurée : sur 10 des 259 mois, l'optimum contraint ne détient aucun actif risqué (tout en cash) ; la renormalisation risky-only divise alors un vecteur quasi nul par sa somme quasi nulle, et le portefeuille de ces mois est du bruit de solveur. Le quadprog de Matlab rend des zéros exacts, 0/0 donne NaN, et le code d'origine remplace NaN par zéro : la valeur publiée repose sur ce comportement. En reproduisant la convention par son critère exact (position nulle quand aucune moyenne, rétrécie pour BS-C, n'est positive : le vecteur nul est alors l'optimum mathématique du programme contraint), le 0,0848 revient exactement. Autrement dit, une cellule d'une table d'un des papiers les plus cités de la discipline n'est pas définie par le protocole mais par le solveur ; elle est inoffensive pour les conclusions du papier, et documentée ici parce qu'une réplication doit dire aussi cela.
Vingt ans de données de plus changent-ils la conclusion du papier ? Les quatre jeux reconstructibles depuis
la bibliothèque Ken French de 2026 (industries, facteurs, 20 portefeuilles taille/valeur avec 1 ou 4
facteurs) sont réévalués sur 1963-07 à 2026-06 (636 mois hors échantillon), même protocole, quinze règles
(les treize du papier plus deux ajouts étiquetés : la variance minimale Ledoit-Wolf constante-corrélation,
qui rétrécit la covariance estimée vers une matrice où toutes les paires d'actifs partagent la même
corrélation, et le « volatility timing » de Kirby-Ostdiek, qui pondère chaque actif par l'inverse de sa
variance estimée, sans aucune covariance à inverser). Les p-valeurs contre 1/N sont données dans les deux
conventions, Jobson-Korkie unilatérale (celle du papier) et Ledoit-Wolf 2008 HAC bilatérale, robuste à
l'autocorrélation. Chiffres : results/tables/extension_2026_*.csv.
Comment lire cette figure : chaque panneau est un univers, chaque barre le ratio de Sharpe mensuel d'une règle sur 1963-2026, et la ligne pointillée le niveau de 1/N sur cet univers ; une barre qui dépasse la ligne fait mieux que 1/N, mais seuls les marqueurs signalent un écart significatif (« † » au-dessus, « * » en dessous, au seuil de p HAC bilatérale 0,05). Aucune règle ne porte de « † » sur les quatre panneaux à la fois : c'est le résultat principal du dépôt.
| Règle | Industries | Mkt/SMB/HML | FF 1 facteur | FF 4 facteurs |
|---|---|---|---|---|
| 1/N | 0,158 | 0,178 | 0,156 | 0,164 |
| MV | −0,004 * | 0,042 * | 0,039 * | 0,119 |
| MIN | 0,157 | 0,126 * | 0,238 † | 0,015 * |
| G-MIN-C | 0,171 | 0,152 | 0,163 | 0,246 † |
| EW-MIN | 0,167 | 0,140 | 0,228 † | 0,018 * |
| MIN-LW (ajout) | 0,160 | 0,134 | 0,174 | 0,130 |
| KO-VT (ajout) | 0,165 | 0,136 * | 0,165 † | 0,174 |
Ratios de Sharpe mensuels, extrait des quinze règles (table complète dans le CSV). Marqueurs, au seuil de p HAC bilatérale sous 0,05 : « † » significativement au-dessus de 1/N, « * » significativement en dessous.
Comment lire ce tableau, en trois constats : d'abord, la conclusion centrale du papier survit à vingt ans de données de plus, la moyenne-variance et Bayes-Stein restent significativement SOUS 1/N partout où la p HAC tranche ; ensuite, quelques règles fondées sur la seule covariance passent devant 1/N sur certains univers (MIN et EW-MIN sur les 20 portefeuilles à 1 facteur, G-MIN-C sur la version 4 facteurs, KO-VT), mais aucune ne gagne sur les quatre univers à la fois, et MIN, gagnante sur l'un, est perdante significative sur l'autre ; enfin, l'ajout Ledoit-Wolf constante-corrélation n'améliore jamais significativement, et sa rotation (0,10 à 0,30 par mois contre 0,02 pour 1/N) le pénaliserait encore après coûts. En une phrase : avec 63 ans de données, il n'existe toujours pas de règle d'optimisation qui batte 1/N de façon consistante.
Le même verdict tient en sous-période de crise. La table results/tables/extension_2026_crises.csv
découpe la série hors échantillon en trois sous-fenêtres (2007-07 à 2009-06, 2020-01 à 2021-12, 2022-01 à
2023-12), sans réestimation : sur la fenêtre 2008, 58 des 60 cellules de Sharpe sont négatives, et les
deux seules positives, MV (0,049) et BS (0,015) sur les industries, sont justement les règles perdantes
sur la période pleine. Sur la fenêtre 2020, les règles de variance minimale qui rivalisent avec 1/N sur
63 ans manquent le rebond (0,022 pour MIN et 0,009 pour MIN-LW sur les industries, contre 0,303 pour
1/N) ; sur la fenêtre 2022, aucun Sharpe ne dépasse 0,16 en valeur absolue, cette sous-fenêtre ne
départage rien.
Comment lire cette figure : chaque courbe suit la valeur d'un dollar investi en 1973-07 sur l'univers des industries, en rendements excédentaires du taux sans risque, sur une échelle logarithmique où une pente constante est un taux de croissance constant ; les bandes grises sont les trois sous-fenêtres de la table des crises citée au paragraphe précédent. La courbe MV s'arrête en octobre 1974 : le portefeuille non contraint y perd plus de 100 % sur un mois, sa richesse devient négative, et la ruine est définitive ; les deux variantes de variance minimale survivent mais finissent sous 1/N (23,9 $ et 25,8 $ contre 42,5 $).
uv sync --locked --all-extras # environnement verrouillé (Python 3.12, cvxpy/Clarabel)
uv run python scripts/fetch_data.py # zip officiel DGU (480 Ko), Ken French, FRED, Banque du Canada
uv run pytest # 18 tests ; ceux qui exigent les données se sautent sans elles
uv run eelab replicate # les 6 jeux, ~11 s ; écrit results/tables/*.csv et la synthèse
uv run eelab extend # extension 1963-2026, 4 jeux, ~14 s
uv run python scripts/make_figures.py # figure de réplication (section 5)
uv run python scripts/make_extension_figures.py # figures de l'extension (section 7)Durée mesurée : la réplication complète des six jeux prend 11 secondes (Apple M2, un cœur).
| Limite | Statut |
|---|---|
| La table 6 (données simulées), les fenêtres de 60 mois et la détention de 12 mois ne sont pas encore répliquées | reconnu ; le protocole est déjà documenté dans la spec |
| Le panneau « rendement perdu à 50 pb » de la table 5 n'est pas répliqué | reconnu ; la spec documente en outre un bug du code d'origine dans ce panneau (la ligne VW y affiche une autre stratégie) |
| Volet canadien, autres covariances (QIS), coûts de transaction dans l'extension | à venir ; l'extension 1963-2026 avec Ledoit-Wolf et p-valeurs HAC est faite (section 7) |
| Les valeurs cibles sont extraites du PDF du papier | mesuré : deux extractions indépendantes concordent cellule par cellule, et recoupent 8 valeurs citées dans la prose |
Papier et matériaux originaux : Victor DeMiguel, Lorenzo Garlappi et Raman Uppal, « Optimal versus naive diversification: How inefficient is the 1/N portfolio strategy? », Review of Financial Studies, 22(5), 2009 ; code et données distribués par les auteurs (révision 2019 de Shiming Wu). Données : Ken French (bibliothèque de Dartmouth), MSCI et données de Roberto Wessels telles qu'incluses dans le zip officiel. Réplication Python : Guillaume Vaudescal, 2026. Code sous licence MIT ; les données restent aux conditions de leurs distributeurs et ne sont pas redistribuées ici.


