Skip to content

qc(carver13): self.history() est 94% du temps mur d'un backtest 2016-2026 (650.9s sur 694.0s, 236ms/appel) #16076

Description

@jsboige

Constat (mesure instrumentee, pas une inference)

Le build instrumente du run d'acceptance de #16073 (642d3510c3c8c34ae0fd23d46a5da25b, projet QC 36488678, 2016-2026, $100k, 18 instruments, 2759 rebalances completes) porte trois horloges murales, servies par le meme canal raise que les compteurs :

TIMING(16073): hist=650.9s fc=18.0s wall=694.0s
chemin secondes part des 694 s
self.history() (2759 appels post-warmup, 18 symboles x 592 barres) 650.9 93.8 %
chemin des forecasts EWMAC (12 _ewma par instrument + le reste de _ewmac_forecast) 18.0 2.6 %
tout le reste 25.1 3.6 %

Soit 236 ms par appel self.history() pour une demande de 18 x 592 = 10 656 lignes (le bulk reel rend 10 617 lignes, cf bulk_shape du meme payload).

Pourquoi c'est le vrai sujet

  • qc(carver13): _ewma coute O(barres) par appel (~3,5e8 iterations Python par backtest 2016-2026) #16073 soupconnait _ewma (3.5e8 iterations Python) de couter « des dizaines de minutes ». La mesure instrumentee le falsifie : tout le chemin des forecasts, _ewma compris, 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.
  • Le mur est dans l'appel de donnees, pas dans le calcul. Tout gain de duree reel sur cette strategie passe par self.history() : c'est 26 fois le chemin des forecasts.

Pistes a arbitrer (pas imposees)

  1. Regrouper les rebalances qui ne changent rien : le schedule tire chaque jour ; si ni l'univers ni les forecasts n'ont de raison de bouger (week-ends, jours sans barre nouvelle pour un symbole), l'appel est repete a l'identique. Mesurer d'abord combien des 2759 appels rendent un bulk byte-identique au precedent.
  2. Reduire n_bars : la demande est 2*256 + 60 + 20 = 592 barres 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 si history() est a cout fixe par appel -- d'ou l'interet de mesurer le cout par ligne avant de couper.
  3. API alternative : self.history[Symbol](...) par symbole, ou un RollingWindow/consolidateur alimente par on_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.
  4. Le format de retour : si le cout est dans la construction du DataFrame pandas plutot que dans la lecture des donnees, un retour array (flatten=True ou equivalent) peut suffire sans toucher au schedule.

Acceptance

  • Mesurer le cout par appel et par ligne de self.history() (sonde dediee, projet sonde, meme fenetre) pour departager cout fixe / cout par ligne.
  • Une implementation qui reduit le mur total mesure par la meme horloge a 3 voies (hist/fc/wall), avec les metriques Sharpe/CAGR/MaxDD/totalOrders inchangees a la reference 0b94436e48ba402efab997cb71ee7a21 (Sharpe -0.168, CAGR -26.247 %, MaxDD 98.000 %, totalOrders 1447, mapped_resolved 49662/0).
  • Neutrite demontree au meme standard que qc(carver13): _ewma coute O(barres) par appel (~3,5e8 iterations Python par backtest 2016-2026) #16073 : identite par construction, ou ecart documente et assume avec re-baseline explicite.

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

Activity

  1. jsboige commented on Sep 14, 2026

    @jsboige
    OwnerAuthor

    [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

  2. jsboige commented on Sep 14, 2026

    @jsboige
    OwnerAuthor

    [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

  3. added 2 commits that reference this issue on Sep 14, 2026
  4. jsboige commented on Sep 15, 2026

    @jsboige
    OwnerAuthor

    [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

  5. added a commit that references this issue on Sep 15, 2026
  6. jsboige commented on Sep 15, 2026

    @jsboige
    OwnerAuthor

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

  7. added 3 commits that reference this issue on Sep 15, 2026
  8. added
    candidate-deliveredReferenced by a merged PR with no post-merge activity -- candidate for close triage (#10466)
    on Sep 16, 2026
  9. jsboige commented on Sep 18, 2026

    @jsboige
    OwnerAuthor

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

  10. added a commit that references this issue on Sep 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    candidate-deliveredReferenced by a merged PR with no post-merge activity -- candidate for close triage (#10466)

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions