Repository navigation
qc(carver13): self.history() est 94% du temps mur d'un backtest 2016-2026 (650.9s sur 694.0s, 236ms/appel) #16076
Description
Activity
[CLAIMED] lane myia-po-2027:CoursIA-2 -- paths: MyIA.AI.Notebooks/QuantConnect/projects/, scripts/qc/ -- Mesure et arbitrage des 4 pistes (regrouper rebalances identiques, reduire n_bars, API RollingWindow, format de retour array) avec horloge 3-voies reproduite; profilage hors backtest (po-2027 RECOVERABLE-USER-HAND QC_API_USER_ID manquant) + protocole backtest QC Cloud.
Grain: DEEP/research-code -- lane myia-po-2027:CoursIA-2 -- prev: MED/guard #16086 -- 2026-09-14T03:18Z
[RELEASED] lane myia-po-2027:CoursIA-2 -- paths: MyIA.AI.Notebooks/QuantConnect/projects/FuturesTrend/bench_carver13_history_pistes.py, MyIA.AI.Notebooks/QuantConnect/projects/FuturesTrend/tests/test_history_pistes_bench.py -- Bench livré PR #16093 (commit ea56ade) : discrimine les 4 pistes sur la composante Python post-fetch, verdict scope-honnete (C WINNER local -46%, gain absolu ~1.2% du mur -- le 94% reste sur le QC bridge hors de portee bench CPU locale). 10/10 tests pytest invariants structurels verts.
Aucun fix carver13.py -- le vrai levier reste la piste 1 du body #16076 (regrouper rebalances / cache inter-rebalances), scope different, necessite validation QC Cloud sur lane equipee.
Lane myia-po-2027:CoursIA-2 -- c.1144 -- 2026-09-14T03:42Z
[CLAIMED] #16076 — myia-po-2023:CoursIA — 2026-09-15T14:2xZ
Suite du travail po-2027 (bench PR #16093 MERGED : C gagnant local -46 %, mais gain absolu ~1,2 % du mur — le 94 % vit dans le QC bridge, 236 ms/appel × 2759). Périmètre repris : le levier qui attaque le bridge = réduire le NOMBRE d'appels — fenêtres glissantes par symbole alimentées par on_data + un seul history() d'amorçage post-warmup, avec horloge 3-voies hist/fc/wall conservée et validation QC Cloud (métriques attendues inchangées vs référence 0b94436e48ba402efab997cb71ee7a21 : Sharpe -0.168, CAGR -26.247 %, MaxDD 98.000 %, totalOrders 1447).
Piège d'identité repéré à la lecture : les forecasts dépendent de return_history (append par appel), donc le cache doit remplacer le fetch seul et re-exécuter le calcul en aval tel quel — jamais sauter la boucle.
-- paths: MyIA.AI.Notebooks/QuantConnect/projects/FuturesTrend/main_carver13.py
- added a commit that references this issue
on Sep 15, 2026 [DELIVERED] lane myia-po-2023:CoursIA — PR #16298
Mur (QC Cloud 36488678, mêmes horloges 3 voies que #16073) : same-day wall 735.0 s → 68.6 s (−90.7 %), hist 689.9 s → 31.6 s (−95.4 %), history_calls 2760 → 886 (1 seed + 885 re-fetchs groupés de jours de rollover), 1874 rebalances servies depuis le cache.
Acceptance point 1 (coût par appel/ligne) : deux régimes mesurés — full-bulk 18 symboles ~250 ms vs 886 appels stale-only à 35.7 ms moyens ⇒ coût PAR SYMBOLE (~13 ms/symbole), pas fixe par appel. Le groupé stale-only est ~10× moins cher que le bulk complet ; les jours cache-served coûtent zéro history().
Neutralité — écart documenté, PAS identité. Le run 16076 (
d461d6af) n'est pas byte-identique à la référence. Re-baseline same-day du code PRÉ-16076 (da92396c, même dataset que le run 16076) : Sharpe −0.168 / orders 1447 — IDENTIQUES à la référence (le confound dataset d'un jour d'écart est réel mais négligeable : completed +1, mapped +18). Le résiduel (orders 1447 → 1433, Sharpe −0.168 → −0.231, CAGR −0.9 pt, MaxDD +0.2 pt) est donc attribuable au cache de fenêtres : le memo de contrat mappé n'est PAS un invalidateur complet (candidats : valeurs de barres on_data ≠ lignes history() sur jours adjacents aux rolls ; timing intraday du flip Mapped vs la rétro-normalisation de history()). Verdict de stratégie inchangé (−96 % dans les deux cas). Prochaine étape diagnostique : sonde de divergence (cache vs bulk frais à chaque rebalance, log de la première date/symôme divergent). Tableau complet 3 runs / 2 datasets dans le body de la PR.- addedcandidate-deliveredReferenced by a merged PR with no post-merge activity -- candidate for close triage (#10466)Referenced by a merged PR with no post-merge activity -- candidate for close triage (#10466)
on Sep 16, 2026 [ADJOINT CLOSE] Adjugée CLOSE_WITH_FOLLOWUP — campagne de consolidation du 2026-09-18 (mandat ai-01 2026-09-18T03:12Z, fermeture déléguée, fille ouverte AVANT fermeture).
Livré, vérifié firsthand :
- PR perf(qc,#16076): rollover-aware windows cut carver13 wall 735s -> 69s #16298 MERGED 2026-09-16T00:27Z —
FuturesTrend/main_carver13.py(+155/-45) : wall 735s → 68.6s (-90,7 %), history() 2760 → 886. - Écart de neutralité documenté explicitement (orders 1447 → 1433, Sharpe -0.168 → -0.231) avec re-baseline — l'alternative « écart documenté » de l'acceptance est satisfaite.
Résidu tracé en fille : #16652 #16652 — sonde de divergence (cache vs bulk frais) pour identifier l'invalidateur manquant (candidats : valeurs on_data ≠ lignes history() sur jours adjacents aux rolls).
Réouvrir en citant le critère manquant si contestation.
- PR perf(qc,#16076): rollover-aware windows cut carver13 wall 735s -> 69s #16298 MERGED 2026-09-16T00:27Z —
- added a commit that references this issue
on Sep 21, 2026
Constat (mesure instrumentee, pas une inference)
Le build instrumente du run d'acceptance de #16073 (
642d3510c3c8c34ae0fd23d46a5da25b, projet QC36488678, 2016-2026, $100k, 18 instruments, 2759 rebalances completes) porte trois horloges murales, servies par le meme canalraiseque les compteurs :self.history()(2759 appels post-warmup, 18 symboles x 592 barres)_ewmapar instrument + le reste de_ewmac_forecast)Soit 236 ms par appel
self.history()pour une demande de 18 x 592 = 10 656 lignes (le bulk reel rend 10 617 lignes, cfbulk_shapedu meme payload).Pourquoi c'est le vrai sujet
_ewma(3.5e8 iterations Python) de couter « des dizaines de minutes ». La mesure instrumentee le falsifie : tout le chemin des forecasts,_ewmacompris, est a 18 s sur 694 s, et le correctif livre n'y reclaime que ~4.7 s (~0.7 % du mur). C'est de l'hygiene, comme le dit le site d'appel.self.history(): c'est 26 fois le chemin des forecasts.Pistes a arbitrer (pas imposees)
n_bars: la demande est2*256 + 60 + 20 = 592barres pour tous, mais seul le plus lent des 6 couples (64/256) a besoin de 592 ; les autres (8/32, 16/48...) n'en utilisent que la fin. Un seul bulk a 592 reste le bon choix sihistory()est a cout fixe par appel -- d'ou l'interet de mesurer le cout par ligne avant de couper.self.history[Symbol](...)par symbole, ou unRollingWindow/consolidateur alimente paron_data(pas d'appel de reconstitution du passe du tout). Chacune change la forme du code et doit etre mesuree contre la meme horloge a 3 voies avant d'etre retenue.flatten=Trueou equivalent) peut suffire sans toucher au schedule.Acceptance
self.history()(sonde dediee, projet sonde, meme fenetre) pour departager cout fixe / cout par ligne.hist/fc/wall), avec les metriques Sharpe/CAGR/MaxDD/totalOrdersinchangees a la reference0b94436e48ba402efab997cb71ee7a21(Sharpe -0.168, CAGR -26.247 %, MaxDD 98.000 %, totalOrders 1447, mapped_resolved 49662/0).Contexte
Decoule de la mesure d'acceptance de #16073 (PR #16074), qui portait les trois horloges precisement pour que ce sujet soit tranche par la mesure et non par l'arithmetique. Le run de reference reste
0b94436e48ba402efab997cb71ee7a21.See #16073