Skip to content

feat(qc,#19740): MomentumRegime composite measured NO BEATS, sleeves now added - #19758

Merged
myia-ai-01 merged 1 commit into
mainfrom
feature/19740-momentumregime-measure
Oct 8, 2026
Merged

myia-ai-01 merged 1 commit into
mainfrom
feature/19740-momentumregime-measure

Conversation

@jsboige

@jsboige jsboige commented Oct 7, 2026 •

Copy link
Copy Markdown
Owner

Grain: DEEP/qc — lane myia-po-2024:CoursIA-3 — prev: MED/docs #19710

Closes #19740

Résumé

Framework_Composite_MomentumRegime était classé Edge au registre des stratégies. Mesuré selon le protocole préinscrit de #19740, il est NO BEATS contre SPY détenu et contre le 60/40, dans sa version d'origine comme dans sa version corrigée.

La mesure révèle aussi un défaut de construction. Le composite annonçait l'addition de deux tranches (SectorMomentum 60 %, RegimeSwitching 40 %), mais SectorMomentum n'a jamais tradé.

  • Cause. Le PortfolioConstructionModel de Lean ne garde qu'un insight actif par symbole avant d'appeler determine_target_percent. RegimeSwitching, ajouté en second, écrase SectorMomentum sur SPY, IEF et GLD, et l'univers de SectorMomentum est entièrement inclus dans le sien.
  • Mesure. Les insights SectorMomentum atteignent le modèle dans 0 des 403 appels.
  • Effet. Le composite valait RegimeSwitching à 40 % plus 60 % de liquide :
    • exposition brute moyenne 0,40 ;
    • corrélation hebdomadaire avec rs 1,00 ;
    • écart de Sharpe avec rs +0,001 [−0,012 ; +0,016].

Ce que change la PR

Fichier Changement
portfolio_construction.py paramètre additive : reconstruit les cibles à partir de l'insight actif le plus récent par couple (symbole, alpha), puis les somme par symbole ; compteurs de diagnostic ; caveat dans le docstring
main.py paramètre mode (intent par défaut, base = code d'origine, sm/rs = une alpha seule, spy/sixty40 = références détenues) ; start/end, sm_weights, rs_lookback, allocations, fee_mult ; graphique shadow (#18923) ; statistiques d'exécution
alpha_models.py lookback_weights et momentum_lookback passés en paramètres, valeurs par défaut inchangées
README.md, README.en.md section « Mesure #19740 », chiffres antérieurs conservés avec lecture corrigée, table des paramètres
docs/qc/qc-strategies-status.md ligne de la tranche 16 : Edge → NO BEATS ; ligne d'inventaire ; annotation de la ligne de synthèse tranche 16

Mesure

QC Cloud, 2015-01-02 → 2026-07-09 (2894 séances), frais Interactive Brokers. Sharpe à taux sans risque nul, sur la valeur du portefeuille à chaque clôture.

Version Sharpe CAGR Pire baisse Rotation / an Exposition brute
intent (défaut) 0,83 10,6 % −24,4 % 7,8 1,00
base (code d'origine) 0,90 5,0 % −11,5 % 3,8 0,40
sm seul 0,63 8,9 % −24,9 % 6,7 1,00
rs seul 0,90 12,5 % −27,5 % 9,5 1,00
SPY détenu 0,83 13,8 % −33,7 % 0,09 1,00
60/40 0,88 8,9 % −21,1 % 0,29 1,00

Verdict (bootstrap circulaire par blocs de 21 séances, 10 000 tirages, graine 18921, Holm sur deux références) :

Candidate Écart vs SPY [IC 95 %] Écart vs 60/40 [IC 95 %] p Holm Sous-périodes positives
intent −0,00 [−0,47 ; +0,43] −0,05 [−0,50 ; +0,37] 1,00 1/3 et 1/3
base +0,08 [−0,29 ; +0,41] +0,02 [−0,36 ; +0,38] 0,72 1/3 et 1/3

NO BEATS pour les deux. La grille et les frais doublés n'étaient prévus que pour une candidate à p Holm < 0,05 : non lancés.

Apport des tranches sous intent (descriptif, hors Holm) :

  • intent − sm : +0,20 [−0,03 ; +0,43] ;
  • intent − rs : −0,08 [−0,46 ; +0,29].

Choix du défaut. intent rend le projet conforme à sa description (docstring de MultiStrategyPCM). Il ne crée aucun avantage mesuré : son Sharpe (0,83) est inférieur à celui de base (0,90). base reste sélectionnable pour reproduire les chiffres antérieurs.

Écart au protocole : fin effective 2026-07-09

Les runs demandaient une fin au 2026-09-30. Ils ont tourné dans une organisation QC éducative sponsorisée, qui retient les 90 derniers jours (outOfSampleDays: 90) : la fin a été ramenée au 2026-07-09, sans erreur.

  • Tous les bras ont tourné dans la même organisation : 0 séance d'écart entre candidate et références (session_gap 0/0 partout).
  • Les trois derniers mois manquent à la fenêtre, pour toutes les versions également.

Chiffres antérieurs

  • README. Le run readme (base, 2015-01-01 → 2025-12-31) reproduit le tableau du README : Sharpe QC 0,21 contre 0,185, CAGR 4,72 % contre 4,728 %, pire baisse 11,5 %, 522 ordres contre 520. Ce tableau mesurait donc RegimeSwitching à 40 % plus du liquide. La piste « T80/RS20 » n'avait pas d'objet : sous base, les parts ne changent que la part de liquide.
  • Registre (« Edge », projet 28871239 : Sharpe QC 0,145, PSR 73,52 %, 183 ordres). Ce résultat n'est pas reproduit : le run oos (base, 2023-01-01 → 2026-05-01, 834 séances) donne Sharpe QC 0,133, PSR 2,5 %, 136 ordres. Hypothèse non vérifiée : autre version du code.
  • Narratif de la tranche 16. Les blocs datés (lignes ~422-432 et ~570 du registre) sont laissés intacts comme historique ; la ligne de synthèse de la tranche est annotée.

Limites

  • Pas de période hors échantillon. IEF a remplacé TLT en connaissant 2015-2026 (commentaire de alpha_models.py). Ce biais favorise la candidate, ce qui renforce le NO BEATS.
  • Compteur PCM calls with SM. Sous intent, il reste à 0 par construction : il compte les insights reçus par determine_target_percent, après l'écrasement. L'addition se lit dans l'exposition brute (1,00) et dans les ordres GLD (203 contre 111).

Composites voisins exposés au même mécanisme (non corrigés ici)

Revue des sources par un sous-agent, puis vérification par la lane. Le motif tient à trois conditions :

  1. plusieurs alphas dans un CompositeAlphaModel ;
  2. des tickers communs aux alphas ;
  3. un PCM qui groupe par source_model pour additionner des parts.

Aucun projet ne surcharge get_target_insights (grep -rn target_insights : 0 résultat).

Projet Verdict Preuve
Framework_Composite_EMATrend exposé, non mesuré 5 tickers communs (main.py:42 / 45-46), CompositeAlphaModel main.py:59-62, by_alpha portfolio_construction.py:23-30
MomentumRegime-AdaptiveWeights exposé, non mesuré univers identiques (main.py:37-38), by_alpha portfolio_construction.py:32-37
Framework_Composite_TrendWeather non exposé aucun ticker commun (main.py:32-39)
Framework_Composite_FamaFrenchAllWeather non exposé univers disjoints par conception (main.py:37, 40)
composite-c1-multiasset non exposé à ce défaut RiskParityPCM ne groupe pas par alpha (portfolio_construction.py:17-36)
composite-c2-equityfactor non exposé à ce défaut MeanVariancePCM ne groupe pas par alpha (portfolio_construction.py:18-55)
Portfolio-IBKR-Coinbase-Hybrid non concerné pas d'Alpha Framework, somme manuelle (main.py:411-447)

Les deux projets exposés sont suivis par #19759 (une mesure chacun) ; ils ne sont pas touchés ici.

Preuves

  • Projet de mesure. QC 37485593, empreintes sha256 (LF) : alpha_models.py 896d0843fcdd, main.py 83125b57687c, portfolio_construction.py 9658c87fcc4b. Les deux premiers fichiers committés sont identiques aux versions mesurées. Le main.py committé (b25f2790cdae) n'en diffère que par la valeur par défaut de mode et des commentaires ; chaque run passait mode explicitement.
  • Backtests :
    • base 207329fa ; intent 1612f3f3 ; sm 85558791 ; rs 92272158 ;
    • spy 952a6554 ; sixty40 ae609e39 ;
    • readme 5529dab9 ; oos 5135a4bd ;
    • essais courts trial 0b67e4ca et trial_intent ed9c5d98.
  • Traces et analyse (hors dépôt) : G:\Mon Drive\MyIA\IA\QC-traces\19740-momentumregime\ (plan.json, backtest.json, chart.json, backtest_raw.json par run ; results_base.json, results_intent.json).
  • Gardes : check_prose_quantitative_claims.py --diff → [OK]. Aucun notebook touché (quantbook.ipynb inchangé).

Verdict SOTA

SOTA-OK : backtests Lean sur QC Cloud, moteur et données natives, aucune sortie substituée.

🤖 Generated with Claude Code

…now added

Lean's PortfolioConstructionModel keeps one active insight per symbol before
determine_target_percent runs, so RegimeSwitching overwrote SectorMomentum on
SPY, IEF and GLD: the composite was RegimeSwitching at 40 % plus 60 % cash.
Mode intent (new default) rebuilds the targets per (symbol, alpha) and adds
them, as MultiStrategyPCM's docstring announces; base keeps the old code.

QC Cloud 2015-01-02 to 2026-07-09: base and intent are both NO BEATS against
SPY and 60/40 (p Holm 0.72 and 1.00). Registry status Edge corrected.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 7, 2026

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 commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Path-collision (organ #13359/#13615)

Cette PR #19758 (feat(qc,#19740): MomentumRegime composite measured NO BEATS, sleeves now added) touche au moins un chemin de fichier aussi modifie par d'autres PRs ouvertes. Risque de double-livraison (meme fichier livre deux fois, 2x le travail et 2x les runs CI). Advisory : parfois legitime (tranches coordonnees, partition paths: explicite, PRs empilees exclues) -- l'organe rend visible, il ne bloque pas.

@jsboige

jsboige commented Oct 7, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2025:CoursIA-2
pr: 19758
head: 6d822e5
complete: true
body: read
comments-reviewed: 2
reviews-reviewed: 0
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: f5d6d5f3ed8f5098f913852c884c7dc3ba91c81fa046563c6382a7014e8b3aec
diff-files: 6
diff-additions: 323
diff-deletions: 59
checks: latest-wins-green
b0: clear
scope: pass
domain: pass
verdict: READY
organ: check_adjoint_prevalidation.py
organ-command: python scripts/check_adjoint_prevalidation.py --derive-verdict 19758
organ-rc: 0
[/ADJOINT PREFLIGHT]

@jsboige

jsboige commented Oct 7, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2025:CoursIA-2
pr: 19758
head: 6d822e5
complete: true
body: read
comments-reviewed: 3
reviews-reviewed: 0
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: 9f0709c5c520372e949d4212219ac2ae81c11f03950886c8f6d2a33c9e654910
diff-files: 6
diff-additions: 323
diff-deletions: 59
checks: latest-wins-green
b0: clear
scope: pass
domain: not-applicable
verdict: READY
organ: check_adjoint_prevalidation.py
organ-command: python scripts/check_adjoint_prevalidation.py --derive-verdict 19758
organ-rc: 0
[/ADJOINT PREFLIGHT]

@myia-ai-01
myia-ai-01 merged commit 8207c65 into main Oct 8, 2026
38 of 45 checks passed
jsboige added a commit that referenced this pull request Oct 8, 2026
…d-composite

Un conflit, resolu en lisant les deux cotes : docs/qc/qc-strategies-status.md,
table des strategies composites. Chaque cote portait une annotation
differente sur une ligne differente -- ma branche « (NO BEATS, #19759) » sur
Framework_Composite_EMATrend, main « (NO BEATS, #19740) » sur
Framework_Composite_MomentumRegime (apportee par 8207c65, #19758).
Resolution = union des deux annotations, aucune information perdue.

Les catalogues generes sont restes byte-identiques a main (regle
catalog-pr-hygiene).

See #19759

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
myia-ai-01 pushed a commit that referenced this pull request Oct 8, 2026
…et_insights override (#19859)

Le defaut documente dans #19740 (mesure) et #19822 (cas pedagogique
QC-Py-14) : la methode de base PortfolioConstructionModel.get_target_insights
ne preserve que le DERNIER insight actif par symbole. Quand deux Alpha
Models emettent sur le meme symbole (EMA-Cross SPY=UP et TrendStocks
SPY=UP au meme rebalancement), le dernier emis efface l'autre avant
determine_target_percent, ce qui rend l'exemple "SPY: 13.33% (EMA) +
30% (Trend) = 43.33%" inatteignable (cf. mesures #19758, #19780).

Le fix ajoute un override get_target_insights dans MultiStrategyPCM qui
preserve TOUS les insights actifs groupes par symbole, ce qui permet
ensuite a determine_target_percent (override existant) de les regrouper
par source_model et d'additionner les tranches de capital allouees a
chaque Alpha.

La cellule d'interpretation (cell-235dfc3b) gagne une section
"Subtilite : addition inter-strategy != get_target_insights par defaut"
qui pose le diagnostic, documente la correction, et signale que la
validation necessite une execution QC Cloud (create_compile +
create_backtest via MCP qc-mcp ou Playwright ; cf. regle F).

See #19822, Part of #19740 (umbrella composites).

Co-authored-by: Claude Haiku 4.5 (1M context) <noreply@anthropic.com>
myia-ai-01 pushed a commit that referenced this pull request Oct 9, 2026
…aut, mesure NO BEATS (#19900)

* feat(qc,#19759): MomentumRegime-AdaptiveWeights -- PCM intent par defaut, mesure NO BEATS

Tranche 2 de #19759. Lean garde un seul insight actif par symbole avant
determine_target_percent : sous le code d'origine, SectorMomentum n'atteignait
jamais les cibles (0 appel sur 403) et le portefeuille valait RegimeSwitching
a 15 % plus 85 % de liquidites (exposition brute 0,15).

- mode `intent` (PCM de #19758, parts additionnees par titre), devenu le defaut
  selon les deux criteres preinscrits ;
- modes `base`, `sm`, `rs`, `spy`, `sixty40`, parametres start/end, parts,
  poids de retour, rs_lookback, fee_mult, graphique shadow et compteurs ;
- README FR/EN : mesure 2015-01 -> 2026-07, verdict NO BEATS pour `intent`
  (p Holm 0,83) et `base` (p Holm 0,75), ancienne analyse corrigee ;
- registre docs/qc/qc-strategies-status.md mis a jour.

See #19759

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

* docs(qc): distinguish pre-rebuild counters and unrounded differences

See #19759. Address Hermes R1/R2 without changing strategy code or measured series.

Co-Authored-By: Claude-Code <noreply@anthropic.com>

---------

Co-authored-by: Your <your.email@example.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[QC] Framework_Composite_MomentumRegime : mesurer « Edge » sous règle préinscrite ; l'agrégation des tranches de MultiStrategyPCM n'a pas lieu

2 participants