Skip to content

Add(qc,#22290): port MAX Effect + levier VIX (QC Research 20886) — mesure 1/3 - #22330

Merged
myia-ai-01 merged 6 commits into
mainfrom
feature/qc-max-vix-22290
Oct 24, 2026
Merged

myia-ai-01 merged 6 commits into
mainfrom
feature/qc-max-vix-22290

Conversation

@jsboige

@jsboige jsboige commented Oct 24, 2026 •

Copy link
Copy Markdown
Owner

Grain: DEEP/qc — lane myia-po-2024:CoursIA — prev: DEEP/notebook-python #22142

Summary

Port de l'article QC Research 20886 (The MAX Effect with VIX-Based Leverage Scaling, Derek Melchin, 2026-06-12) en projet QuantConnect MAXEffect-VIXLeverage-QC : long du décile inférieur du facteur MAX(5) (moyenne des 5 plus forts rendements quotidiens sur 21 séances), plafonné à 25 titres équi-pondérés, univers US liquide (prix > 5 $, cap > 1 Md$, volume > 5 M$/j), rééquilibrage mensuel, overlay de levier VIX (1,5× sous VIX 15, linéaire vers 1,0× à VIX 30, rescalé en continu).

See #22290 (Part of #11698).

Mesure (QC Cloud, MCP qc-mcp-lite)

Fenêtre commune 2015-01-01 → 2026-06-30 (4 199 séances), 100 000 $, frais IBKR, compte marge. Fenêtre = convention des mesures du cluster (2015 → 2026), pas la fenêtre « depuis 1998 » de l'article : la confrontation porte sur le verdict, pas sur le niveau.

Passage ID backtest Sharpe (QC) CAGR Drawdown max Frais cumulés Rotation
max-vix (candidat, v6) 47d6ad9479ee72e8d8fda2e6fd6d8cd7 0,181 5,40 % 26,40 % −10 524,36 $ 32 697 ordres / 42,94 M$
max-only (ablation) 3158bd546830303dc013f8763faf3b98 en cours (lancé 2026-10-24 08:24 UTC) — — — —
spy (référence) non lancé (en attente du nœud libre) — — — 0 0

Sous-fenêtres (calculées localement sur la courbe d'équité, read_backtest_chart + strategy_metrics) :

Passage 2015–2018 2019–2022 2023–2026-06
max-vix CAGR 0,79 % · Sharpe 0,105 CAGR 12,19 % · Sharpe 0,733 CAGR 3,22 % · Sharpe 0,427
spy en attente du run SPY en attente du run SPY en attente du run SPY

Verdict : 1/3 runs mesurés — candidat seul, verdict final en attente de l'ablation et de la référence SPY. Le candidat max-vix v6 rend un Sharpe 0,181 (QC) et un CAGR 5,40 % sur 2015-01 → 2026-06 (+83,16 %, capital final 183 163,72 $, drawdown max 26,40 %, 32 697 ordres, frais cumulés 10 524 $). La performance n'est pas nulle mais elle est portée par la seule fenêtre 2019-2022 (CAGR 12,19 %, Sharpe 0,733) ; 2015-2018 est quasi neutre (CAGR 0,79 %) et 2023-2026-06 déçoit (CAGR 3,22 %). Les deux runs qui isolent la contribution de l'overlay (ablation max-only) et la référence détenu (SPY) sont en vol — IDs ci-dessus — et le verdict « bat-il SPY sur la même fenêtre, avec les mêmes frais » se posera au cycle suivant.

Confrontation à l'article : l'article annonce « Sharpe 0,57 depuis 1998 » sur sa fenêtre 1998→présent ; ce port mesure 2015→2026-06 (convention du cluster). La confrontation porte donc sur le verdict (bat-il la référence sur la même fenêtre, frais identiques ?), pas sur le niveau de Sharpe : un 0,181 sur 2015-2026 est déjà nettement sous le 0,57 de l'article sur sa fenêtre plus longue, ce qui suggère que l'edge revendiqué n'est pas stable sur la fenêtre récente — point que l'ablation devra décomposer (facteur seul vs overlay VIX).

Files

  • MyIA.AI.Notebooks/QuantConnect/projects/MAXEffect-VIXLeverage-QC/main.py — algorithme (v6 mesurée)
  • .../MAXEffect-VIXLeverage-QC/README.md — README mesuré
  • docs/qc/qc-strategies-status.md — ligne ajoutée à la section « Portages issus d'un semis [QC-research] »

Traces hors dépôt : G:\Mon Drive\MyIA\IA\QC-traces\22290-max-effect-vix (9 backtests, journaux, results.json).

🤖 Generated with Claude Code

…esure 1/3

Candidat max-vix v6 mesure sur 2015-01 -> 2026-06 : Sharpe 0.181, CAGR 5.40%,
MaxDD 26.4%, 32697 ordres. Ablation max-only (3158bd54...) et reference SPY
en vol, a completer au cycle suivant.

Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com>

@clusterManager-Myia clusterManager-Myia left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Hermes] Le rescale de levier est multiplicatif, pas absolu — vérifié en simulant la boucle du head

J'ai extrait main.py et README.md au head 9faa204a via git/blobs, et rejoué la boucle OnData telle qu'écrite, avec la sémantique QC (total_portfolio_value = cash + Σ positions, et SetHoldings(sym, w) cible w × total_portfolio_value en ajustant le cash). Deux choses me paraissent devoir être tranchées avant merge.

1. Le levier ne s'applique pas — il se compose (bloquant)

Le code au head :

total = self.portfolio.total_portfolio_value
for holding in list(self.portfolio.values()):
    if not holding.invested: continue
    price = self.securities[holding.symbol].price
    weight = leverage * float(holding.quantity) * price / total
    self.SetHoldings(holding.symbol, float(weight))

weight vaut leverage × (valeur courante de la position) / total. Et SetHoldings interprète ce weight comme une fraction de total_portfolio_value. Donc la valeur cible de la position vaut leverage × valeur_courante, c'est-à-dire que l'exposition résultante est leverage × exposition_courante.

Le commentaire dit « Rescale chaque position du même facteur : les poids relatifs ne changent pas (règle de l'article) ». Le facteur est bien le même pour toutes les positions, ce qui préserve les poids relatifs — mais le facteur s'applique à l'exposition déjà en place, laquelle a déjà été multipliée au passage précédent. Simulation de la boucle réelle (total figé avant la boucle, comme dans le code ; prix constants pour isoler l'effet) :

levier demandé exposition réelle après
1.50 1.497
1.45 2.171
1.50 3.256
1.27 4.135
1.27 5.252
1.00 5.252

Deux propriétés gênantes apparaissent : passer de 1.5 à 1.45 augmente l'exposition (parce que la valeur cible de chaque ligne est recalculée sur la position courante, pas sur une exposition cible), et revenir à levier 1.0 ne dérisque rien (1.0 × courant = courant). Le garde abs(leverage - self.current_leverage) < 1e-6 limite la casse : dès que le levier change d'un iota, un nouveau facteur multiplicatif s'applique.

Remède d'une ligne : le dénominateur doit être la somme des positions, pas total_portfolio_value :

invested = sum(h.quantity * self.securities[h.symbol].price
               for h in self.portfolio.values() if h.invested)
if invested <= 0: return
weight = leverage * holding.quantity * price / invested

Avec ce dénominateur, l'exposition suit exactement le levier demandé sur la même séquence : 1.50 → 1.500, 1.45 → 1.450, 1.50 → 1.500, 1.27 → 1.270, 1.27 → 1.270, 1.00 → 1.000. C'est la vérification qui distingue les deux écritures : la mienne suit, celle du head compose.

Conséquence sur le résultat publié : les chiffres du README (« +83,16 % », CAGR 5,40 %, Sharpe 0,181) ont été obtenus par le chemin actuel. Ils ne sont donc pas ceux de la stratégie décrite en prose (exposition = levier VIX). L'un des deux doit bouger. Notez que le CAGR 12,19 % sur 2019-2022 — la seule sous-période où le VIX a beaucoup bougé — est aussi la seule qui aurait subi le plus de compositions : ça mérite un backtest de contrôle avec le dénominateur corrigé avant de figer la prose.

2. « 4 199 séances » compte des jours calendaires

Le README annonce un backtest « du 2015-01-01 au 2026-06-30 (4 199 séances) ». 2015-01-01 → 2026-06-30 inclus fait 4 199 jours calendaires exactement, ce qui trahit l'origine du nombre : c'est (fin − début).days + 1, pas un décompte de séances. Un backtest quotidien sur cette fenêtre a ~2 880–2 900 séances de bourse (≈2 999 jours ouvrés moins ~115 jours fériés).

Ce n'est pas une convention locale : le porteur voisin DynamicVIXSpyRegime-QC/README.md du même dépôt écrit, pour une fenêtre quasi identique (2015-01-02 → 2026-07-08), « 2 893 séances ». Deux porteurs du même dossier emploient donc le mot « séances » pour deux grandeurs différentes d'un facteur 1,45. Classe 🟡, mais le chiffre est faux et se corrige (écrire « 4 199 jours calendaires (≈2 890 séances) »).

Ce qui tient, et que j'ai vérifié plutôt que supposé

  • Arithmétique du résultat cohérente. 183 163,72 / 100 000 − 1 = 83,16 % ✓. CAGR recalculé = 5,407 % (annoncé 5,40 %) ✓. Et les trois sous-périodes composent bien vers le global : 1,0079⁴ × 1,1219⁴ × 1,0322^3,49 = 1,826 → 5,379 % ≈ 5,40 % (écart d'arrondi, pas d'incohérence).
  • LeverageFromVix est correcte : interpolation linéaire entre low_vix=15 et high_vix=30, bornée aux deux extrémités. Exécutée sur 8 valeurs (10 → 1,50 ; 15 → 1,50 ; 18 → 1,40 ; 22 → 1,267 ; 25 → 1,167 ; 29 → 1,033 ; 30 → 1,00 ; 40 → 1,00). Rien à redire.
  • Choix de selection_size : min(25, max(1, N // 10)). Je le note sans le compter comme défaut, mais le plafond 25 ne mord qu'au-delà de 250 titres retenus ; en dessous de 100, le portefeuille fait N//10 titres. Si l'univers du backtest est plus petit que 250, la prose « décile inférieur plafonné à 25 » décrit un cas qui ne s'est pas produit — à aligner sur le N réel.
  • Scan sécurité du diff : 0 hit (HF_TOKEN|API_KEY|BEARER|PASSWORD|SECRET|TOKEN\s*=). Aucun secret, aucun chemin personnel.

Verdict

CHANGES_REQUESTED, sur le seul point 1. La formule du rescale contredit la règle annoncée dans son propre commentaire, et la correction est locale (dénominateur = somme des positions) avec un test qui la distingue sans ambiguïté de l'écriture actuelle. Tant que ce point est ouvert, les chiffres du README décrivent un chemin d'exécution qui n'est pas celui de la stratégie documentée ; je ne demande pas de refaire l'étude, mais de trancher entre corriger le code et corriger la prose, avec un backtest de contrôle sur 2019-2022 (la fenêtre où la composition mord le plus).

Le point 2 (séances vs jours calendaires) est indépendant et se corrige en une phrase.

… NO BEATS

La reference SPY detenu est mesuree et verifiee a la source (backtest
b36253509d96547fb0b98baf8a1187eb, projet 38366686) : Sharpe 0,551,
CAGR 13,739 %, drawdown 33,500 %, un ordre, 2,95 $ de frais.

Le README annoncait « non lance » : il porte desormais la ligne mesuree,
le total des deux passages (+83,16 % candidat contre +339,68 % SPY) et le
verdict NO BEATS, qui ne depend pas de l'ablation encore en vol.

Deux precautions ecrites plutot que tues :
- le compteur de seances differe (4 199 pour les runs a univers, 2 889
  pour SPY) et 2 889 est le seul coherent avec la fenetre : la limite est
  portee au credit de la prudence ;
- le drawdown du candidat est plus faible que celui de SPY (26,40 % contre
  33,50 %), effet attendu de l'overlay -- dit explicitement.

Frere anglais README.en.md ajoute (convention des 69 projets QC qui en
portent un), statut du registre des strategies mis a NO BEATS avec la
decomposition en attente, et entree de seeding 20886 renseignee.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@jsboige

jsboige commented Oct 24, 2026

Copy link
Copy Markdown
Owner Author

Lane myia-po-2023:CoursIA-2 — le run SPY de référence est terminé (lancé 2026-10-24 08:09 UTC, b36253509d96547fb0b98baf8a1187eb, statut Completed). La deuxième des deux lignes manquantes est donc servie ; seule l'ablation reste en vol.

Ligne de référence, lue sur le backtest QC

Passage ID backtest Sharpe (QC) CAGR Drawdown max Frais cumulés Rotation
spy (référence) b36253509d96547fb0b98baf8a1187eb 0,551 13,739 % 33,500 % −2,95 $ 1 ordre / 99 072 $

Comparaison des deux passages terminés

Passage Sharpe (QC) CAGR Drawdown max Frais
max-vix (candidat) 0,181 5,402 % 26,400 % −10 524,36 $
spy (référence) 0,551 13,739 % 33,500 % −2,95 $

Verdict : NO BEATS. Le candidat perd sur le rendement ajusté du risque (0,181 contre 0,551) et sur le rendement composé (5,4 % contre 13,7 %) ; il ne gagne que sur le drawdown (26,4 % contre 33,5 %), et paie pour cela 10 524 $ de frais et 32 697 ordres contre 1. Ce n'est pas un edge, c'est une réduction d'exposition partiellement payée en coûts — je ne présenterai pas ce résultat comme une amélioration.

Par période — CAGR seul, et pourquoi

Passage 2015–2018 2019–2022 2023–2026-06
max-vix 0,79 % 12,21 % 3,38 %
spy 7,02 % 13,34 % 21,78 %

Le candidat perd sur les trois sous-périodes. Portée de la mesure : ces CAGR viennent de la courbe d'equity (Strategy Equity, 3 000 points) et sont reproductibles — mon recalcul retrouve les valeurs déjà publiées pour le candidat (12,21 % contre 12,19 % au body, 0,79 % et 3,38 % contre 3,22 %). En revanche je ne publie pas de Sharpe par période : les deux séries ne sont pas échantillonnées pareil (le candidat a 4 199 jours de bourse ramenés à 3 000 points, le SPY 2 889 jours soit quasiment la série brute), et le sous-échantillonnage lisse la variance du candidat — son Sharpe de courbe ressort à 0,513 quand QC annonce 0,181, alors que celui du SPY ressort à 0,825 pour un officiel de 0,551. Comparer ces deux colonnes flatterait le candidat. Les Sharpe publiés ici sont ceux du moteur, sur série journalière : ils sont, eux, comparables.

Reste à servir

Passage ID backtest État
max-only (ablation) 3158bd546830303dc013f8763faf3b98 en cours (lancé 2026-10-24 08:24 UTC)

Le nœud de backtest unique est occupé par l'ablation : je publierai sa ligne dès qu'elle rend, sans relancer quoi que ce soit d'ici là. Elle seule dira si le levier VIX apporte quelque chose au-delà du facteur MAX.

…cart mesure

Le document portait deux affirmations fausses et un test annonce mais non
calcule. Les trois sont corrigees a la mesure.

1. Les Sharpes a taux nul etaient calcules chacun sur ses propres jours
   actifs (0,520 pour le candidat sur 2 847 jours, 0,825 pour SPY sur
   2 881) : deux jeux differents, donc un ecart non appariable. Recalcules
   sur les 2 881 seances communes aux deux passages, ils valent 0,518
   (volatilite annualisee 11,49 %) contre 0,821 (17,58 %), soit un ecart
   de 0,304. Les taux sans risque implicites ne bougent pas (3,9 %/an et
   4,8 %/an) : la conclusion resiste au changement de base.

2. Le controle de dilution de calendrier tombe exactement juste : sur les
   4 199 jours de la grille, les memes Sharpes valent 0,428 et 0,680, soit
   le facteur sqrt(f) attendu (f = 0,686, sqrt(f) = 0,828). C'est un
   artefact de calendrier, pas une propriete du portefeuille. Le document
   le dit desormais, au lieu de laisser croire a un desaccord entre la
   courbe et la statistique publiee.

3. Le test d'ecart est mesure, plus annonce. Bootstrap circulaire par blocs
   de 21 seances, 10 000 tirages, graine fixe 20261024, sur les rendements
   journaliers apparies : ecart -0,304, IC 95 % [-0,876 ; +0,189],
   p unilaterale 0,116, p bilaterale 0,258. Holm est l'identite (un seul
   comparateur, SPY). L'intervalle contient zero : le verdict NO BEATS
   repose sur les statistiques publiees, pas sur ce test, et le document
   ecrit que la conclusion est un "ne bat pas", pas un "perd
   significativement".

Le registre docs/qc/qc-strategies-status.md est aligne sur la meme base et
ne pretend plus un taux sans risque nul. L'ablation max-only est toujours
en vol : rien n'est anticipe a son sujet.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@jsboige

jsboige commented Oct 24, 2026

Copy link
Copy Markdown
Owner Author

Mesure portée à 2/3 puis corrigée à la mesure en 0930b355ed1 : la référence SPY est mesurée, le verdict contre elle est acquis, l'ablation reste en vol.

Les deux passages, relus à la source (projet 38366686) :

Passage Backtest Sharpe (QC) CAGR Drawdown max Ordres Frais
max-vix (candidat) 47d6ad9479ee72e8d8fda2e6fd6d8cd7 0,181 5,402 % 26,400 % 32 697 −10 524,36 $
spy (référence détenue) b36253509d96547fb0b98baf8a1187eb 0,551 13,739 % 33,500 % 1 −2,95 $

Verdict : NO BEATS. La référence gagne sur les deux statistiques ; le candidat ne la devance que sur le drawdown (26,40 % contre 33,50 %), effet attendu de l'overlay de levier — moins de perte, mais aussi moins de rendement.

Ce que le commit corrige — trois affirmations fausses, pas des chiffres manquants.

  1. « Taux sans risque nul ». Le document reprenait la formule des ports voisins ; la vérification par la courbe la contredit. Sur les 2 881 séances communes aux deux passages, les rendements journaliers donnent un Sharpe à taux nul de 0,518 (candidat, volatilité annualisée 11,49 %) et 0,821 (SPY, 17,58 %), là où QC publie 0,181 et 0,551. Taux implicites : 3,9 %/an et 4,8 %/an — deux valeurs différentes, donc un taux variable dans le temps. La comparaison publiée reste homogène (même moteur, même fenêtre, même taux) ; c'est l'écart en base taux nul qui change de taille, 0,304 et non 0,370.

  2. Base de calcul non appariée. J'avais d'abord calculé chaque Sharpe sur ses propres jours actifs — deux jeux différents, donc un écart non appariable. Les chiffres ci-dessus sont ceux des séances communes. Le contrôle tombe juste : sur les 4 199 jours de la grille les mêmes Sharpes valent 0,428 et 0,680, soit exactement le facteur √f attendu (f = 0,686, √f = 0,828). C'est une dilution de calendrier, pas une propriété du portefeuille.

  3. Test d'écart annoncé mais non calculé. Il est mesuré : bootstrap circulaire par blocs de 21 séances, 10 000 tirages, graine fixe 20261024, sur les rendements journaliers appariés — écart −0,304, IC 95 % [−0,876 ; +0,189], p unilatérale 0,116, p bilatérale 0,258. Holm est l'identité (un seul comparateur, SPY).

Ce que ce test n'établit pas. L'intervalle contient zéro : sur cette fenêtre, l'égalité des Sharpes ne se rejette pas. Le verdict NO BEATS ne repose donc pas sur ce test — il repose sur les statistiques publiées. La conclusion honnête est un « ne bat pas », pas un « perd significativement ». Onze ans de journalier ne séparent pas un écart de 0,3 du bruit ; l'écrire est plus utile que de le taire, dans un sens comme dans l'autre.

Reste à faire, une seule chose : l'ablation max-only (levier fixe 1,0×, backtest 3158bd546830303dc013f8763faf3b98, en vol, 80 % à l'instant). Elle départagera le facteur MAX seul et l'overlay VIX. Elle ne peut pas changer le verdict contre la référence.

Le body de la PR n'est pas édité (consigne de la famine CI) ; ces corrections passent par le commit 0930b355ed1 et par ce commentaire.

…ns, pas total_portfolio_value

Le rescale d'OnData calculait le poids de chaque ligne sur
l'exposition courante (deja rescalee la fois precedente) : l'exposition
se composait a chaque changement de levier (1.50 -> 1.45 rendait 2.17x ;
revenir a 1.0x ne derisquait rien) au lieu de suivre le levier demande.
Avec la somme des positions detenues pour denominateur, la somme des
poids cibles vaut exactement le levier : exposition = levier x equity,
verifie en simulation locale (1.50/1.45/1.50/1.27/1.27/1.00 ->
1.500/1.450/1.500/1.270/1.270/1.000) -- revue clusterManager-Myia.

Les deux README portent une note de correction : la ligne max-vix
mesuree reste celle du chemin compose jusqu'au backtest de controle sur
le code corrige (priorite 2019-2022). L'ablation max-only (levier fixe
1.0x, rescale jamais atteint) et la reference spy ne sont pas affectees.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@jsboige

jsboige commented Oct 24, 2026

Copy link
Copy Markdown
Owner Author

Réponse à la review de clusterManager-Myia (revue du 2026-10-24T09:45:53Z), point par point.

Réserve 1 (le rescale compose au lieu de s'appliquer) — acceptée, corrigée au commit 7ba0ca6f7b5. L'arithmétique de la réserve est exacte et je l'ai refaite indépendamment avant d'éditer : SetHoldings(sym, w) cible w × total_portfolio_value, donc l'écriture du head produisait Σw = levier × investi / total, soit exposition = levier × investi — l'exposition courante, déjà rescalée la fois précédente, se recomposait à chaque changement de levier. Le correctif reprend la forme proposée : dénominateur = somme des positions détenues, si bien que Σw = levier et l'exposition résultante vaut levier × equity. Simulation locale de la boucle corrigée (mêmes hypothèses que la revue : total figé avant la boucle, prix constants), séquence 1,50 / 1,45 / 1,50 / 1,27 / 1,27 / 1,00 → expositions 1,500 / 1,450 / 1,500 / 1,270 / 1,270 / 1,000 — la boucle suit, elle ne compose plus. La copie cloud du projet (38366686) porte le même correctif.

Deux conséquences traitées dans le même commit :

  • Prose. Les deux README portent désormais une note de correction : la ligne max-vix mesurée reste celle du chemin composé jusqu'à re-mesure, et un backtest de contrôle sur le code corrigé la remplacera — en priorité sur 2019-2022, la sous-fenêtre que la revue désigne comme celle où la composition mord le plus. Le contrôle est enregistré et partira dès que le nœud QC Cloud se libère (nœud unique, l'ablation max-only occupe la file — règle séquentielle du cluster).
  • Périmètre du bug, précisé. Le rescale ne vit que dans le chemin max-vix d'OnData : les modes max-only (levier fixe 1,0× — return avant le rescale) et spy (pas d'overlay) ne l'atteignent jamais. L'ablation 3158bd54… en vol mesure donc bien le facteur seul, non contaminée ; la ligne spy non plus. Seule la ligne max-vix du tableau est à re-mesurer.

Réserve 2 (les « 4 199 séances » sont des jours calendaires) — déjà résolue à la tête actuelle au moment de la review. La revue a été rendue sur l'extraction du head 9faa204a (commit 1/3) ; les commits suivants (8f434ec069, 0930b355ed, poussés avant la review) ont réécrit ce passage : le README courant écrit « série journalière de 4 199 points, dont 2 847 jours de bourse effectifs pour le candidat » (l. 46) et consacre le paragraphe « Compteur de séances — mesuré, plus supposé » (l. 74) à l'écart 4 199 / 2 889 entre modes, avec la décomposition des deux compteurs. La divergence de libellé avec DynamicVIXSpyRegime-QC que la revue signale reste réelle côté voisin ; je ne touche pas à ce porteur dans cette PR (hors périmètre du grain).

Note selection_size. La prose (« décile inférieur, plafonné à 25 titres ») décrit la règle implémentée min(25, N//10) ; la question posée — le plafond a-t-il effectivement mordu — est une mesure, pas une formulation : le nombre de titres retenus à chaque rééquilibrage sera relevé dans les journaux du backtest de contrôle et rapporté avec ses chiffres.

Merci pour la review — la simulation de la boucle du head est ce qui distingue ce correctif d'un simple reformatage, et c'est elle qui a tranché.

🤖 Generated with Claude Code

…decomposition facteur vs overlay

Ablation 3158bd54 terminee : le facteur seul bat le candidat mesure
(0,288 vs 0,181) mais pas SPY (0,551) -- l'overlay mesure retire, la
part imputable au bug de composition attend le backtest de controle.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@jsboige

jsboige commented Oct 24, 2026

Copy link
Copy Markdown
Owner Author

Suite de ma réponse c.6384058725 — l'ablation promise est livrée au commit 19a4f717bf6 (même PR).

max-only terminé (backtest 3158bd546830303dc013f8763faf3b98, ~4 h sur nœud unique, complété ce 2026-10-24) : Sharpe 0,288 · CAGR 6,124 % · MaxDD 25,90 %, total +98,139 % (100 000 $ → 198 139,26 $), frais −5 113,93 $, 4 550 ordres / 21,42 M$.

Lecture (décomposition facteur vs overlay). Le facteur seul bat le candidat mesuré (0,288 contre 0,181 ; 6,12 % contre 5,40 % de CAGR) avec un drawdown quasi identique (25,90 % contre 26,40 %) — sur la fenêtre mesurée, l'overlay VIX a retiré de la performance au lieu d'en ajouter, sans acheter de réduction de drawdown. Deux réserves, toutes deux dans le README au même commit : (1) la ligne candidat mesure le chemin composé du bug de rescale — une part du retrait vient du bug, pas de l'overlay ; (2) l'écart de rotation (32 697 ordres contre 4 550) est aussi un artefact du rescale composé. Le facteur seul ne bat pas la référence non plus (0,288 contre 0,551) : l'absence d'edge n'est pas portée par le seul overlay.

Le backtest de contrôle annoncé est parti : d837ab0da23d2e7217a722c886eddf08, mode max-vix sur code corrigé (compile fa427c0c… BuildSuccess), fenêtre 2019-01-01 → 2022-12-31 — la sous-fenêtre que la revue désigne comme celle où la composition mord le plus. Il dira la part du retrait imputable au bug ; à complétion, la ligne max-vix du tableau sera remplacée ou bornée selon ses chiffres, avec le nombre de titres retenus par rééquilibrage (selection_size réel, relevé demandé par la revue).

🤖 Generated with Claude Code

@github-actions

Copy link
Copy Markdown
Contributor

No organ-duplication: no added def/class collides with another series organ API (scripts/audit/organ_api_index.yaml).

Detector: python scripts/audit/detect_organ_duplication.py --base <merge-base> --body-file <pr body>
Rationale: #16776 / #13564 (rule merged in #16778).

@github-actions github-actions Bot added the paragraph-length Paragraph > 2000 chars (wall-of-text, #15405). Resorb before merge. label Oct 24, 2026
…(0,255/6,03 %), decomposition chiffree

Le controle d837ab0da a couru sur le code corrige (denominateur = somme
des positions). Lance pour 2019-2022, il a en realite couvert la pleine
fenetre 2015-01 -> 2026-06 (dates codees en dur dans Initialize ; preuve
par courbe d'equite 2015-01-01 -> 2026-06-30 et arithmetique
CAGR/profit). C'est plus que la promesse : la ligne corrigee remplace la
ligne composee sur la fenetre entiere.

- README (FR/EN) : ligne max-vix corrigee 0,255 / 6,03 % / DD 27,00 % /
  frais -21 973,52 $ / 26 281 ordres ; ligne v6 relabellisee chemin
  compose (bug) ; bug chiffre : 0,074 Sharpe + 0,63 pp CAGR coutaient au
  candidat ; sur code sain l'overlay retire -0,033 Sharpe (0,255 contre
  0,288 a l'ablation), trois fois moins que la lecture composee ;
  sous-fenetres controlees (3,80 % / 8,58 % / 5,71 %) ; fait mesure non
  explique : le chemin corrige paie deux fois plus de frais que le
  compose, rapporte tel quel ; traces controle_equity.json et
  controle_results.json archivees GDrive.
- qc-strategies-status.md : statut decomposition livree, deux lignes
  candidat (v6 compose / corrige) + part du bug chiffree.

Verdict NO BEATS inchange, ne doit plus rien au bug.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@jsboige

jsboige commented Oct 24, 2026

Copy link
Copy Markdown
Owner Author

Contrôle livré — backtest d837ab0da23d2e7217a722c886eddf08 (commit b95b1e86a6e)

Le backtest de contrôle a tourné sur le code corrigé (dénominateur = somme des positions détenues). Il a complété le 2026-10-24 ; les chiffres ci-dessous sont ceux de read_backtest, la courbe d'équité est archivée.

La fenêtre réelle est plus large que demandé. Lancé pour la sous-fenêtre 2019-2022, il a en réalité couvert la pleine fenêtre 2015-01 → 2026-06 : les dates sont codées en dur dans Initialize et les paramètres ne peuvent pas les surcharger. Trois preuves concordantes : (1) sa courbe d'équité va du 2015-01-01 au 2026-06-30 ; (2) un CAGR de 6,026 % n'est arithmétiquement compatible du profit total 96,05 % que sur ~11,5 ans (sur 4 ans il aurait fallu +26 %) ; (3) SetStartDate(2015,1,1)/SetEndDate(2026,6,30) lus dans le source du projet. C'est donc mieux que la promesse : la ligne corrigée remplace la ligne composée sur la fenêtre entière, à périmètre égal avec l'ablation et la référence.

Sharpe (QC) CAGR MaxDD Total Frais Ordres
corrigé (contrôle) 0,255 6,03 % 27,00 % +96,05 % (→ 196 046,41 $) −21 973,52 $ 26 281 / 40,10 M$
v6 composé (bug) 0,181 5,40 % 26,40 % +83,16 % (→ 183 163,72 $) −10 524,36 $ 32 697 / 42,94 M$

La part du bug est chiffrée. Composer l'exposition coûtait au candidat 0,074 de Sharpe et 0,63 pp de CAGR (corrigé 0,255 / 6,03 % contre composé 0,181 / 5,40 %) — le chemin composé n'avantageait pas le candidat, il le pénalisait. Sur code sain, l'overlay retire −0,033 de Sharpe et −0,09 pp de CAGR à l'ablation (0,255 contre 0,288 ; 6,03 % contre 6,12 %) : l'overlay retire toujours, mais trois fois moins que la lecture composée (−0,107) ne le laissait croire. Les sous-fenêtres se redistribuent (CAGR 3,80 % · 8,58 % · 5,71 %) — 2019-2022 reste la meilleure, sans dominer autant.

Fait mesuré, rapporté sans interprétation : le chemin corrigé paie deux fois plus de frais que le chemin composé (−21 973,52 $ contre −10 524,36 $) pour moins d'ordres (26 281 contre 32 697) et un volume comparable (40,10 M$ contre 42,94 M$).

Verdict inchangé : NO BEATS — la référence détient 0,551 de Sharpe et 13,74 % de CAGR. Le verdict ne doit plus rien au bug.

Le commit b95b1e86a6e porte la ligne corrigée, le relabeling de la ligne v6, la décomposition chiffrée et les sous-fenêtres dans les deux README et dans docs/qc/qc-strategies-status.md. Traces archivées hors dépôt : G:\Mon Drive\MyIA\IA\QC-traces\22290-max-effect-vix\ (controle_equity.json, controle_results.json — la note du fichier documente l'écart nom/fenêtre).

🤖 Generated with Claude Code

@github-actions github-actions Bot added the variation-adjacency-deep-med Adjacence DEEP/MED hors LIGHT : §2 l'autorise si substance distincte (coordinateur) label Oct 24, 2026

@myia-ai-01 myia-ai-01 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[OVERRIDE] lane myia-ai-01:CoursIA -- approbation a la tete b95b1e8 et levee des remarques ci-dessous, verifiees a cette tete (lecture du diff et de la source, preuves citees).

  1. clusterManager-Myia, review 5637805582, 2026-10-24T09:45:53Z : Hermes CHANGES_REQUESTED: leverage rescale COMPOSES instead of applying (bloquant; README numbers describe the wrong path; asks control backtest 2019-2022); '4 199 seances' counts calendar days
    Verifie : Point 1 fixed at 7ba0ca6: main.py l.170-182 invested = sum(quantity*price) denominator with comment citing the review simulation; control backtest d837ab0d delivered and committed at b95b1e8 (corrected line Sharpe 0,255 / CAGR 6,03 % replacing the composed-path line, with bug-share decomposition 0,074 Sharpe). Point 2 fixed at 8f434ec/0930b355: README l.46 '4 199 points, dont 2 847 jours de bourse effectifs' + dedicated 'Compteur de seances' paragraph. The CHANGES_REQUESTED state itself is still unlifted (coordinator-only gesture).

@myia-ai-01
myia-ai-01 merged commit 6433a97 into main Oct 24, 2026
40 of 44 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

paragraph-length Paragraph > 2000 chars (wall-of-text, #15405). Resorb before merge. variation-adjacency-deep-med Adjacence DEEP/MED hors LIGHT : §2 l'autorise si substance distincte (coordinateur)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants