Skip to content

QC Cloud-SectorRotation-Momentum : un rééquilibrage tombé sur une demi-séance passe tout en SHY (garde d'historique suspectée) #20286

Open

Description

@jsboige

Constat

En mesurant #20264 sur Cloud-SectorRotation-Momentum (backtests QC du 2026-10-10, fenêtre codée 2018-01-01 → 2025-01-01), un second motif est apparu dans les deux runs, avant et après le correctif de la tranche de minuit. Quand le compteur de 21 séances tombe sur une demi-séance (clôture américaine à 13:00, New York), la stratégie vend tout et passe à 100 % en SHY, alors que le marché est en hausse franche.

Run Backtest Date (journal des ordres QC) Ordres
code de main (a492cda) a772737bfde57dad91cb64801eb0939c 2019-11-29 18:00Z (lendemain de Thanksgiving) QQQ, SPY, EFA, GLD vendus ; SHY acheté
code corrigé #20264 a8e7809afb021ce8b42e8b59d61e9e1b 2019-07-03 17:00Z (veille du 4 juillet) QQQ, SPY, EFA, GLD vendus ; SHY acheté

Aucun autre rééquilibrage de ces runs ne tombe sur une demi-séance. Les deux qui y tombent passent en défensif.

Pourquoi c'est un défaut et pas un signal

_go_defensive() ne se déclenche que si aucun des cinq titres n'est qualifié (prix au-dessus de la SMA200 et momentum 126 séances positif). Le 2019-07-03, SPY est loin au-dessus de sa SMA200 et son momentum 126 séances est nettement positif (point bas de fin décembre 2018). Quatre titres détenus sortent ensemble : la cause est donc commune à la tranche, pas propre à un titre.

Restent trois sorties de la boucle de qualification (main.py, lignes 65-82) qui ne dépendent pas du marché :

  1. symbol not in data ;
  2. history(...) vide, ou KeyError ;
  3. len(closes) < self.momentum_lookback.

Le garde de #20264 (data.bars.contains_key sur les cinq titres) est passé ce jour-là dans le run corrigé, donc des barres étaient présentes. Hypothèse à vérifier : sur une demi-séance, history([symbol], 126, Resolution.DAILY) rend 125 barres, et la garde de longueur écarte tous les titres. Rien n'est encore mesuré de l'intérieur de l'algorithme.

Protocole proposé

  1. Un backtest de diagnostic sur la fenêtre codée, qui journalise à chaque rééquilibrage len(closes), symbol in data, le prix et la SMA de chaque titre. Le lire aux deux dates ci-dessus.
  2. Si l'hypothèse 3 tient : correctif minimal (accepter len(closes) >= lookback - 1, ou demander lookback + 1 barres et prendre les 126 dernières), puis mesure avant/après sur le même modèle que QC : la tranche de minuit (avis de dividende) consomme le rééquilibrage de on_data en journalier — recensement #20264 (comptage des passages en SHY sur demi-séance, statistiques QC, pas de verdict de stratégie).
  3. Recenser les autres projets QC qui combinent une garde len(history) < N à un rééquilibrage pouvant tomber sur une demi-séance.

Portée

Distinct de #20264 (tranche de minuit sans barre) : ici la tranche porte des barres, à une heure de clôture anticipée. Trouvé en mesurant #20264, non corrigé dans sa PR pour garder un sujet par PR.

Traces des deux runs : G:\Mon Drive\MyIA\IA\QC-traces\20264-midnight-slice\Cloud-SectorRotation-Momentum\ (journaux d'ordres complets).

Activity

  1. added a commit that references this issue on Oct 11, 2026
  2. jsboige commented on Oct 11, 2026

    @jsboige
    OwnerAuthor

    [CLAIMED] lane myia-po-2024:CoursIA-3 -- backtest de diagnostic (longueur d'historique et présence des données à chaque rééquilibrage), puis correctif et mesure avant/après si l'hypothèse 3 tient. paths: MyIA.AI.Notebooks/QuantConnect/projects/Cloud-SectorRotation-Momentum/**

  3. jsboige commented on Oct 11, 2026

    @jsboige
    OwnerAuthor

    Pré-enregistrement (lane myia-po-2024:CoursIA-3). Écrit avant tout backtest, et suit les étapes 1 et 2 du protocole de l'issue.

    Code mesuré (sha256 de main.py, 12 caractères)

    Variante Empreinte Contenu
    avant 2a1ce95cac64 main à 68972f1. Backtest existant a8e7809afb021ce8b42e8b59d61e9e1b (projet 37630571), même empreinte : il n'est pas relancé.
    diag e3e61eebe939 avant avec des journaux en plus, logique de trading inchangée. Code de mesure seulement, il ne sera pas commité.
    fix f853395e1587 avant plus deux lignes : history(..., lookback + 5, ...), puis les 126 dernières clôtures. La garde de longueur ne bouge pas.

    Ce que journalise diag

    • Une ligne par titre à chaque rééquilibrage : présent ou non dans la tranche, prix et SMA200, longueur d'historique avec ses première et dernière dates, momentum. La sortie de boucle est nommée parmi les trois de l'issue.
    • Chaque jour, après le garde de minuit de QC : la tranche de minuit (avis de dividende) consomme le rééquilibrage de on_data en journalier — recensement #20264 : la longueur d'historique des cinq titres. La ligne est journalisée pour toute séance qui ne ferme pas à 16:00 (New York), et pour les dix premières séances pleines où un titre a moins de 126 barres.
    • Un résumé en fin de run.

    Exécution : nœuds de backtest QC, fenêtre codée 2018-01-01 → 2025-01-01, diag et fix en parallèle.

    Prédictions

    1. diag rend les mêmes ordres que avant (mêmes dates, mêmes titres). Sinon les journaux ont perturbé le run, et la lecture de diag ne vaut plus pour avant.

    2. L'hypothèse 3 tient si deux conditions sont réunies :

      • au rééquilibrage du 2019-07-03, les cinq titres sont dans la tranche, et ceux qui passent la SMA200 sortent tous sur len125 ;
      • les longueurs de 125 tombent sur les séances qui ne ferment pas à 16:00, et seulement sur elles.

      Elle est réfutée si la sortie du 2019-07-03 est nodata, empty ou key, ou si la longueur y vaut 126. Dans ce cas, pas de correctif dans cette PR : je publie la cause mesurée.

    3. Si elle tient, avec fix :

      • zéro passage en SHY sur un rééquilibrage de demi-séance ;
      • un calendrier de rééquilibrage identique à avant, puisque le compteur de 21 séances ne dépend pas des positions.

    Ce qui sera publié

    • Les lignes de diagnostic aux dates concernées, et le résumé de fin de run.
    • Le nombre de passages en SHY, en séparant demi-séances et séances pleines.
    • Sharpe, CAGR, pire baisse, ordres et frais de avant et de fix, avec les identifiants de backtest.

    Ces chiffres iront dans le README du projet (FR/EN). La ligne SectorRotation de docs/qc/qc-strategies-status.md prendra les chiffres de fix, puisque c'est le code qui serait sur main.

    Seuil fixé d'avance : si le Sharpe QC bouge d'au moins 0,05 entre avant et fix, je le signale dans le README. Pas de verdict de stratégie : c'est la correction d'un défaut, sur une fenêtre déjà vue. Le NO-BEATS de #20264 reste en l'état.

    Étape 3 (recensement) : un relevé des autres projets QC qui combinent une garde len(history) < N et un rééquilibrage pouvant tomber sur une demi-séance est en cours. Il sera publié avec le résultat. Les éventuels autres projets touchés restent hors de cette PR, un sujet par PR.

  4. jsboige commented on Oct 11, 2026

    @jsboige
    OwnerAuthor

    Résultat du premier tour, et pré-enregistrement du second (lane myia-po-2024:CoursIA-3). Les deux runs ont été lus à completed: true.

    Tour 1 : diag et fix (pré-enregistrement c.6105254259)

    Variante Backtest QC Ordres Sharpe Rééquilibrage du 2019-07-03
    avant (2a1ce95cac64) a8e7809afb021ce8b42e8b59d61e9e1b 309 0,224 100 % SHY
    diag (e3e61eebe939) 921283996fe873976fdd9e4adbb45dd5 309 0,224 100 % SHY
    fix (f853395e1587) 5bf8331b90febecf6032d057cd11b488 309 0,224 100 % SHY

    Prédiction 1 tenue : diag rend exactement les ordres de avant (309 ordres, même date, même titre, même quantité, aucune différence). Sa lecture vaut donc pour avant.

    Prédiction 2 : le mécanisme tient, le chiffre est réfuté.

    • Au rééquilibrage du 2019-07-03 13:00, les cinq titres sont dans la tranche et passent leur SMA200. Ils sortent tous sur la garde de longueur, mais avec 105 barres, pas 125 :
      QQQ:len105[2019-02-04 16:00..2019-07-03 13:00] SPY:len105[...] EFA:len105[...] GLD:len105[...] IWM:len105[...]
    • Sur la fenêtre, il y a 15 séances qui ne ferment pas à 16:00. Elles sont toutes courtes, avec 104 à 106 barres pour 126 demandées. Aucune séance pleine n'est courte (résumé de fin de run : non16h=15 court_non16h=15 court_16h=0).
    • L'historique d'une demi-séance commence environ un mois trop tard : le 2019-02-04 au lieu de début janvier. Il manque une vingtaine de barres, pas une.
    • La sortie 3 de l'issue est donc la bonne, et la cause est commune aux cinq titres, comme supposé. En revanche, « 125 barres » était faux : je ne l'avais pas mesuré.

    Prédiction 3 réfutée pour ce correctif.

    • fix demande 131 barres. Il en reçoit encore moins de 126 sur une demi-séance, et le run est identique à avant : mêmes 309 ordres, mêmes statistiques, même passage en SHY le 2019-07-03.
    • Le correctif pré-enregistré ne corrige rien. Il ne sera pas commité.
    • Pourquoi Lean raccourcit la requête un jour de clôture anticipée n'est pas établi ici. Seul l'effet est mesuré.

    L'autre rééquilibrage en SHY de cette période, le 2018-11-29 16:00, est un vrai signal : les cinq titres y sont sous leur SMA200 (ligne DIAG REB du même journal).

    Tour 2 : fix2, pré-enregistré avant le run

    Code : fix2 = avant + history(..., 2 * lookback, ...), puis les 126 dernières clôtures, sha256 7510c24e4f58. La garde de longueur ne bouge pas. Même fenêtre, nœuds QC.

    Prédictions

    1. Ordres identiques avant la demi-séance. Jusqu'au 2019-07-03 exclu, les ordres de fix2 sont identiques à ceux de avant (date, titre, quantité). Sur une séance pleine, les 126 dernières barres d'une requête de 252 sont les mêmes que celles d'une requête de 126.
    2. Pas de défensif à tort. Le 2019-07-03, fix2 ne passe pas en SHY : le journal porte REBALANCE: N assets, et aucun achat de SHY n'est daté d'une demi-séance.
    3. Même calendrier. Les 83 rééquilibrages tombent aux mêmes dates que dans avant.
    4. Écart de trajectoire, descriptif seulement. Après le 2019-07-03, les positions diffèrent : l'écart de trajectoire est publié tel quel.

    Si 1 ou 3 échoue, le correctif change autre chose que la demi-séance : il n'est pas commité, et je dirai ce qui a bougé. Seuil et absence de verdict de stratégie inchangés : un écart de Sharpe d'au moins 0,05 est signalé dans le README.

    Étape 3, recensement : ce que la mesure change

    Un relevé des projets QC qui combinent un history(N) et une garde de longueur avait été fait sous l'hypothèse « une barre de moins ». Il classait comme protégés les projets qui demandent N+5 ou N+10 barres, comme ceux qui gardent sur N*0.8.

    Avec un déficit mesuré de 16 à 17 %, ce classement ne tient plus. Une requête de N+5 ou N+10 barres est aussi exposée, comme l'a montré fix ici. Le relevé sera repris avec ce seuil et publié avec le résultat du tour 2. Les corrections éventuelles iront dans d'autres PRs.

  5. jsboige commented on Oct 11, 2026

    @jsboige
    OwnerAuthor

    Résultat du second tour (lane myia-po-2024:CoursIA-3), lu à completed: true. Pré-enregistrement : c.6105308987.

    Tour 2 : fix2 (sha256 7510c24e4f58)

    Variante Backtest QC Ordres Sharpe CAGR Pire baisse PSR
    avant (2a1ce95cac64) a8e7809afb021ce8b42e8b59d61e9e1b 309 0,224 6,84 % 27,6 % 0,64 %
    fix2 (7510c24e4f58) 5661dc625175652677c63daa90074862 307 0,196 6,29 % 27,6 % 0,50 %
    1. Tenue. Jusqu'au 2019-07-03 exclu, les 54 ordres de fix2 sont identiques à ceux de avant (date, titre, quantité).
    2. Tenue. Le 2019-07-03, le journal porte REBALANCE: 5 assets | Top: QQQ (29.2%) | Total mom: 97.00%. Aucun achat de SHY n'est daté d'une demi-séance. Les deux achats de SHY du run (2018-10-30 et 2022-07-05) tombent sur des séances pleines.
    3. Tenue. Les 83 rééquilibrages tombent aux mêmes dates que dans avant.
    4. Écart de trajectoire, descriptif. Les rendements annuels sont identiques, sauf 2019 (+7,1 % → +3,4 %) et un dixième en 2020-2021. En 2019, le passage en SHY à tort a fait mieux que la position investie : c'est un effet de trajectoire, pas une propriété de la règle. L'écart de Sharpe (−0,028) est sous le seuil de 0,05 fixé d'avance. Pas de verdict de stratégie : le NO-BEATS du README tient.

    Le correctif est donc commité (PR à suivre).

    Calendrier des demi-séances

    Sur 2018-2024, les 15 séances qui ne ferment pas à 16:00 sont les 3 juillet, les lendemains de Thanksgiving et les 24 décembre. Toutes rendent 104 à 106 barres pour 126 demandées. Aucune n'est la première séance d'un mois. Deux sont la dernière séance d'un mois : 2019-11-29 et 2024-11-29.

    Un rééquilibrage par date_rules.month_start ne tombe donc jamais sur une demi-séance sur cette fenêtre. Un calcul à date fixe en fin de mois, quotidien ou par compteur de séances (comme ici), peut y tomber.

    Recensement repris (lecture des lignes de requête et de garde, non exhaustif)

    Requête N, garde N, exposés comme ici si un calcul tombe sur une demi-séance (calendrier de chaque projet à vérifier) :

    • Cloud-VolTargeting main.py:76-77
    • SectorMomentum main.py:50-52 (252 barres)
    • Framework_Composite_MomentumRegime alpha_models.py:101-103
    • MomentumRegime-AdaptiveWeights alpha_models.py:101-103
    • composite-c2-equityfactor alpha_models.py:236-238
    • Sparse-Index-Tracking-QC main.py:265, 271-272 (316 barres)
    • ML-XGBoost main.py:176-179
    • ML-TextClassification main.py:123-126
    • FuturesTrend main.py:106-107 et 131-132 (contrats à terme : l'effet n'est mesuré que sur des actions US)

    Requête N+5, garde N, classée à tort comme protégée au premier relevé : FamaFrench main.py:76-77.

    Requête N+5, garde 0,8 N, rééquilibrage month_start : DualMomentum, Trend-Following, VolTarget-Momentum, RiskParity, GlobalMacro-Regime. Ces cinq projets ne sont pas exposés en pratique, puisqu'aucune demi-séance n'est un premier jour de mois. Le code reste fragile pour autant. Sur une demi-séance, environ 0,83 (N+5) barres passent la garde 0,8 N, puis iloc[-N] sort des bornes.

    Requête N+5, garde 0,8 N, calcul quotidien : MeanReversion main.py:69-70. La garde passe, mais l'usage de la série reste à vérifier.

    Pas repris à ce tour : MomentumStrategy, DualMomentumNoTLT, composite-c1-multiasset, Framework_Composite_FamaFrenchAllWeather, BlackLitterman, ForexCarry (marché des changes : l'effet n'y est pas établi), Paradox46, MultiHorizonMomentum676, la famille HAR-RV et Vol-* (gardes len >= 2).

    Ce relevé est une lecture du code, pas une mesure. Avant toute correction, chaque projet suivra le même protocole qu'ici : vérifier sur le backtest publié qu'un calcul tombe bien sur une demi-séance. Les corrections iront dans des PRs séparées. L'issue reste ouverte pour cela.

  6. jsboige commented on Oct 11, 2026

    @jsboige
    OwnerAuthor

    [CLAIMED-AMEND] lane myia-po-2024:CoursIA-3 -- paths: MyIA.AI.Notebooks/QuantConnect/projects/Cloud-SectorRotation-Momentum/, MyIA.AI.Notebooks/QuantConnect/projects/Framework_Composite_MomentumRegime/, MyIA.AI.Notebooks/QuantConnect/projects/MomentumRegime-AdaptiveWeights/**

  7. jsboige commented on Oct 11, 2026

    @jsboige
    OwnerAuthor

    Pré-enregistrement, suite du recensement c.6105344807 (lane myia-po-2024:CoursIA-3). Écrit avant tout backtest.

    Projets : Framework_Composite_MomentumRegime (MR) et MomentumRegime-AdaptiveWeights (AW). Les deux alpha_models.py portent le même code ; ils ne diffèrent que par les poids par défaut de SectorMomentumAlpha.

    Lecture du code (main à 68972f1a6b)

    • SectorMomentumAlpha._composite_momentum (l. 101-103) : history(symbol, 252), garde len < 252. Émission mensuelle, à la première tranche du mois. Aucune demi-séance n'est un premier jour de mois : je ne l'attends pas exposé.
    • RegimeSwitchingAlpha._apply_momentum (l. 230-231) : history(symbol, 68), garde len < 63. Il est appelé à la première tranche du mois et le jour d'un changement de régime vers bull, qui peut tomber n'importe quel jour. Si ce jour est une demi-séance, l'historique rendu serait d'environ 47 barres (c.6105308987 : environ 21 barres de moins), SPY et QQQ seraient écartés et _apply_momentum rendrait []. Comme _need_rebalance est déjà remis à faux, le passage en bull ne serait pas appliqué avant l'émission du mois suivant.

    Mesure : copies de diagnostic hors dépôt, sans changement de logique : compteur par alpha, heure de la tranche et longueur rendue ; une ligne de journal par appel court ou par tranche ni de 16:00 ni de minuit ; une ligne par jour de changement de régime ; une ligne DIAG RS LOST quand le calcul ne retient aucun titre. Mode intent (défaut), fenêtre codée de chaque source (MR 2015-2025, AW 2018-2024), un backtest par projet sur les nœuds QC.

    Fichier (sha256, 12 car.) main diag
    MR alpha_models.py 896d0843fcdd 889177bc2155
    MR main.py b25f2790cdae 55b57ba4a986
    AW alpha_models.py 16dfd8dfad78 25e7910ca0c6
    AW main.py 33169b0a9842 676f11e015d4

    Prédictions

    1. SectorMomentumAlpha : aucun appel d'historique sur une tranche de demi-séance (13:00, New York), dans les deux projets.
    2. RegimeSwitchingAlpha : un appel sur une demi-séance seulement un jour de changement de régime. S'il y en a au moins un : longueur sous 63 et ligne DIAG RS LOST le même jour.
    3. Sur les tranches de séance pleine (16:00), longueur égale à la demande (252 ou 68). Les tranches de minuit (QC : la tranche de minuit (avis de dividende) consomme le rééquilibrage de on_data en journalier — recensement #20264) sont publiées à titre descriptif.

    Règle de décision, fixée d'avance

    • Au moins une émission perdue, ou un appel court qui écarte un seul des deux titres (le partage 70/30 n'est alors plus choisi) : correctif identique à fix(qc,#20286): SectorRotation -- demi-seances, history() en double fenetre #20330 (demander le double, garder les N dernières barres), une PR pour les deux projets, mesurée orig contre fix sur les mêmes fenêtres. Si le Sharpe QC bouge d'au moins 5 centièmes, les lignes du README concernées sont signalées pour réécriture. Pas de verdict de stratégie : c'est la correction d'un défaut, sur des fenêtres déjà vues.
    • Aucun : pas de correctif. Je mets à jour le recensement ici, et les deux projets passent dans « non exposés en pratique ».
  8. jsboige commented on Oct 11, 2026

    @jsboige
    OwnerAuthor

    Résultat de la mesure MomentumRegime / AdaptiveWeights (lane myia-po-2024:CoursIA-3), lu à completed: true. Pré-enregistrement : c.6106934850.

    MR (2015-2025) AW (2018-2024)
    Projet QC (nœuds ESGF) / backtest 37661337 / 74feb0f69ecb 37661339 / c8759b64ecee
    Demi-séances dans la fenêtre 23 15
    Appels SectorMomentumAlpha : 16:00 / minuit / 13:00 36 / 360 / 0 32 / 304 / 0
    Appels RegimeSwitchingAlpha : 16:00 / minuit / 13:00 62 / 182 / 0 42 / 114 / 0
    Appels courts 0 0
    Changements de régime (vers bull) 72 (23), tous sur une tranche de 16:00 50 (16), tous sur une tranche de 16:00
    Lignes DIAG RS LOST 0 0

    Prédictions : 1 tenue (aucun appel de SectorMomentumAlpha sur une demi-séance). 2 tenue au sens strict, mais sans exemple : aucun changement de régime n'est tombé sur une demi-séance, donc aucun appel de RegimeSwitchingAlpha à 13:00. 3 tenue : toutes les longueurs rendues égalent la demande, à 16:00 comme à minuit.

    Décision (règle fixée d'avance) : aucune émission perdue, donc pas de correctif.

    Le chemin reste exposable. Un passage en bull un jour de demi-séance ferait perdre l'émission jusqu'au mois suivant. Sur ces fenêtres, c'était environ une chance sur cinq (MR : 23 passages en bull sur environ 2 760 séances, 23 demi-séances) et une sur sept (AW), et c'est resté sans exemple. Ces deux projets passent dans « exposables, non atteints sur les fenêtres publiées ». Le correctif de #20330 s'y transposerait tel quel le jour où l'un d'eux tourne sur une autre fenêtre.

    Descriptif, à verser à #20264 : la première tranche du mois est une tranche de minuit 120 mois sur 132 en MR (la tranche d'avis de dividende décrite en #20264). L'émission mensuelle de SectorMomentumAlpha y a donc lieu. MR passe 202 ordres sur 683 à minuit (heure de New York), AW 108 sur 362. Ce n'est pas le défaut de #20264 : les alphas lisent le dernier prix connu, les longueurs d'historique sont pleines, et l'ordre part à l'ouverture suivante comme depuis une tranche de 16:00. Je le note sans le qualifier davantage.

    Recensement, mis à jour

    Lecture des 17 appels d'historique pris en décision de trading, déléguée puis vérifiée ligne à ligne sur les cas qui changent la liste. Elle corrige c.6105344807 sur trois points.

    • Mesuré, défaut atteint : Cloud-SectorRotation-Momentum (compteur de 21 jours dans on_data) ; correctif en fix(qc,#20286): SectorRotation -- demi-seances, history() en double fenetre #20330.

    • Mesuré, non atteint : Framework_Composite_MomentumRegime, MomentumRegime-AdaptiveWeights (ci-dessus).

    • Exposés par la même mécanique (appel dans on_data, sur la tranche de 13:00), non mesurés :

      • Sparse-Index-Tracking-QC (main.py:254-257, compteur de 63 jours ; un appel court reporte le rééquilibrage au trimestre suivant, car le compteur a déjà avancé) ;
      • SectorMomentum (main.py:88-94, sortie quotidienne quand SPY passe sous sa SMA200 ; un appel court retarde la rotation défensive d'un jour, puisque la condition reste vraie le lendemain).
    • Appels depuis un événement planifié à 10:00 New York (after_market_open("SPY", 30)) :

      • MeanReversion et FuturesTrend tous les jours ;
      • ML-XGBoost et ML-TextClassification le lundi.

      Le défaut n'a été mesuré qu'à 13:00, sur la tranche de clôture d'une demi-séance. Qu'un appel à 10:00 le même jour rende aussi moins de barres n'est pas établi, et c'est la prochaine mesure. MeanReversion serait le cas le plus fin : sa garde (len < 0,8 N) rend un rendement nul au lieu d'écarter le titre, ce qui neutraliserait le filtre de force relative ce jour-là.

    • Corrigé, non exposés :

      • Cloud-VolTargeting (month_start, main.py:60-64) et composite-c2-equityfactor (garde de mois) étaient listés exposés en c.6105344807 à tort ;
      • de même FamaFrench et Framework_Composite_FamaFrenchAllWeather (garde de mois, marge de 5 barres).
      • Aucun projet n'utilise month_end.

    Traces : G:/Mon Drive/MyIA/IA/QC-traces/20286-half-session/regime/{mr-diag,aw-diag} (plan figé, backtest, ordres, journal).

  9. jsboige commented on Oct 11, 2026

    @jsboige
    OwnerAuthor

    Pré-enregistrement de la mesure suivante (lane myia-po-2024:CoursIA-3), écrit avant le backtest. Suite de c.6106980806.

    Question : un appel history(N, DAILY) fait depuis un événement planifié à 10:00 New York (after_market_open("SPY", 30)) un jour de demi-séance rend-il aussi moins de barres ? Le défaut n'a été mesuré qu'à 13:00, sur la tranche de clôture (c.6105308987). La réponse décide du sort de MeanReversion, FuturesTrend, ML-XGBoost et ML-TextClassification.

    Sonde : copie de diagnostic de MeanReversion/main.py hors dépôt (sha256 7851ba9c19ad sur main, 4717d4f9253e pour la sonde), sans changement de logique.

    • _get_3m_return est appelé chaque jour pour SPY ; la sonde compte la longueur rendue (history(68)), par type de séance lu dans les horaires de l'exchange (heure de clôture du jour) et par heure.
    • Elle journalise chaque appel d'une demi-séance et chaque appel court.
    • Les jours de demi-séance, elle ajoute un appel history(SPY, 126) pour comparer à la mesure de 13:00 (104 à 106 barres), avec la date de la première et de la dernière barre.

    Exécution : fenêtre codée de la source (2015-2024, 20 demi-séances), un backtest sur les nœuds QC.

    Prédiction : je ne prédis pas le sens, la cause du déficit n'étant pas établie.

    Règle de décision

    • Au moins une demi-séance où history(68) rend moins de 68 barres : les quatre projets planifiés passent dans « exposés, mécanique mesurée », et le correctif se traite projet par projet, une PR par projet ou par famille de code identique, chacune avec sa propre mesure orig contre fix. MeanReversion d'abord, puisqu'il appelle chaque jour.
    • 68 barres partout : les appels planifiés à 10:00 sortent de la liste des exposés, et le défaut est circonscrit aux appels faits sur la tranche de clôture d'une demi-séance.
  10. jsboige commented on Oct 11, 2026

    @jsboige
    OwnerAuthor

    Résultat de la mesure des appels planifiés à 10:00 (lane myia-po-2024:CoursIA-3), lu à completed: true. Pré-enregistrement : c.6106988782.

    Écart au protocole, déclaré : la sonde construite sur MeanReversion s'est arrêtée le 2018-09-11 sur une erreur sans rapport avec les demi-séances (voir plus bas), après 6 demi-séances sur 20. J'ai mesuré la question à part, avec une sonde minimale qui ne trade pas. Elle abonne SPY en journalier et appelle history(SPY, 68) puis history(SPY, 126) chaque jour à 10:00 New York (after_market_open("SPY", 30)). Le type de séance est lu dans les horaires de l'exchange. Fenêtre 2015-2025 (projet QC 37661550 sur les nœuds ESGF, backtest 539e7f21a22c, sha256 18b4ca9cae5e).

    Séance appels history(68) complets appels history(126) complets
    Demi-séance (clôture 13:00) 23 / 23 23 / 23
    Séance pleine 2 743 / 2 743 2 743 / 2 743

    Un jour de demi-séance à 10:00, la dernière barre rendue est celle de la veille, par exemple 2015-11-27 : de 2015-06-01 à 2015-11-25, 126 barres. Les 6 demi-séances vues par la sonde MeanReversion avant son arrêt donnent la même chose (68 et 126).

    Décision (règle fixée d'avance) : 68 barres partout. Les appels planifiés à 10:00 sortent de la liste des exposés : MeanReversion, FuturesTrend, ML-XGBoost, ML-TextClassification. Le défaut se limite aux appels faits sur la tranche de clôture d'une demi-séance, c'est-à-dire dans on_data ou dans un alpha Framework.

    Liste qui reste exposée :

    Hors sujet, trouvé en route : MeanReversion non modifié (main.py sha256 7851ba9c19ad) plante aussi sur QC Cloud le 2018-09-11 (projet 37661514, backtest 6bf412f10f48), IndexError sur iloc[-63]. XLC, introduit en juin 2018, n'a alors qu'entre 51 et 62 barres : assez pour passer la garde len < 0,8 N, pas assez pour l'indice. Issue séparée à suivre.

    Traces : G:/Mon Drive/MyIA/IA/QC-traces/20286-half-session/scheduled/{probe-10h,meanrev-10h,meanrev-orig}.

  11. jsboige commented on Oct 11, 2026

    @jsboige
    OwnerAuthor

    Pré-enregistrement, suite du recensement c.6106980806 (lane myia-po-2024:CoursIA-3). Écrit avant le backtest.

    Projet : SectorMomentum (archivé, plafond de Sharpe ~0,56). Le recensement le classe « exposé, non mesuré » : on_data appelle history(symbol, 252) sur la tranche de clôture, et la garde len < 252 rend None.

    Lecture du code (main à 59ac415638)

    • Rééquilibrage mensuel (l. 96-115) : trois appels à la première tranche du mois. Aucune demi-séance n'est un premier jour de mois : je ne l'attends pas exposé.
    • Sortie quotidienne (l. 88-94) : quand le livre tient SPY et que SPY clôture sous sa SMA200, deux appels (TLT, GLD). Si cette clôture est une demi-séance, l'historique rendu serait d'environ 231 barres. Les deux scores vaudraient None et la rotation défensive attendrait la tranche suivante, la condition restant vraie.

    Mesure : une copie de diagnostic hors dépôt, sans changement de logique.

    • Compteur des appels par heure de tranche, et une ligne de journal par appel court ou par appel hors 16:00 et minuit.
    • Une ligne DIAG EXIT-COND par tranche où la condition de sortie est vraie, avec un champ lost (score None).
    • Le compteur des tranches de 13:00, et l'heure de la tranche qui consomme le mois.

    Fenêtre codée 2015-01-01 → 2024-12-31, un backtest sur les nœuds QC. La copie ne change pas la logique : ses ordres sont ceux de main.

    Fichier (sha256, 12 car.) main diag
    main.py a29aca2975bd 02b15c0709d3

    Prédictions

    1. Rééquilibrage mensuel : aucun appel sur une tranche de 13:00.
    2. Sortie quotidienne : un appel à 13:00 seulement si la première clôture de SPY sous sa SMA200 tombe un jour de demi-séance. S'il y en a un, longueur sous 252 et lost=True le même jour.
    3. Sur les tranches de 16:00 et de minuit, longueur égale à 252.

    Règle de décision, fixée d'avance

    • Au moins une sortie perdue. Correctif identique à fix(qc,#20286): SectorRotation -- demi-seances, history() en double fenetre #20330 : demander le double, puis garder les 252 dernières barres. Une PR, mesurée orig contre fix sur la fenêtre codée. Si le Sharpe QC bouge d'au moins 5 centièmes, les lignes du README sont signalées pour réécriture. Pas de verdict de stratégie : le projet est archivé, et il s'agit de la correction d'un défaut.
    • Aucune. Pas de correctif. Le projet passe dans « exposable, non atteint sur la fenêtre publiée ».
  12. jsboige commented on Oct 11, 2026

    @jsboige
    OwnerAuthor

    Résultat de la mesure pré-enregistrée en c.6111047977 (lane myia-po-2024:CoursIA-3), sur SectorMomentum.

    Runs (nœuds QC, lus à completed: true, fenêtre codée 2015-01-01 → 2024-12-31) :

    • diag 02b15c0709d3, 95 ordres lus à la source sur 95, journal complet (162 lignes) ;
    • témoin, ajouté après le pré-enregistrement : main.py tel quel (a29aca2975bd), pour vérifier que la copie de diagnostic ne change pas les ordres. Résultat : mêmes 95 ordres (date, titre, quantité, type) et mêmes statistiques que la copie de diagnostic.

    Compteurs de la copie de diagnostic (ligne DIAG SUMMARY) :

    • appels history : 51 sur une tranche de 16:00, 327 sur une tranche de minuit, 0 sur une tranche de 13:00 ;
    • appels courts (moins de 252 barres) : 0 ;
    • tranches de 13:00 vues : 20 (les demi-séances de la fenêtre) ;
    • heure de la tranche qui consomme le mois : 16:00 pour 11 mois, minuit pour 109 mois.

    Prédictions

    1. Rééquilibrage mensuel : aucun appel sur une tranche de 13:00. Tenue.
    2. Sortie quotidienne : un appel à 13:00 seulement si la première clôture de SPY sous sa SMA200 tombe une demi-séance. La condition de sortie est vraie 9 fois sur la fenêtre (2015-08-20, 2015-11-12, 2015-12-11, 2018-10-11, 2018-12-04, 2019-05-31, 2022-01-21, 2022-02-11, 2023-10-25), toutes sur une tranche de 16:00, toutes lost=False. Le cas ne s'est pas présenté : tenue, sans avoir été mise à l'épreuve.
    3. Sur les tranches de 16:00 et de minuit, longueur 252. Tenue (0 appel court).

    Décision (règle fixée d'avance) : aucune sortie perdue, donc pas de correctif au titre de #20286. SectorMomentum passe dans « exposable, non atteint sur la fenêtre codée ». Il reste exposé : une sortie dont la première clôture sous la SMA200 tomberait une demi-séance serait retardée d'une séance.

    Hors de la question posée, deux constats descriptifs :

    • Le mois se consomme à minuit, 109 mois sur 120. C'est le mécanisme de QC : la tranche de minuit (avis de dividende) consomme le rééquilibrage de on_data en journalier — recensement #20264 : une tranche de minuit sans barre (vraisemblablement un avis de dividende : TLT distribue chaque mois ; non vérifié dans ce run) consomme la garde rebalance_month. 71 des 95 ordres sont émis à minuit (44 mois) et s'exécutent à l'ouverture du jour même ; les 24 autres sont émis à la clôture et s'exécutent à l'ouverture suivante. Les historiques lus à minuit sont pleins et s'arrêtent à la clôture précédente : pas de lecture du futur, un calendrier mélangé. SectorMomentum figure dans le tableau « possiblement touchés » de QC : la tranche de minuit (avis de dividende) consomme le rééquilibrage de on_data en journalier — recensement #20264 ; je l'y signale comme atteint. Un éventuel correctif se pré-enregistrera là, pas ici.
    • Le README ne décrit pas la fenêtre du code. Il annonce « 2015-2026 » : Sharpe 0,555, CAGR 13,0 %, pire baisse 22,8 %. Le code s'arrête au 2024-12-31 et donne, au témoin, Sharpe QC 0,275, CAGR 6,85 %, pire baisse 22,8 %. L'écart de Sharpe (0,555 contre 0,275) n'est pas expliqué par cette mesure : fenêtre plus longue, ou autre version du code, je ne l'ai pas vérifié. Je ne corrige rien ici : le projet est archivé et la question posée était autre.

    Traces hors dépôt : G:/Mon Drive/MyIA/IA/QC-traces/20286-half-session/sm-diag/ et sm-orig/ (plan avec empreintes, résultat brut, ordres, journal).

    Sparse-Index-Tracking-QC reste le dernier projet « exposé, non mesuré » du recensement.

  13. jsboige commented on Oct 12, 2026

    @jsboige
    OwnerAuthor

    Constat mesuré qui contredit une prémisse du recensement (lane myia-po-2024:CoursIA-3).

    Le recensement dit qu'aucune demi-séance n'est un premier jour de mois. C'est faux quand le 3 juillet tombe un lundi : ce jour-là est à la fois le premier jour de cotation de juillet et une demi-séance qui ferme à 13:00. Sur les fenêtres publiées, c'est le cas en 2017 et 2023, et la prochaine fois en 2028.

    Mesure (backtests du lot #20264, protocole c.6115262186, code de main sans modification) : aucune ligne de rééquilibrage ni aucun ordre ces mois-là.

    Projet Fenêtre Mois sans rééquilibrage
    MomentumStrategy 2015-2024 2017-07, 2023-07 (118 mois sur 120)
    FamaFrench 2018-2024 2023-07 (83 sur 84)
    FamaFrench 2015-2024 2017-07, 2023-07

    Les deux ont le motif « requête N+5, garde N » (MomentumStrategy/main.py:65-67, FamaFrench/main.py:76-78). Ils sortent ensuite sans écrire dans le journal quand il manque des scores (main.py:125-126 et :127-128). La cause, un historique trop court sur la tranche de 13:00, est déduite du code : aucune ligne de journal ne la montre directement.

    Le correctif de #20264 ajoute des projets à cette liste. En déplaçant la décision de la tranche de minuit vers la première barre du mois, il fait tomber le rééquilibrage de ces deux mois sur la demi-séance :

    Pour les cinq projets classés plus haut « requête N+5, garde 0,8 N, rééquilibrage month_start », l'argument « pas exposés en pratique » tombe aussi. Leur cas n'est pas mesuré ici : planifiés après l'ouverture, ils ne lisent peut-être pas l'historique sur la tranche de 13:00.

    Correctif à appliquer projet par projet, celui de #20330 : demander le double de barres, puis garder les N dernières. Je propose de commencer par MomentumStrategy et FamaFrench, avec le même protocole qu'ici : vérifier le trou sur le backtest publié, corriger, puis relancer.

  14. 6 remaining items

  15. jsboige commented on Oct 12, 2026

    @jsboige
    OwnerAuthor

    Résultat — SectorMomentum, lane myia-po-2024:CoursIA-3. Mesure du pré-enregistrement c.6117521094. PR : #20444.

    Les quatre prédictions ont tenu.

    1. Les deux rééquilibrages manquants reviennent : [RISK ON] SPY=0.060 au 2017-07-03 13:00 et [RISK ON] SPY=0.104 au 2023-07-03 13:00. On les retrouve sur la fenêtre codée comme sur la fenêtre du README.
    2. Avant le 2017-07-03, les ordres sont identiques en multiensemble (date, titre, quantité) : 38 sur 38, sur les deux fenêtres. L'exception admise pour une sortie SMA200 n'a pas servi : les 11 sorties tombent aux mêmes dates avant et après.
    3. Les dates de rééquilibrage sont celles d'avant, plus les deux lundis, sans aucune perte. Le compte de mois rééquilibrés passe de 118 à 120 sur 120 pour la fenêtre codée, et de 137 à 139 sur 139 pour celle du README.
    4. Hors échantillon, les deux variantes sont identiques au centime : capital final, 6 ordres, frais, Sharpe 1,261.
    Fenêtre Sharpe CAGR Pire baisse Ordres Backtest fix
    codée 2015 → 2024 −0,096 → −0,081 0,53 → 0,78 % 38,2 % 111 → 112 a90623a7e25fe53321d26d9228d4a3a1
    hors échantillon 2025 → 2026-07-10 1,261 → 1,261 40,83 % 19,2 % 6 → 6 bbf4f63bc43a7e460835b39057542615
    README 2015 → 2026-07-10 0,157 → 0,169 5,26 → 5,49 % 38,2 % 118 → 119 c62cedc7e6b7a29582d9a3c6bb2fb933

    Le juillet 2017 rétabli n'envoie aucun ordre, car le livre est déjà en SPY. Le juillet 2023 rétabli achète du SPY le 3, à la clôture de 13:00. Sans le correctif, le livre restait en liquidités du 2023-06-01 au 2023-08-01. Ce mois en liquidités commençait par l'achat refusé du 2023-06-01 (#20388), et le défaut de demi-séance le prolongeait. Les achats refusés restent au même nombre : 10, 1 et 11. Les écarts de Sharpe (+0,015 et +0,012) restent sous le seuil de 0,05 : les chiffres de la section #20264 ne reçoivent pas de renvoi.

    Traces, hors dépôt : ordres, journaux complets et backtest_raw.json des trois runs, dans G:\Mon Drive\MyIA\IA\QC-traces\20286-half-session\SectorMomentum\. Les journaux des runs avant y sont aussi, relus à la source depuis les backtests de #20389.

    Projets traités pour ce défaut : SectorRotation (#20330, mergée), FamaFrench (#20411) et SectorMomentum (#20444). DualMomentumNoTLT suivra après le merge de #20407, qui touche le même fichier.

  16. added 2 commits that reference this issue on Oct 12, 2026
  17. jsboige commented on Oct 12, 2026

    @jsboige
    OwnerAuthor

    [CLAIMED] lane myia-po-2024:CoursIA-3 -- DualMomentumNoTLT : correctif demi-seances (meme forme que #20330/#20411/#20444), suite de #20407, mesure pre-enregistree avant backtest -- paths: MyIA.AI.Notebooks/QuantConnect/projects/DualMomentumNoTLT/**

  18. jsboige commented on Oct 12, 2026

    @jsboige
    OwnerAuthor

    Pré-enregistrement, DualMomentumNoTLT (lane myia-po-2024:CoursIA-3, suite de #20407). Écrit avant tout backtest.

    Pourquoi ce projet. Depuis #20407, la garde de mois de DualMomentumNoTLT ne consomme le mois que sur une tranche qui porte une barre. En juillet 2017 et en juillet 2023, cette tranche est la clôture de 13:00 du lundi 3 juillet, une demi-séance. Sur cette tranche, history() rend environ 21 barres de moins que demandé : la garde de longueur écarte les cinq titres, scores reste vide et le rééquilibrage sort sans rien faire. Le README de #20407 le déclare comme limite connue. Le journal du run « après » de #20407 le confirme : 118 lignes REBAL pour 120 mois, aucune en juillet 2017 ni en juillet 2023 (juin puis août).

    Code mesuré

    Exécution : nœuds de backtest QC, paramètres inchangés, un backtest par fenêtre, résultats lus à completed: true, ordres relus jusqu'au compte des statistiques, journaux lus en entier. Comparaison des ordres en multiensemble (date, titre, quantité) par séance : l'ordre de soumission dans une même séance varie d'un run à l'autre.

    Prédictions

    1. Les mois manquants reviennent : une ligne REBAL (ou ALL CASH) datée du 2017-07-03 et une du 2023-07-03 dans la fenêtre codée, soit 120 lignes au lieu de 118.
    2. Avant le 2017-07-03, les ordres sont identiques à avant. Il n'y a pas d'exception admise : le code n'agit que sur la première barre du mois, et aucune autre première barre de la fenêtre n'est une demi-séance.
    3. Les dates de rééquilibrage de fix sont celles d'avant, plus les deux lundis. Après juillet 2017, les quantités des ordres peuvent différer, puisque la valeur du portefeuille n'est plus la même.
    4. Hors échantillon, aucune première barre de mois n'est une demi-séance : fix est identique à avant au centime, ordres et statistiques.

    Ce qui sera publié : dans le README, le paragraphe « Limite connue » est remplacé par le résultat : mois rééquilibrés, Sharpe, CAGR, pire baisse, nombre d'ordres avant et après, et les identifiants de backtest. Les chiffres de la section #20264 ne sont pas réécrits. Si l'écart de Sharpe dépasse 0,05 sur la fenêtre codée, le paragraphe le dit. Si la prédiction 4 échoue, la règle hors échantillon de #20407 s'applique : pas de dégradation si ΔSharpe > −0,10, ΔCAGR > −0,5 pt et Δpire baisse < +1,0 pt.

    Pas de verdict de stratégie. C'est la correction d'un défaut, sur des fenêtres déjà vues.

  19. jsboige commented on Oct 12, 2026

    @jsboige
    OwnerAuthor

    Résultat, DualMomentumNoTLT (lane myia-po-2024:CoursIA-3) — PR #20509. Mesure du pré-enregistrement c.6131650205.

    Fenêtre Variante Mois rééquilibrés Sharpe CAGR Drawdown max Ordres Backtest
    codée 2015-2024 avant 118 / 120 0.441 9.955 % 21.4 % 234 b2ff070974e440f64029c69473bb7af7
    fix 120 / 120 0.446 10.049 % 21.4 % 239 a32a1a24f317c96e5d0fe2bbb00ca583
    hors échantillon 2025-01 → 2026-07-10 avant 19 / 19 1.203 30.233 % 14.0 % 42 bbf5126ce1eac446800cedc56c04f546
    fix 19 / 19 1.203 30.233 % 14.0 % 42 91eae7e7741ff46af96b5cd83dbccc5a

    Les quatre prédictions tiennent :

    1. Les lignes REBAL du 2017-07-03 13:00 et du 2023-07-03 13:00 reviennent, soit 120 au lieu de 118.
    2. Les ordres sont identiques avant le 2017-07-03, en multiensemble (date, titre, quantité).
    3. Les dates de rééquilibrage sont celles d'avant, plus les deux lundis, et aucune n'est perdue.
    4. Hors échantillon, ordres et statistiques sont identiques.

    Le 3 juillet 2023, le rééquilibrage vend GLD et passe sur QQQ et SPY un mois plus tôt. |ΔSharpe| = 0,005 sur la fenêtre codée.

    Pas de verdict de stratégie. La variante Framework (alpha_model.py) n'est ni touchée ni mesurée ; elle reste au recensement de #20264.

    Traces : G:\Mon Drive\MyIA\IA\QC-traces\20286-half-session\DualMomentumNoTLT\.

  20. jsboige commented on Oct 12, 2026

    @jsboige
    OwnerAuthor

    Pré-enregistrement, les cinq projets « requête N+5, garde 0,8 N, month_start » (lane myia-po-2024:CoursIA-3, suite du constat c.6115476132). Écrit avant tout backtest.

    Ce qui reste ouvert. Le constat c.6115476132 a montré que le lundi 3 juillet 2017 et le lundi 3 juillet 2023 sont à la fois le premier jour de cotation du mois et une demi-séance. L'argument « aucune demi-séance n'est un premier jour de mois » ne protège donc plus DualMomentum, Trend-Following, VolTarget-Momentum, RiskParity et GlobalMacro-Regime. Leur cas n'a pas été mesuré.

    Lecture du code (main à f35a009f20)

    • Les cinq rééquilibrent par schedule.on(date_rules.month_start("SPY"), time_rules.after_market_open("SPY", 30)), donc à 10:00 New York. Aucun n'appelle history() dans on_data.
    • La mesure c.6107023496 a montré qu'à 10:00, un jour de demi-séance, history(SPY, 68) et history(SPY, 126) sont complets (23 sur 23). La dernière barre rendue est celle de la veille. Elle n'a pas testé 252 + 5 barres.
    • Les cinq demandent N + 5 barres (N = 252, 126 ou 60), écartent un titre si len < 0,8 N, puis lisent iloc[-N]. Si l'appel de 10:00 rendait environ 21 barres de moins, comme à 13:00, la requête de 257 en rendrait environ 236. La garde passerait (236 ≥ 201,6) et iloc[-252] lèverait IndexError : le backtest s'arrêterait le 3 juillet.
    • Aucun titre des cinq univers n'est trop jeune sur ces fenêtres (pas de cas XLC comme QC MeanReversion : le code de main plante le 2018-09-11 (IndexError, XLC trop jeune) et le README décrit la v4.0 #20346).

    Code mesuré : main.py de main, sans modification. sha256 (12 premiers caractères) : DualMomentum 069d1fe98210, Trend-Following e6b44645daae, VolTarget-Momentum b0ba6f938f49, RiskParity c9ad7fb7ee8f, GlobalMacro-Regime 5d9634c91d7f. Fenêtres du code : 2015-2024 pour quatre projets, 2018-2025 pour GlobalMacro-Regime (seul le 3 juillet 2023 y tombe). Nœuds QC, un projet QC par stratégie.

    Prédictions

    1. Les cinq backtests vont à completed: true, sans erreur d'exécution.
    2. Chaque projet écrit sa ligne de rééquilibrage (Trending ( ou <régime> |) datée du 2017-07-03 10:00 (si la fenêtre le contient) et du 2023-07-03 10:00.
    3. Après le préchauffage, chaque mois de la fenêtre a sa ligne de rééquilibrage : aucun mois manquant.

    Règle de décision, fixée d'avance

    • Si les trois prédictions tiennent pour un projet, il sort de la liste des exposés : l'appel planifié à 10:00 lit des historiques complets, aussi à 257 barres. Pas de correctif. La fragilité de la garde 0,8 N devant iloc[-N] reste notée, mais elle ne relève pas des demi-séances.
    • Si l'une échoue, le projet entre dans la file des correctifs, avec la forme de fix(qc,#20286): SectorRotation -- demi-seances, history() en double fenetre #20330 et le protocole habituel : avant / après, ordres identiques avant la date en cause.

    Pas de verdict de stratégie : c'est une mesure de défaut. Traces : G:/Mon Drive/MyIA/IA/QC-traces/20286-half-session/five-10h/.

  21. jsboige commented on Oct 13, 2026

    @jsboige
    OwnerAuthor

    Résultat, les cinq projets « requête N+5, garde 0,8 N, month_start » (lane myia-po-2024:CoursIA-3). Mesure du pré-enregistrement c.6134914257. Runs sur les nœuds QC, lus à completed: true. Ordres relus à la source jusqu'au compte des statistiques, journaux complets.

    Projet Fenêtre Backtest Mois avec ligne de rééquilibrage Heure des lignes 2017-07-03 2023-07-03
    DualMomentum 2015-2024 58ef57b863442c637f9a3b10c5e7d33e 120 / 120 10:00 oui oui
    Trend-Following 2015-2024 930de8b78db29824dcf7ae7dbcf2ba0a 120 / 120 10:00 oui oui
    VolTarget-Momentum 2015-2024 2828bd66c72fb6571742ef54a5ddcc89 120 / 120 10:00 oui oui
    RiskParity 2015-2024 9c8c0eb18a43ab2113f9d9ae31575b3f 120 / 120 10:00 oui oui
    GlobalMacro-Regime 2018-2024 67938945c0c2b37b55d10935a76f0570 84 / 84 10:00 hors fenêtre oui

    Les trois prédictions tiennent, pour les cinq projets.

    1. Les cinq backtests vont à completed: true, sans erreur d'exécution. Un historique court de 21 barres aurait fait lever IndexError sur iloc[-252] le 3 juillet : il n'y en a pas.
    2. Chaque 3 juillet de la fenêtre porte sa ligne de rééquilibrage à 10:00, et les ordres de ces jours partent à 10:00 New York. Exemple, DualMomentum le 2017-07-03 : Trending (5/6): [EEM:21.2%, EFA:19.9%, SPY:17.6%, GLD:-8.1%, TLT:-9.0%. Ce sont des rendements à 12 mois calculés sur la série complète.
    3. Aucun mois manquant : 120 lignes sur 120 mois, 84 sur 84 pour GlobalMacro-Regime.

    Décision (règle fixée d'avance) : les cinq projets sortent de la liste des exposés, sans correctif. La mesure c.6107023496 tient donc aussi à 257 barres : un appel planifié à 10:00 un jour de demi-séance lit un historique complet, qui s'arrête à la clôture de la veille. Le défaut reste limité aux appels faits sur la tranche de clôture de 13:00, dans on_data ou dans un alpha Framework.

    La fragilité de la garde len < 0,8 N devant iloc[-N] demeure, mais elle relève des titres jeunes (le cas de #20346), pas des demi-séances. Aucun titre de ces cinq univers n'est dans ce cas sur ces fenêtres.

    Liste qui reste exposée :

    Hors sujet, trouvé en route (sans lien avec les demi-séances, pas traité ici) :

    • VolTarget-Momentum : 11 ordres refusés pour pouvoir d'achat insuffisant, de 2015-02-02 à 2023-12-01. Quand le multiplicateur de volatilité est à son plafond de 1,50, la somme des cibles atteint 150 % : le 2017-07-03, EEM 50 + EFA 40 + SPY 30 + GLD 20 + TLT 10, et les 2015-02-02, 2019-01-02 et 2023-12-01 aussi. Le 2017-07-03 ne compte pourtant aucun refus. Pourquoi seules ces 11 dates en ont, je ne l'ai pas établi : l'ordre d'envoi, achats avant ventes, est une hypothèse non vérifiée. Ces mois-là, une partie des ordres est refusée.
    • RiskParity : 1 ordre refusé, au premier rééquilibrage (2015-02-02).

    Ces deux constats appellent une issue séparée avant toute lecture des métriques publiées de ces projets.

    Traces : G:/Mon Drive/MyIA/IA/QC-traces/20286-half-session/five-10h/ (plan, backtest, ordres, journal, five_check.json).

  22. jsboige commented on Oct 13, 2026

    @jsboige
    OwnerAuthor

    [CLAIMED] lane myia-po-2024:CoursIA-3 -- Sparse-Index-Tracking-QC : backtest de diagnostic (heure et contenu de la tranche, longueur d'historique a chaque declenchement du compteur de 63 tranches), protocole pose ici avant les runs, puis correctif (historique double + compteur sur les seules tranches portant la barre de SPY, cf #20264) et mesure avant/apres -- paths: MyIA.AI.Notebooks/QuantConnect/projects/Sparse-Index-Tracking-QC/**

  23. jsboige commented on Oct 13, 2026

    @jsboige
    OwnerAuthor

    Protocole posé avant les runs — Sparse-Index-Tracking-QC

    Le rééquilibrage trimestriel se déclenche dans on_data quand un compteur de tranches vaut 1 modulo 63 (main.py:251-257). Deux défauts peuvent le toucher :

    Variantes (QC Cloud, nœuds de backtest sponsorisés, un projet par variante, empreinte du fichier vérifiée avant compilation)

    Variante Code
    avant main.py de main + journal seul, sans changement de comportement : TRIGGER (heure, présence de la barre SPY, nombre de dividendes, séances écoulées), HIST (lignes et colonnes de l'historique), compteur de reports, ligne finale SLICES
    fix compteur avancé seulement sur les tranches qui portent la barre de SPY ; historique demandé sur 2 × 316 barres, 316 dernières lignes gardées avant l'élimination des titres incomplets ; une ligne history par déclenchement ; compteur de reports dans la ligne de fin

    Chaque variante tourne en mode=sparse et mode=full : 4 backtests. Fenêtre unique, celle du code (2015-01-01 → 2026-08-31) ; la fin effective, ramenée vers J-90 sur les nœuds de backtest sponsorisés, est lue dans le résultat brut. Pas de fenêtre hors échantillon : le code couvre déjà toute la période jusqu'à sa date d'écriture. Ordres relus à la source jusqu'au nombre des statistiques, journal lu en entier, rien n'est lu avant completed: true.

    Prédictions

    1. avant : SLICES total > with_spy_bar (des tranches de minuit existent).
    2. avant : au moins un TRIGGER porte bar=0 (minuit), et l'écart moyen entre deux déclenchements, compté en séances, est inférieur à 63.
    3. avant : un déclenchement à 13:00 rend rows < 316 et un report ; un déclenchement à 16:00 ou à 00:00 rend rows = 316. Nombre de reports = nombre de déclenchements à 13:00. Si aucun ne tombe à 13:00, le défaut QC Cloud-SectorRotation-Momentum : un rééquilibrage tombé sur une demi-séance passe tout en SHY (garde d'historique suspectée) #20286 est latent pour ce projet sur cette fenêtre, et sera écrit tel quel.
    4. fix : chaque ligne history porte session ≡ 1 modulo 63 et rows = 316 ; aucun report ; sessions en fin de run = with_spy_bar de avant.
    5. Les deux variantes : assets = 41 à chaque déclenchement (aucun titre éliminé).
    6. Métriques : aucun signe attendu. L'écart dépend du marché aux dates déplacées. Ce que le correctif doit apporter, c'est un rééquilibrage tous les 63 jours de séance, comme le décrit le README.
  24. jsboige commented on Oct 13, 2026

    @jsboige
    OwnerAuthor

    Résultats du protocole pré-enregistré (c.6141122238)

    Quatre runs sur les nœuds de backtest sponsorisés, tous lus à completed: true, ordres relus à la source jusqu'au nombre des statistiques, journaux lus en entier. Fin effective relue dans le résultat brut : 2026-07-15 pour les quatre (le code demande 2026-08-31).

    Run Backtest Ordres Déclenchements Rééquilibrages Sautés Reportés
    avant, sparse f47ad143db11752e7ca117dd2f746fcf 687 65 62 2 1
    avant, full 5045a6592675037ab4e54a65fde1e33a 1386 65 50 14 1
    fix, sparse b41e290d2cd285ce13995aa04d3f7fbd 536 47 47 0 0
    fix, full 71ae29a8ba6de3e7ca3a76ccab3f117f 1222 47 43 4 0

    « Sautés » regroupe ce que _skipped compte déjà : sélection infaisable, filtre de poussière vide, validateur en échec, rotation sous la bande de non-transaction de 10 %. « Reportés » est le compteur ajouté : historique trop court au déclenchement.

    Prédictions

    1. Tranches de minuit : tenue. Ligne SLICES de l'avant : 4069 tranches au total, dont 2899 portent la barre de SPY. Les 1170 autres sont des tranches de minuit (avis de dividende).
    2. Trimestre raccourci : tenue. 21 des 65 déclenchements de l'avant tombent sur une tranche de minuit (bar=0), le premier dès le 2015-01-02 00:00. L'écart entre deux déclenchements, compté en séances, vaut 44,9 en moyenne (de 42 à 49), au lieu de 63.
    3. Historique de demi-séance : tenue. Un seul déclenchement tombe à 13:00 : le 2018-12-24, veille de Noël. history(316) y rend 261 lignes, et le rééquilibrage est reporté. Les 64 autres déclenchements, à 16:00 ou à 00:00, rendent 316 lignes. Reports = 1 = nombre de déclenchements à 13:00, dans les deux modes. Comme le compteur avait déjà avancé, ce trimestre était perdu, et le report n'apparaissait dans aucun compteur.
    4. Correctif : tenue. Les 47 lignes history portent session ≡ 1 modulo 63, toutes à 16:00, toutes à 316 lignes. Écart entre déclenchements : exactement 63 séances, 46 fois sur 46. Aucun report. Ligne de fin : sessions=2899, égal au with_spy_bar de l'avant.
    5. Univers complet : tenue. 41 colonnes (SPY et les 40 titres) à chaque déclenchement, avant comme après : aucun titre éliminé.
    6. Métriques, sans direction annoncée :
    Mode Sharpe Rendement annuel composé Pire baisse Gain net Ordres Frais
    sparse 0,635 -> 0,616 17,322 % -> 16,740 % 34,7 % -> 35,3 % 532,3 % -> 497,0 % 687 -> 536 -22 %
    full 0,712 -> 0,709 17,257 % -> 17,152 % 30,7 % -> 31,3 % 528,3 % -> 521,8 % 1386 -> 1222 -7 %

    La première différence d'ordres tombe dès le 2015-01-02. L'avant déclenche à 00:00, sur la tranche de dividende, et ses ordres MarketOnOpen sont remplis à l'ouverture du jour même. Le correctif déclenche à la clôture de la première séance, et ses ordres sont remplis le 2015-01-05. Ensuite, les dates de rééquilibrage n'ont plus rien en commun : 65 déclenchements contre 47.

    L'écart de métriques n'a pas de signe à retenir. Le classement entre les deux modes ne bouge pas : full garde le meilleur Sharpe et la pire baisse la plus faible. Moins de rééquilibrages veut dire moins d'ordres et moins de frais. Le correctif ne vise pas un meilleur rendement : il fait rééquilibrer tous les 63 jours de séance, comme le décrit le README, sans trimestre perdu.

    Ce qui reste

    • Les chiffres publiés du README (2026-09-01, fin 2026-08-31) viennent de runs distincts, sur une fenêtre plus longue : ils ne se comparent pas directement aux runs ci-dessus. Une paire de runs du correctif sur la fenêtre codée entière est en cours, pour mettre à jour ce tableau dans la PR.
    • Traces complètes (ordres, journaux, résultats bruts, empreintes des fichiers envoyés) : G:\Mon Drive\MyIA\IA\QC-traces\20286-sparse-index\.
    • La PR suit, avec ce relevé dans le README du projet.
  25. jsboige commented on Oct 13, 2026

    @jsboige
    OwnerAuthor

    Complément : fenêtre codée entière

    Les deux runs annoncés au point « Ce qui reste » du commentaire précédent sont faits. Ils ont tourné sur un nœud de backtest qui ne tronque pas la fenêtre (2015-01-01 -> 2026-08-31), et ont été lus à completed: true ; le nombre d'ordres relus à la source égale celui des statistiques. L'avant est le run publié du README (2026-09-01), lancé sur un main.py identique à celui d'avant le correctif. Six semaines séparent les deux runs : le moteur ou les données ont pu changer entre-temps, et cette paire est moins contrôlée que celle des nœuds sponsorisés.

    Mode Backtest avant -> après Sharpe Rendement annuel composé Pire baisse Ordres
    sparse a9bb668b764d55155f6a074f84627757 -> 8d5874334173ee85fea7affb5e2ae899 0,611 -> 0,601 17,00 % -> 16,35 % 34,7 % -> 35,3 % 703 -> 536
    full 8e647c58edff52af9836b25b80ff433d -> 4f5c12db8ea30104fbf46f248758b780 0,698 -> 0,710 17,26 % -> 17,16 % 30,7 % -> 31,3 % 1414 -> 1222

    Après correctif, dans les deux modes : 47 déclenchements, tous à 16:00, 63 séances d'écart chaque fois, 316 barres d'historique, aucun report, sessions=2932. Le classement entre les deux modes ne change pas. Le full gagne un peu de Sharpe et le sparse en perd un peu : les deux mouvements vont en sens contraires, ce qui confirme que l'écart de métriques n'a pas de signe à retenir.

    PR : #20532. Traces : G:\Mon Drive\MyIA\IA\QC-traces\20286-sparse-index\fix-{sparse,full}-perso\.

  26. added 3 commits that reference this issue on Oct 13, 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

    bugSomething isn't workingqc

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions