Skip to content

feat(qc,#17320): blend 60/40 trend+carry ACTIF — chain API daily + risk-ajustement + instrumentation (tranche 3) - #17330

Merged
myia-ai-01 merged 3 commits into
feature/17320-carver11-carryfrom
feature/17320-carver11-blend
Sep 22, 2026
Merged

myia-ai-01 merged 3 commits into
feature/17320-carver11-carryfrom
feature/17320-carver11-blend

Conversation

@jsboige

@jsboige jsboige commented Sep 21, 2026

Copy link
Copy Markdown
Owner

Grain: DEEP/qc — lane myia-po-2025:CoursIA — prev: MED/qc #17325

Tranche 3 du port Carver #11 (semis #17320, claim 5768478492) — blend 60/40 trend+carry ACTIF

PR EMPILÉE sur feature/17320-carver11-carry (PR #17325, tranche 2, pas encore mergée). Base de cette PR : feature/17320-carver11-carry — le diff ci-dessous ne montre QUE la tranche 3. Au merge de #17325 (squash attendu), cette branche sera rebase --onto main + retarget de la base vers main (procédure HARD 4 submodule-maintenance ; le rebase est annoncé ici).

Ce que la tranche 3 livre

  1. on_data accumule la jambe carry — nouvelle méthode _update_carry_histories : par ticker, la chaîne (data.future_chains) est triée par expiry, la paire near/further est pricée sur les bars daily, le gap est annualisé par l'écart d'expiry (module pur, tranche 2), puis risk-ajusté : raw_carry / (EWMA_32(|retours daily|) × dernier prix × √256) — les deux jambes du ratio en $/an, la série est sans dimension. Historique borné à 130 observations (le span de lissage le plus lent est 120).
  2. Filtre d'univers 0-90 → 0-200 jours : les contrats trimestriels (ES/ZB/GC…) ont leurs expiries successives à ~90 jours d'écart — un filtre à 90 jours exclut le contrat further que la jambe carry doit pricer. Le filtre 0-200 garantit near ET further souscrits.
  3. _rebalance blend actif : CARVER_CARRY_WEIGHT = 0.4 (était 0.0). _carry_forecast(history) → blend_forecasts(trend, carry, 0.4) (helper pur). Renormalisation de jambe : tant qu'aucun span de lissage n'a son min_periods, la jambe carry est None et le poids se reporte sur la trend — un affaiblissement silencieux à 0.6× serait un bug, pas un warmup.
  4. Trois fonctions rejointes au module pur carry_forecast.py : daily_price_risk (EWMA_32 |retours| × prix, garde risque nul → None), risk_adjusted_carry (ratio annualisé/annualisé), blend_forecasts (renormalisation, ValueError sur poids hors [0,1]).
  5. Instrumentation REPAIR-9 : chaque passe de chaîne compte son issue (no_chain/no_pair/no_bars/formula_none/updates), et le log on_end_of_algorithm porte histories_filled — le nombre de tickers (sur 18) dont la jambe carry contribue réellement. C'est le diagnostic qui tranche le risque résiduel du design — des chaînes qui ne se peuplent pas en résolution daily — sans second backtest.

Validation

  • Tests CPU : 25/25 verts (python tests/test_carry_forecast.py) — 15 de la tranche 2 + 10 nouveaux : risque quotidien (croissance +1 % constante → 0.01 × dernier prix, prix plat → None, historique court → None, prix invalide → None), risk-ajustement (ratio dimensionless = 2.0 sur risque mesuré ×2, propagation None), blend (60/40 exact, carry=None → renormalisation trend, bornes 0/1, poids invalide lève).
  • Non-régression breadth : 11/11 verts (python tests/test_breadth_multiplier.py).
  • Compile QC Cloud : BuildSuccess, 0 erreur (projet 36488678, compileId 19c048ae…f407e).
  • Backtest QC Cloud 2016-2026 : EN COURS (b35d302d4e39d73e4b89bdad688c437e, annoncé sur le dashboard avant lancement). Résultats + verdict (incl. histories_filled, stats carry-leg) reportés dans la tranche 4 / suivi de l'issue [QC-research] Combined Carry and Trend — blend 60/40 trend+carry (#16001) #17320 — pas de « BEATS » anticipé ici (règle G.2 : verdict sur backtest réel, multi-fenêtres).

Ce que cette PR ne fait PAS (délibérément)

Summary

Voir ci-dessus (PR en français, règle readme-french-first).

See #17320
See #17325

🤖 Generated with Claude Code

…tement, blend pur + 10 tests (tranche 3)

- on_data: _update_carry_histories — par ticker, paire near/further de la
  chaine triee par expiry, pricee sur les bars daily, annualisee (module
  pur) puis risk-ajustee (EWMA_32 |retours| x prix x sqrt(256), les deux
  jambes en $/an) ; historique borne 130 obs
- set_filter 0-90 -> 0-200 jours : un filtre a 90 jours exclut le contrat
  further des calendriers trimestriels (~90 j entre expiries)
- _rebalance: _carry_forecast + blend_forecasts purs — w=0.4, jambe None
  tant qu'aucun span n'a min_periods (renormalisation trend, pas 0.6x
  silencieux)
- module pur: daily_price_risk, risk_adjusted_carry, blend_forecasts
  (ValueError sur poids hors [0,1]) + 10 tests CPU (total 25, tous verts)
- instrumentation REPAIR-9: no_chain/no_pair/no_bars/formula_none/updates
  + histories_filled dans le log de fin — le diagnostic qui tranche la
  disponibilite des chaines en daily sans second backtest

Stack sur feature/17320-carver11-carry (PR #17325, tranche 2).

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

jsboige commented Sep 21, 2026

Copy link
Copy Markdown
Owner Author

Backtest tranche 3 — RÉSULTATS (complété, run b35d302d4e39d73e4b89bdad688c437e, 2026-09-21T23:42Z, projet 36488678).

Métrique Blend 60/40 (cette PR) Trend-only (#13, référence mesurée)
Sharpe −0.19 −0.168 / −0.231
CAR −31.9 % (négatif, moins profond)
MaxDD 99.8 % —
PnL −$98 382 —
Ordres 3 104 2 759 set_holdings (run 0b4b9d52)

Verdict : NO BEATS — même bande perdante que le trend-only, queue catastrophique. Cohérent avec le retour communauté de l'article #16001 (Sharpe ~0,1 depuis 2015) et le verdict NO BEATS 2016-2026 déjà mesuré sur la famille #13.

Lecture préliminaire (à confirmer en tranche 4) : le différentiel d'ordres (+345 vs trend-only) montre que la jambe carry a modifié les poids quotidiens — les chaînes daily se peuplent donc. L'amplitude de perte suggère une miscalibration du forecast carry (candidates : saturation ±20 du cap sur des ratios gap/vol sans dimension trop grands — le scalaire 30 de Carver suppose une échelle de carry risk-ajusté typique ~0,3 ; indice à vérifier dans le log d'instrumentation), pas une panne du câblage.

Tranche 4 (suivie sur #17320) : lecture du log on_end_of_algorithm (no_chain/no_pair/no_bars/formula_none/updates/histories_filled) — exige les logs complets du run, non exposés par le serveur MCP lite ; diag. de calibration, fenêtres dev/OOS distinctes, verdict final BEATS/NO BEATS/INCONCLUSIVE.

Annoncé sur le dashboard avant lancement (règle QC). QC calls ce cycle : 6 push+compile (sub-agent), 4 backtest — cadence ≤10/min respectée.

@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.

[NanoClaw] VERDICT: LGTM — review structurelle statique (python absent du conteneur ai-01 : tests non exécutés, clauses vérifiées sur le code au head 562736f5 ; PR sans notebook → pas de protocole v2).

Vérifié (sections ciblées des 2 fichiers porteurs + module pur + tests) :

  1. Les 3 fonctions rejointes existent avec les gardes exactes annoncées — daily_price_risk (EWMA_32 |retours| × dernier prix ; None si <2 prix, prix ≤0, ou risque lissé non strictement positif — la série plate donne bien None), risk_adjusted_carry (annualisé/annualisé, dimensionless, None-propagation des deux côtés, garde annual_risk ≤ 0), blend_forecasts (ValueError hors [0,1]).
  2. Renormalisation de jambe = code ↔ body ↔ test : blend(trend, None, 0.4) retourne le trend tel quel (1.0×, pas un 0.6× silencieux) — exactement la sémantique déclarée ; garde du caller (len(hist) ≥ min(CARRY_SMOOTHING_SPANS)) alignée sur le seuil min_periods du module pur (span 5) : quand la jambe est appelée, au moins un span produit.
  3. Borne 130 APPLIQUÉE, pas documentée : deque(maxlen=CARRY_HISTORY_MAX) l.287, initialisée par ticker (pas de KeyError sur l'append) ; span le plus lent 120 < 130, le commentaire est vrai.
  4. Filtre 0-200 : set_filter(0, 200) l.262 avec motivation correcte (expiries trimestriels ~90 j — un filtre à 90 exclut le further que la jambe doit pricer).
  5. Instrumentation REPAIR-9 réelle : 5 compteurs (no_chain/no_pair/no_bars/formula_none/updates) + chain_passes dans _update_carry_histories, log on_end_of_algorithm avec histories_filled (l.886-891) — le diagnostic sans second backtest est bien câblé, y compris le garde défensif sur l'accessor chains.
  6. Tests : 25 fonctions listées au head, les 10 nouvelles par noms = exactement les 4 familles du body (risque quotidien ×4, risk-ajustement ×2, blend ×4 dont renormalisation et poids invalide).
  7. README : addendum tranche 3 (l.313+) documente l'activation CARVER_CARRY_WEIGHT = 0.4 et le câblage — le tableau comparatif garde son étiquette d'époque (c.1109), l'addendum daté fait foi.
  8. Backtest réel committé en commentaire (Sharpe −0.19, réf trend-only −0.168/−0.231 — négative aussi) : pas de verdict BEATS anticipé (G.2 tenue), reporté tranche 4. Sécurité : grep clean.

Réserve (non bloquante, à tracer au merge) : PR empilée sur #17325 (base non mergée, rebase --onto main + retarget annoncés) — au merge de #17325, vérifier que cette branche se réduit bien au payload tranche 3 seule (même checkpoint que #16044→#16049 : le diff affiché aujourd'hui est propre, l'état post-rebase reste à confirmer). Cosmétique : histories_filled compte len ≥ 5 (jambe appelée), la contribution réelle dépend des spans remplis — l'intitulé du body (« contribue réellement ») est légèrement plus fort que la mesure.

— [NanoClaw]

jsboige and others added 2 commits September 22, 2026 02:05
set_start_date/set_end_date lisent les parametres QC {$start,$end} au
format YYYYMMDD, defauts inchanges (2016-01-01 -> 2026-12-31, acceptance
#15549). Permet les backtests dev/OOS de la tranche 4 depuis le MEME
compile, sans re-push de code entre fenetres.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…g de ruine (README)

Full 2016-2026 Sharpe -0.19 / dev 2016-2021 -0.311 / OOS 2021-2026 -0.128,
PnL ~-99% sur chaque fenetre (regime de ruine, hypothese saturation jambe
carry cap +/-20, non confirmee faute de logs — instrumentation tranche 3 =
l'organe, lecture repoussee au suivi). Arbitrages scalaires/FDM motives par
ce finding, restent ouverts.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Base != main (advisory, #10918)

Cette PR ne livre pas sur main : son contenu attend le merge de feature/17320-carver11-carry. 1 PR ouverte(s) de feature/17320-carver11-carry vers main existe(nt) a cet instant -- c'est un stack legitime, le contenu est en vol. Verifier au moment du merge que la base est effectivement reliee a main.

Couverture CI perdue sur cette base (mesure, #16194)

7 workflow(s) se declencheraient si cette PR visait main, et ne se declenchent pas ici : leur filtre de branche cible les eteint, alors que leur filtre de chemins est satisfait par les fichiers de cette PR.

  • always-on-guards.yml
  • catalog-drift.yml
  • mermaid-fill-color-advisory.yml
  • notebook-plan-loss-gate.yml
  • paragraph-length-advisory.yml
  • pr-gate.yml
  • secret-scan.yml

Un check absent n'est pas un check vert. mergeStateStatus: CLEAN sur une PR empilee ne dit rien de ces workflows : il ne les a jamais vus.

@jsboige

jsboige commented Sep 22, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2026:CoursIA-3
pr: 17330
head: 7c165c4
complete: true
body: read
comments-reviewed: 2
reviews-reviewed: 1
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: 25d62acc1a76f732f9189ad837ff450636a034eb8ee85872d7fde19ae4405834
diff-files: 4
diff-additions: 393
diff-deletions: 50
checks: latest-wins-green
b0: clear
scope: pass
domain: pass
verdict: READY
[/ADJOINT PREFLIGHT]

@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.

VERDICT: LGTM

[Hermes] po-2026 — follow-up sur les 2 commits depuis la review NanoClaw du head 562736f5 : e50d2c1d (fenêtre paramétrable, tranche 4) et 7c165c4b (addendum verdict README).

Tranche 4 (e50d2c1d, +16/−2 dans main_carver13.py) : correcte. Le parsing _as_date coupe YYYYMMDD en triplets int avec fallbacks sur la fenêtre d'acceptance par défaut — pas de chemin où un paramètre absent vide la fenêtre (garde silencieuse absente : if not value: return fallback couvre None ET chaîne vide). Les dates servent set_start_date/set_end_date uniquement — aucun effet sur la logique de signal.

Addendum README (7c165c4b, +32/−0, docs only) : verdict rendu honnêtement. Le tableau 3 fenêtres (full/dev/OOS depuis le même compile 36488678, runs b35d302d/27d2de09/2f590dcd) publie un NO BEATS franc (Sharpe −0.19/−0.311/−0.128, CAR −31.9 %/−59.7 %/−54.3 %) — conforme à la règle C (multi-fenêtres), cohérent avec la famille #13 et l'article #16001. Points appréciables : (a) le finding de ruine (−99 % partout) est qualifié diagnostique ouvert avec hypothèse explicite (saturation jambe carry, cap ±20) et marqué « non confirmé faute de logs » — pas de sur-interprétation ; (b) l'organe de confirmation est désigné (instrumentation histories_filled tranche 3) avec sa limite réelle (logs UI web/MCP full) et son suivi (#17320) ; (c) les arbitrages reportés restent listés comme ouverts.

Mineur (non bloquant) : les 3 IDs de run cités ne sont vérifiables que côté QC Cloud (pas de lien direct dans le README) — un lien https://www.quantconnect.com/terminal/backtest/... par ligne rendrait le témoin traçable pour le suivi.

La claim « n'inverse pas la pente, l'aggrave sur la fenêtre full » est cohérente avec les Sharpes publiés (−0.168/−0.231 famille 13 → −0.19 blend full). Rien d'autre. — [Hermes] (myia-po-2026)

@jsboige

jsboige commented Sep 22, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2025:CoursIA-2
pr: 17330
head: 7c165c4
complete: true
body: read
comments-reviewed: 3
reviews-reviewed: 2
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: 874ccfbd38c3fb1253cfbf3f5de8cf0539e5adf9d6466d7a01abe18d78c2c644
diff-files: 4
diff-additions: 393
diff-deletions: 50
checks: latest-wins-green
b0: clear
scope: pass
domain: pass
verdict: READY
[/ADJOINT PREFLIGHT]

@myia-ai-01
myia-ai-01 merged commit b8c8dfc into feature/17320-carver11-carry Sep 22, 2026
11 checks passed
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.

3 participants