Repository navigation
[QC][Explorer] Évaluer « Multi-Horizon ETF Momentum Rotation » (676) sous frais du courtier #19174
Description
Source
QuantConnect Strategy Explorer, stratégie publique 676 « Multi-Horizon ETF Momentum Rotation Strategy » (auteur affiché : Jon Thibodeaux), version 1.1.0 du 01/10/2026. Fiche lue le 2026-10-04 par l'API publique POST /api/v2/strategies/read (projet à cloner : 34803853, backtest de référence : 828ad393d1ac88255bac5a44e80fe3eb, discussion 21181).
Description publiée : rotation mensuelle entre 20 ETF (actions US et internationales, obligations, matières premières, devises). Score de momentum = moyenne de cinq taux de variation sur 5, 21, 63, 126 et 252 séances, chacun mesuré avec un saut de 21 séances. Le premier jour de bourse du mois, les cinq ETF au meilleur score sont retenus ; si les cinq scores sont négatifs, tout passe en liquidités. Poids inversement proportionnels à l'écart-type des rendements journaliers sur 63 séances. Toutes les positions sont liquidées avant la pose des nouvelles cibles. La version 1.1.0 a ajouté le saut de 21 séances et cinq ETF à l'univers (UUP, FXF, AIA, DBA, RLY).
Chiffres affichés par la fiche (non vérifiés, Sharpe au sens de QuantConnect) : CAGR 5 ans 8,07 %, pire baisse 5 ans 15,6 %, Sharpe 1 an 0,914. Aucun historique hors échantillon : la version évaluée date du 01/10/2026.
Pourquoi
C'est la première stratégie de rotation d'ETF multi-classes du Strategy Explorer évaluée ici, après deux stratégies sur actions individuelles (#18904, #18905). Deux de ses briques existent déjà dans le dépôt : le momentum multi-horizons et le dimensionnement par l'inverse de la volatilité (#19072). La question est donc moins « l'idée tient-elle ? » que « apporte-t-elle quelque chose face aux allocations d'ETF du dépôt, et à quel coût en frais ? ».
Deux points de vigilance :
- la liquidation complète chaque mois fait payer deux fois les frais des lignes conservées ;
- un univers de 20 lignes et cinq horizons laisse beaucoup de degrés de liberté à une stratégie publiée il y a quelques jours.
Protocole
Même protocole que #18904, même règle de verdict, mêmes références :
- Lire le projet publié ; à défaut, réimplémentation déclarée d'après la description publique, chaque point laissé ouvert tranché dans le README.
- Backtest QC avec les frais du courtier (modèle par défaut de Lean) sur la fenêtre principale 2018-01-01 → 2026-09-25, puis sur la fenêtre de la fiche (écart de reproduction seulement).
- Mesures : Sharpe, CAGR, pire baisse, rotation annuelle, frais annuels, Sharpe à frais doublés ; comparaison au SPY détenu et au 60/40 SPY/IEF ; corrélations hebdomadaires avec les paniers proxys des allocations d'ETF du dépôt.
- Verdict
BEATS/NO BEATS/INCONCLUSIVE, avec robustesse par sous-période, à frais doublés et sur des paramètres voisins (grille fixée avant le calcul). - Point propre à cette stratégie : ce que coûte la liquidation complète, mesuré contre la même règle qui ne traite que les écarts.
- Geler le code à la date du verdict et l'inscrire au registre du suivi en ombre ([ML-Pipeline][#18907 5c] Suivi en ombre : geler les candidats à une date D et les rejouer chaque mois, historique hors temps sans biais de sélection #18923).
Livrable
Un projet sous MyIA.AI.Notebooks/QuantConnect/projects/ avec attribution à l'auteur et lien vers la fiche. Backtests annoncés sur le dashboard (limite de 10 appels/min partagée par la flotte).
See #18904.
Activity
jsboige commentedon Oct 4, 2026
[CLAIMED] lane myia-po-2024:CoursIA-3 -- réimplémentation déclarée, backtests QC et verdict selon un pré-enregistrement posté avant le premier run -- paths: MyIA.AI.Notebooks/QuantConnect/projects/MultiHorizonMomentum676/**
jsboige commentedon Oct 4, 2026
[PRÉ-ENREGISTREMENT] lane myia-po-2024:CoursIA-3 — évaluation de la 676 en réimplémentation déclarée. Posé avant le premier backtest : aucun run de ce projet n'existe à l'heure de ce commentaire (son horodatage fait foi).
1. Ce qui est évalué
Le projet publié
34803853n'est pas lisible par le compte de la flotte (files/read: « You do not own this project »), et la page de la discussion 21181 ne rend pas son contenu sans navigateur. J'écris donc une réimplémentation déclarée d'après la description publique de la fiche, comme pour #18904. Aucune ligne du code d'origine n'est reprise.Projet, sur une branche à venir :
projects/MultiHorizonMomentum676/. Références : celles de #18904 (voir §4).P[t−21] / P[t−21−h] − 1pour h ∈ {5, 21, 63, 126, 252}, sur les clôtures journalières ajustéesliquidate=1)fee_multConséquence : un écart à la fiche peut venir de ces choix, surtout de l'univers, autant que de la stratégie. Il est rapporté, il n'entre pas dans le verdict.
Chiffres de la fiche, relus le 2026-10-04 : CAGR 5 ans 8,07 %, pire baisse 5 ans 15,6 %, Sharpe 1 an 0,914 au sens de QuantConnect ; backtest de référence
828ad393….2. Fenêtres
3. Mesures
Comme #18904 : valeur du portefeuille à chaque clôture (graphique
shadow, sériese0..e4, contrat du rejeu en ombre de #18923) ; Sharpe à taux sans risque nul (rendements journaliers, ddof 1, √252), CAGR et pire baisse parstrategy_metrics.py; rotation annuelle et frais annuels par les sériesturnoveretfees. Les statistiques du rapport QuantConnect ne sont pas utilisées. Chaque rebalancement est écrit dans le journal de l'algorithme (lignes retenues, poids, mois en liquidités).4. Règle de verdict
Identique à #18904. Deux comparaisons dans la fenêtre principale :
Références réutilisées, pas relancées : les runs
spyet6040de #18904 (projetFourSleeve774Benchmarks,main.pyde sha2568c4088c51967…, PR #19139) couvrent exactement la même fenêtre, avec les mêmes frais et le même rebalancement le premier jour de bourse du mois. Les séries sont alignées par date ; les séances manquantes d'un côté sont comptées et rapportées.Test :
voltarget_strategy_verdict.circular_block_diff, bootstrap circulaire par blocs de 21 séances, 10 000 tirages, graine 18921, mêmes indices pour les deux séries. La p-valeur unilatérale est la part des tirages où la différence est ≤ 0. Correction de Holm sur les deux comparaisons.NO BEATSBEATSINCONCLUSIVEConditions de robustesse :
fee_mult=2).Grille, un paramètre à la fois :
top∈ {3, 7} ;skip=0(sans saut) ;weights=equal. Elle n'est lancée que si le test principal rend p Holm < 0,05 pour au moins une référence : sinonBEATSest déjà exclu et la grille ne peut plus changer le verdict (leçon du complément 1 de #18904, posée ici d'avance).5. Point propre à la 676 : le coût de la liquidation complète
Un run
liquidate=0dans la fenêtre principale : mêmes cibles, mais seuls les écarts sont traités. Rapportés, hors verdict : différence de frais annuels, de rotation annuelle et de CAGR entreliquidate=1etliquidate=0.Corrélations hebdomadaires, Pearson sur les rendements du vendredi, sans test, sur la fenêtre principale : avec les paniers proxys
vt2(SPY/QQQ/IEF/GLD à poids égaux) etaw(SPY 0,30 / IEF 0,30 / GLD 0,30 / XLP 0,10) de #18904, réutilisés eux aussi, et avec la 774.6. Ordre des runs
Un backtest à la fois, annoncé sur le dashboard, lu seulement à
completed: true:liquidate=0;Les séries brutes sont rangées hors dépôt, et leur chemin sera cité dans le résultat.
7. Après le verdict
Le code est gelé au SHA du verdict et inscrit au registre du suivi en ombre (#18923), puis rejoué chaque mois sur la période écoulée.
Ce pré-enregistrement ne sera pas modifié. Tout changement de règle ou de grille sera posté en complément daté, avant le run qu'il concerne.
jsboige commentedon Oct 4, 2026
[COMPLÉMENT daté 2026-10-04, avant toute relance] lane myia-po-2024:CoursIA-3 — défaut d'implémentation dans
main.pyen modeliquidate=1; trois des quatre runs pré-enregistrés sont annulés et relancés.Ce qui a été vu
Les quatre runs pré-enregistrés ont tourné avec
main.pysha2560d683f60da11…: principal, frais doublés, fenêtre de la fiche,liquidate=0. Le run principal et le runliquidate=0écrivent les mêmes lignesselchaque mois, donc les mêmes cibles. Pourtant leurs pires baisses ne se ressemblent pas : −10,8 % pour le premier, −22,7 % pour le second. Les mêmes cibles ne peuvent pas produire deux expositions aussi différentes. J'ai donc lu le journal des ordres des deux backtests (backtests/orders/read, 1 026 et 646 ordres).Cause
En données journalières, un ordre passé à 10 h s'exécute à la clôture. Après
liquidate(), l'appelset_holdings(cibles)calcule donc ses quantités contre des positions qui ne sont pas encore vendues. Il n'envoie que les écarts.Exemple du 2018-03-01. Le run principal vend tout : AIA −234, EEM −359, EWJ −392, QQQ −124, SPY −118. Il n'achète ensuite que SPY −24, AIA +53, EEM +61, EWJ +18 et QQQ −2. Ce sont exactement les ordres du run
liquidate=0le même jour.Sur l'ensemble de la fenêtre, j'ai reconstruit les positions à partir des ordres et comparé l'exposition brute après chaque rebalancement à celle du run
liquidate=0, mois par mois sur 104 dates communes :Le run principal ne mesure donc pas la règle déclarée.
Conséquence
0d683f60da11…liquidate=1liquidate=1liquidate=1liquidate=0set_holdingsavecliquidate_existing_holdingsMesures et décisions de la v1 :
INCONCLUSIVEcontre les deux références, que je n'ai pas publié.v1du dossier des traces de l'évaluation. Rien n'est effacé.Correctif
Il ne touche que la mécanique d'ordre. La règle, l'univers, les fenêtres, les références, la règle de verdict et la grille conditionnelle ne changent pas.
Avec
liquidate=1, les quantités cibles absolues sont fixées avant la liquidation : position actuelle plus l'ordre qui mène à la cible. La liquidation et les achats sont ensuite envoyés ensemble. Tout s'exécute à la même clôture, ventes d'abord.Nouveau
main.py: sha256a5f8a4248526…(6 787 octets).Relance
Les quatre runs sont relancés sous ce code, avec les mêmes paramètres, un à la fois : principal, frais doublés, fenêtre de la fiche,
liquidate=0. Le runliquidate=0est relancé pour que les quatre runs partagent le même code.Contrôle prévu avant toute mesure : relire le journal des ordres du nouveau run principal et vérifier qu'au 2018-03-01 il revend tout puis rachète les cibles en entier.
Déclaration (pas un changement)
Janvier 2018 n'est investi ni par la 676 ni par les références de #18904. En données journalières, aucun prix n'est encore connu à 10 h le 2 janvier, et le premier investissement a lieu le 1er février. La mécanique est la même des deux côtés ; je la conserve pour garder la symétrie de la comparaison.
jsboige commentedon Oct 5, 2026
[RÉSULTAT] lane myia-po-2024:CoursIA-3 — évaluation de la 676 en réimplémentation déclarée, selon le pré-enregistrement #19174 (comment), posé avant le premier backtest.
Les runs viennent du code corrigé décrit dans le complément #19174 (comment) (
main.pysha256a5f8a4248526…). Ce complément a été posté avant leur relance. La règle de verdict et la grille n'ont pas changé.Verdict :
NO BEATScontre les deux référencesFenêtre principale 2018-01-01 → 2026-09-25, 2 194 rendements journaliers alignés, aucune séance manquante d'un côté ni de l'autre.
Méthode :
circular_block_diff, blocs de 21 séances, 10 000 tirages, graine 18921 ;NO BEATSNO BEATSLes deux différences sont négatives : c'est la condition de
NO BEATSdu §4.Robustesse. Elle est rapportée pour information ; elle ne peut plus changer le verdict.
Grille non lancée, comme le prévoyait le §4 : aucune référence n'atteint p Holm < 0,05.
Mesures par run
Sharpe à taux sans risque nul. Frais annuels en % du capital de départ.
liquidate=1)liquidate=0Coût de la liquidation complète (§5, hors verdict)
Mêmes cibles chaque mois, seule la façon de les atteindre change :
liquidate=1liquidate=0Vendre puis racheter les lignes conservées multiplie la rotation par 2,6 et presque double les frais. Cela coûte environ 0,1 point de rendement par an, sans rien changer à l'exposition.
Le run
liquidate=0relancé sous le nouveau code donne une série identique, octet pour octet, à celle de la v1. Le correctif ne touche donc que le cheminliquidate=1.Écart à la fiche (hors verdict)
Sur la fenêtre de 5 ans supposée de la fiche (2021-10-01 → 2026-09-30, hypothèse déclarée au §2) :
Le rendement est plus haut ici d'environ 1,5 point, et la pire baisse plus faible. L'écart peut venir de l'univers (15 lignes sur 20 sont les nôtres) autant que d'un autre point laissé ouvert, et il n'est pas attribuable sans le code d'origine. Le Sharpe 1 an de la fiche (0,914) est calculé au sens de QuantConnect, avec taux sans risque : il n'est pas comparé.
Ce que fait la règle, mois par mois
Source : journal de l'algorithme, 105 rebalancements de janvier 2018 à septembre 2026. Les lignes
selde la v1 et de la v2 sont identiques, car la sélection ne dépend pas de la mécanique d'ordre.Corrélations hebdomadaires (sans test)
Pearson sur les rendements du vendredi, fenêtre principale :
vt2awCes trois paniers ont un Sharpe nettement supérieur à celui de la 676 (0,675) sur la même fenêtre.
Version du code et traces
projects/MultiHorizonMomentum676/main.py, sha256a5f8a4248526…(6 787 octets). L'empreinte du fichier du projet QC a été revérifiée à chaque lecture de run. Un seul compile pour les 4 runs.0d683f60da11…) annulés par le complément restent déposés dans le sous-dossierv1.spy,6040,vt2,awetbasede [QC][Explorer] Évaluer « Four-Sleeve Adaptive Growth » (774) sous frais IBKR #18904 (FourSleeve774Benchmarks,main.pysha2568c4088c51967…; 7749b4ff36fc02d…), lus dans leurs dossiers, pas relancés.strategy_metrics.pyetvoltarget_strategy_verdict.circular_block_diffdumainde CoursIA au commitf1794486ae. Ces deux fichiers n'ont pas changé depuisd0103b51a7.G:\Mon Drive\MyIA\IA\QC-traces\19174-multi-horizon-676\(hors dépôt).Suite
PR à venir avec le projet
projects/MultiHorizonMomentum676/: code, README et cette section de résultats. Après le merge, comme annoncé au §7 :main;fix(qc,#19174): README 676 -- liens vers PR #19139 et comptes en pros…
feat(qc,#19174): MultiHorizonMomentum676 -- reimplementation declaree…
docs(consolidation,#16473): acceptance 2 lot 6 (axe E, 60 orphelines #…
docs(consolidation,#16473): acceptance 2 lot 6 (axe E, 60 orphelines #…
feat(shadow,#18923): freeze the 676 as first QC candidate; plan-qc re…
docs(consolidation,#16473): acceptance 2 lots 1+3+4+5+6 (axes B/A/C/D…
myia-ai-01 commentedon Oct 7, 2026
Fermeture par le coordinateur. Livrée par #19182 et #19250 :
MultiHorizonMomentum676, avec l'attribution à l'auteur, le lien vers la fiche et le verdictNO BEATS;mhm676dansML-Training-Pipeline/shadow/registry.json.— ai-01, cycle 07/10 06:13Z