QuantConnect (QC) - Configuration et règles
Document de reference pour la coordination QC (MCP, orgs, patterns, anti-patterns). Pour les details pédagogiques et le mapping livre Jared, voir la navigation des docs QC ci-dessous.
Backtests obligatoires
Toute modification d’une stratégie QC (main.py, paramètres, périodes) DOIT être validée par un backtest :
create_compilepour vérifier la compilationcreate_backtestpour lancer le backtestread_backtestpour récupérer les métriques (Sharpe, CAGR, MaxDD)- Reporter les résultats dans le message de commit ET sur RooSync
Changer une date ou un paramètre sans backtest = travail invalide.
Mesures post-backtest : gates minimaux (read_backtest post-completion, #14142)
read_backtest appelé pendant qu’un backtest tourne encore rend totalOrders: 0 et des statistics à "-" / "0%" / "$0.00" — un état indiscernable d’un run terminé sans aucun ordre. Incident fondateur (PR #14012, 2026-09-01) : la conclusion « la condition OR n’a JAMAIS été vraie sur 1 461 jours BTC/ETH minute » a été publiée sur un totalOrders=0 lu en cours d’exécution ; la relecture post-completion (commit 71849ef20) a trouvé 487 172 ordres — la conclusion inverse.
Garde obligatoire avant de citer totalOrders ou statistics (invariant cross-lane, tout read_backtest cité dans une PR/issue/JSON la porte) :
result = read_backtest(project_id=..., backtest_id=...)
# GARDE : tant que le backtest n'a pas termine, totalOrders=0 et statistics="-"
# sont des artefacts d'etat, pas des mesures.
assert result["status"] == "Completed.", \
f"backtest pas termine : status={result['status']!r}"
assert result["progress"] == 1, \
f"progress != 1 : progress={result['progress']!r}"
# Ici seulement, totalOrders / statistics sont fiables.Seconde cause de « remplissage nul » à écarter avant toute conclusion stratégique : la devise de compte (#14215). Sur AccountType.CASH, LEAN exige le solde de la devise de cotation ; un compte financé en USD qui négocie des paires USDT (BTCUSDT/ETHUSDT) voit chaque achat rejeté — 0 fill, quelle que soit la condition d’entrée. Le backtest de contrôle B3 (une seule variable changée : set_account_currency("USDT") avant set_cash) est passé de 0 ordre à 917 199 ordres (net −99,88 %) — preuve que le « signal absent » était un compte dans la mauvaise devise. Un verdict « aucun remplissement » sur paires crypto DOIT donc vérifier devise de cotation ↔︎ devise de compte avant d’inférer quoi que ce soit sur la stratégie.
Ces deux gates se vérifient en session via le MCP (snippet ci-dessus à coller dans l’appel) — pas via un script REST direct, interdit par la règle d’accès ci-dessous.
Convention SetEndDate — fenêtre figée vs flottante (mécanisme D2, #9768)
L’absence d’un appel SetEndDate (Python : self.set_end_date(...)) n’est pas toujours un défaut : elle ouvre la fenêtre de backtest à la date courante, ce qui est un comportement légitime selon le type de notebook. La classification (audit #9772 Phase 0) distingue deux régimes :
| Régime | Environnement | SetEndDate attendu |
Raison |
|---|---|---|---|
Déploiement (class X(QCAlgorithm), dossier projects/) |
QC Cloud / Live / Paper | Requis (fenêtre figée) | Reproductibilité du backtest de production — sans date fixée, le résultat dérive à chaque exécution |
Recherche (QuantBook(), dossier ML-Training-Pipeline/) |
Research env | Flottant par design (légitime) | Notebooks exploratoires : la fenêtre flottante est une feature, le notebook n’est pas un livrable reproductible |
Avant de « corriger » un notebook QC sans SetEndDate : vérifier son régime. Un notebook de recherche QuantBook sans date figée n’est pas un defect D2. Un notebook de déploiement QCAlgorithm (surtout dans projects/) sans SetStartDate/SetEndDate est un defect à figer (exception : Paper Trading explicite, où l’absence de dates = live par construction, ex. QC-Py-27). Le détecteur canonique est scripts/notebook_tools/scan_window_drift.py (#10230/#10627, qui remplace le grep -L set_end_date brut — ce dernier sur-compte d’un ordre de grandeur en mélangeant les deux régimes).
QC Cloud API - Accès via MCP Docker (OBLIGATOIRE)
Méthode d’accès : Utiliser le MCP Docker quantconnect/mcp-server configure dans .mcp.json a la racine du projet.
- NE PAS utiliser de scripts Python avec l’API REST directe (provoque du rate-limiting et des erreurs d’auth)
- Le MCP gère l’authentification et le rate-limiting automatiquement
- Fichier de config :
.mcp.json(déjà dans.gitignore, JAMAIS committer)
Configuration .mcp.json
{
"mcpServers": {
"qc-mcp": {
"command": "docker",
"args": ["run", "-i", "--rm",
"-e", "QUANTCONNECT_USER_ID",
"-e", "QUANTCONNECT_API_TOKEN",
"-e", "QUANTCONNECT_ORGANIZATION_ID",
"-e", "AGENT_NAME",
"quantconnect/mcp-server"],
"env": {
"QUANTCONNECT_USER_ID": "<voir dashboard RooSync>",
"QUANTCONNECT_API_TOKEN": "<voir dashboard RooSync>",
"QUANTCONNECT_ORGANIZATION_ID": "<voir dashboard RooSync>",
"AGENT_NAME": "claude-code"
}
}
}
}Alternative légère : qc-mcp-lite (~5k tokens vs ~40k)
Le MCP Docker officiel charge un schema d’outils volumineux (~40k tokens). Pour les workflows de backtest standard, le dépôt fournit un wrapper Python léger scripts/qc-mcp-lite/server.py (~10 outils, schema <5k tokens) qui re-expose l’API QC v2 sans conteneur Docker.
Outils exposes : create_compile, read_compile, create_backtest, read_backtest (Sharpe/CAGR/MaxDD), read_backtest_chart (graphique écrit sur disque : equity, exposition, rotation, graphique personnalisé), list_backtests, list_projects, read_project, read_file, create_file, update_file_contents. Auth = pattern QC v2 (SHA256(token:timestamp) + header Basic userId:hash). Rate limiting 10 appels/min applique in-process (même limite fleet-wide).
Config .mcp.json (remplace l’entrée Docker qc-mcp ; secrets dans .env gitignore, JAMAIS inline) :
{
"mcpServers": {
"qc-mcp-lite": {
"command": "python",
"args": ["scripts/qc-mcp-lite/server.py"],
"env": {
"QC_API_USER_ID": "<voir dashboard RooSync>",
"QC_API_ACCESS_TOKEN": "<voir dashboard RooSync>"
}
}
}
}Verification rapide : python -c "from server import list_projects; print(list_projects())" depuis scripts/qc-mcp-lite/. Procédure complete (setup .env, retour au MCP Docker complet) : scripts/qc-mcp-lite/README.md.
Rate limiting strict
MAX 10 appels/minute entre TOUS les agents. Avant de lancer un backtest, poster sur le dashboard. Un seul agent a la fois sur l’API QC.
Pour retrouver les tokens
- Dashboard workspace CoursIA : section status
- Messages RooSync : tag
quantconnectouTOKEN - En cas de token invalide : demander au coordinateur (ai-01) via RooSync
Troubleshooting hash mismatch (incident 2026-04-05)
~/.claude.json (config globale Claude Code) contient parfois une section mcpServers par workspace qui surcharge .mcp.json local. Un ancien token cache la peut causer Hash doesn't match malgré le bon token dans .mcp.json projet.
Vérifier dans cet ordre :
~/.claude.jsonsection du workspace (config globale qui peut surcharger).mcp.jsonracine projet (config projet standard)- Token valide sur QC (tester via API directe Python)
Fix recurrent : supprimer l’entrée mcpServers.qc-mcp de ~/.claude.json pour que .mcp.json soit la seule source de vérité.
Organisations QC
QC est multi-tenant via les “organizations”. Le cluster CoursIA utilise plusieurs orgs en parallèle selon le contexte :
| Org | Tier | Usage | Backtest API |
|---|---|---|---|
| Research tier dedicated (default user) | Research (payant) | Deploiements de reference, Binance crypto data subscription, projets de développement | Inclus |
| Partner school | Free/sponsored | Cours partenaire, masterclass Quant League | NON inclus |
| ECE | Free | Matériel pédagogique ECE | NON inclus |
Règle d’or : pour create_backtest programmatique via API, il faut une org avec backtest API incluse (research tier). Les orgs gratuites/éducatives (partenaire, ECE) n’ont PAS l’API backtest — erreur récurrente : tenter create_backtest sur une org partenaire échoue silencieusement ou avec rate-limit. Vérifier l’org cible avant de dispatcher.
Switcher d’org
L’orga par défaut du MCP est définie par QUANTCONNECT_ORGANIZATION_ID dans .mcp.json. Deux options pour changer ponctuellement :
- Éditer
.mcp.jsonenv var et rebuild le MCP Docker container - Spécifier
organizationIdexplicitement par appel quand le tool MCP l’accepte
Note : read_account retourne TOUJOURS l’orga par défaut du USER_ID (la research tier quand non force par env var).
Énumération des orgs
Il n’existe pas d’endpoint list_organizations. La seule façon : mcp__qc-mcp__list_projects retourne les projets de toutes les orgs dont l’user est membre+ — agréger les organizationId distincts.
Structure QC dans le dépôt
MyIA.AI.Notebooks/QuantConnect/
Python/ # 27+ notebooks progressifs (QC-Py-01 a QC-Py-Cloud-XX)
projects/ # ~50 strategies avec main.py + research.ipynb
shared/ # Librairie utilitaire (backtestlib, indicators, plotting)
partner-course-quant-trading/ # Cours partenaire : exercices, templates, lean-workspace
docs/ # Documentation technique (pas de coordination)
Provisionnement reproductible des data LEAN locales
Les data equity/forex locales (<lean-workspace>/data/) sont gitignorées (binaires volumineuses, régénérables — .gitignore ligne 581). L’incident #8734 (leçon C942-L ★★★, découvert c.942) a montré que des zips tronqués (fin 2021-03-31) forward-fillés silencieusement par fillDataForward=True (défaut Lean) invalident les métriques sans aucun signal d’erreur : le notebook affiche une période « 2015 → 2025 » normale mais les ~4-5 dernières années sont une ligne plate. Trois outils forment la chaîne reproductible qui ferme ce défaut :
| Outil | Rôle | Issue |
|---|---|---|
scripts/quantconnect/yfinance_to_lean_daily.py |
Convertisseur yfinance → zips LEAN daily (OHLC x10000, 00:00, lowercase) |
#8627 |
scripts/quantconnect/check_data_freshness.py |
Détecteur STALE, exit 1 gatable pre-exec | #8737 |
scripts/quantconnect/provision_lean_data.py |
Provisionneur : regen idempotente one-command d’un univers + gate fraîcheur cablée | #8742 |
Le manifeste versionné lean_universes.manifest.json (committé, texte) pin la spec de chaque univers (tickers + plage + regen_date + issue) — c’est le « quelle data a produit ce Sharpe » vérifiable au merge-gate. Les zips restent gitignorés (machine-local), mais reproductibles en une commande :
python scripts/quantconnect/provision_lean_data.py --universe turn_of_month
# → download yfinance + convert + gate fraîcheur (exit 1 si STALE)Avant toute re-exec equity/forex quantbook : provisionner l’univers (ou lancer check_data_freshness.py) pour ne pas reposer sur une ligne plate forward-fillée. Le provisionneur est idempotent (un ticker déjà FRESH est skipé sauf --force) et la gate est cablée post-provision (pas un outil optionnel à penser à lancer). Voir #8734, #8737, #8627.
QC Cloud Assistants — méthode privilégiée Quantbook execution
QuantConnect expose 8 assistants intégrés (Conductor, Ideas, Research, Research Validation, Backtest, Paper Testing, Live Monitoring, Mia) accessibles via :
https://www.quantconnect.com/organization/<org_id>/assistants
Le Research Assistant résout le problème “Quantbook execution Windows local impossible” : il execute les cells du notebook sur QC Cloud, itère automatiquement (edit, execute, fix, re-execute) jusqu’au succès, et les tokens consommes sont ceux de QC (pas Anthropic).
Workflow Research Assistant (via Playwright)
- Naviguer
https://www.quantconnect.com/organization/<org_id>/assistants - Cliquer “New Task” sur Research Assistant
- Créer tâche avec prompt +
project_idQC Cloud cible - Deployer : l’agent execute les cells du notebook
- Lire les résultats dans Tasks > Deployments > Completed
Limites et précautions
- Validation cluster obligatoire post-deployment : même si Research Assistant claim “Sharpe 3.50”, refaire en local par walk-forward 5-fold + multi-seed >=4 + transaction costs avant tout claim BEATS. Cf .claude/rules/pr-review-discipline.md section C.
- Coût QC tokens : ne pas lancer 50 deployments en parallèle sans vérifier le burn rate
- Éviter chevauchement agents sur même deployment (tokens dupliqués) : coordination via dashboard avant lancement
- Notebook output download : Playwright snapshot ou API download artifact (workflow exact a documenter par usage)
Cas d’usage privilégiés
- Re-execution Quantbooks audit (cf section validation H.7 de CLAUDE.md)
- Validation algos QC Cloud avant import dans projects/
- Debugging multi-aller-retour des strategies en iteration
Architecture composites (AlphaModel + MultiStrategyPCM)
Pattern standardise pour combiner plusieurs strategies dans un même algo QC :
Structure de fichiers (3 fichiers obligatoires)
main.py:QCAlgorithmavecset_alpha(CompositeAlphaModel(...))+set_portfolio_construction(MultiStrategyPCM(...))alpha_models.py: une classe par alpha, chaque avecself.nameetsource_model=self.nameportfolio_construction.py:MultiStrategyPCMavecdetermine_target_percent(PAScreate_targets)
MultiStrategyPCM — design
- Groupe les insights par
source_model - Alloue une slice de capital par stratégie via dict
alpha_allocations - Supporte branches weight-hint ET equal-weight
- Utilise
set_rebalancing_funcpour le rebalance timing
AlphaModel — règles
- DOIT avoir
self.name = "StrategyName"dans__init__ - DOIT passer
source_model=self.namea tous lesInsight.price() - DOIT filtrer par liste explicite de tickers (PAS
algorithm.securities.values()) - DOIT enregistrer les indicateurs dans
on_securities_changeduniquement pour les tickers connus - NE JAMAIS ajouter SPY comme equity benchmark dans l’univers (cause un leak si on itère
securities)
Composites realises — leçons (consolidation, pas snapshot)
| Composite | Allocation optimum | Sharpe | Leçon |
|---|---|---|---|
| TrendWeather (TrendStocks + AllWeather) | T75 / AW25 | 1.15+ | Sweep monotone : plus de TrendStocks = meilleur Sharpe. ROC63 momentum weighting = gain majeur (0.79 -> 1.13) |
| FamaFrenchAllWeather | FF20 / AW80 | ~0.59 | Sweep monotone vers AllWeather : FamaFrench n’ajoute pas de diversification |
| MomentumRegime (SectorMomentum + RegimeSwitching) | ABANDONNE | max 0.24 | Problème “double-defense” : les deux alphas défensifs sur les mêmes périodes |
| EMATrend (EMA-Cross + TrendStocks) | en cours | a venir | Overlap 5 tech stocks entre strategies (intentionnel) |
Règle générale : si le sweep d’allocation montre un comportement monotone (90/10 ou 10/90 gagne), le second alpha n’apporte pas de diversification — vérifier qu’il occupe un quadrant de marche distinct du premier. Confirmation par la “décennie 2015+” : risk-off via TLT détruit la valeur, equity défensifs (XLP/IEF) > bonds long.
Patterns universels (consolidation 30+ iterations strategies)
Patterns confirmés (a ré-utiliser)
- Risk-adjusted momentum (return/vol) > raw momentum
- Skip-month (Jegadeesh 1990) : exclure le dernier mois — single-asset only
- TLT risk-off détruit la valeur sur la décennie 2015+ : XLP/IEF > TLT
- Stop-loss -8% a -12% : réduit MaxDD sans tronquer les reversions
- ATR sizing contre-productif pour Donchian trend following
- Profit target 50% pour options (TastyTrade) + VIX band 15-35
- Drift rebalancing 3% > SMA overlay pour portfolios statiques
- Vol window 60d > 20d pour covariance min-var
- Monthly + regime-change rebal > daily : réduit trades 80%
- Trail breakeven 3% > 4% pour BTC daily
- SMA50 >> SMA100 pour crypto : SMA100 filtre les bonnes entrées bull
- SL 6% minimum sur BTC daily : 5% trop serré
- OLS hedge ratio ne sauve pas pairs trading : le problème est les paires elles-mêmes
- Fix structural bugs >> academic improvements : leverage/risk mgmt > signal refinement
- Diversifier instruments > relaxer seuils : ajouter SPY+QQQ+IWM > baisser RSI threshold
- Composite via Algorithm Framework = clean separation (AlphaModel + PCM + source_model)
- Biweekly rebalance est l’optimum pour ML (weekly = trop de turnover, monthly = trop lent)
- Anti-overfitting (max_depth 5, min_samples 10) critique pour tree models
- MLPClassifier/MLPRegressor de sklearn marche bien sur QC Cloud
- Selective liquidation réduit le turnover vs full portfolio wipe
Anti-patterns critiques
- SPY Parking : investir en SPY quand inactif = beta loading déguisé, le Sharpe monte mais l’alpha est nul
- Backtests courts = overfitting : Trend-Following Sharpe 2.157 (3 mois) -> 0.06 (7 ans)
- ChatGPT/academic suggestions : 3/4 dégradent sur QC cloud. Ne garder que les fixes structurels
- yfinance != QC cloud : 6/12 research suggestions dégradent en pratique
- Crypto strategies pre-2018 unreliable : 2017 bubble distortion
- MaximumDrawdownPercentPortfolio = JAMAIS sur multi-stock (liquidation simultanée)
- 1 param a la fois : changer tout ensemble -> regression non-diagnostiquable
- Raw momentum + min-var : ne pas combiner (double penalisation)
- Fake ML implementations (hardcoded weights) : pires que real sklearn models
- SMA100 filter trop restrictif pour mean reversion
- USD trend filter degrade FX momentum
Leçons techniques QC
read_fileAVANTupdate_file_contents: collaboration lock (expire vite)- Options :
Resolution.MINUTEsinon chain vide - 1 seul backtest a la fois sur le node QC
algo.rsi(symbol, 14, Resolution.Hour)ne marche pas dansOnSecuritiesChanged-> utiliserregister_indicatorclass X(QCAlgorithm, Mixin)interdit (Python/CLR multiple inheritance)- Binance CASH :
set_account_currency("USDT")+set_cash(10000) - Binance fees : preleve en BTC -> utiliser
portfolio[sym].quantitypasorder qty - QC API auth :
SHA256(token:timestamp)as hash, headerTimestamp, Basic auth - Chart API : data seulement pour backtests récents (~quelques heures)
Historique training & checkpoints (preservation)
Toute l’historique des trainings ML/QC est préservée dans le dépôt et accessible a tous les agents, PAS dans des memos chronologiques :
| Source | Contenu |
|---|---|
MyIA.AI.Notebooks/QuantConnect/ML-Training-Pipeline/REGISTRY.md |
Registry 70+ checkpoints, BEATS/FAIL/MIXED par symbole, stages -1/0/1/2, Anti-Bias audit |
MyIA.AI.Notebooks/QuantConnect/ML-Training-Pipeline/CURRICULUM.md |
Plan global ML curriculum |
MyIA.AI.Notebooks/QuantConnect/ML-Training-Pipeline/docs/M1..M17 + Stage2 + Stage7 + RECAP_KEEPERS_V2 |
35 fichiers de notes méthodologiques par iteration |
MyIA.AI.Notebooks/QuantConnect/ML-Training-Pipeline/docs/Curriculum_V2_Meta_Analysis.md |
Meta-analyse curriculum V2 |
MyIA.AI.Notebooks/QuantConnect/ML-Training-Pipeline/scripts/results/*/checkpoint.jsonl + train.log |
27 runs avec état par combo et logs unbuffered (local, gitignored) |
QC Cloud (MCP list_projects + list_backtests + read_backtest) |
Sharpe/CAGR/MaxDD live de chaque iteration |
| docs/archive/ml-trading-state.md | Leçons consolidées (vol vs direction, parcimonie, transaction costs, recommandations datasets) |
Règle : pas de duplication. Si tu veux ajouter une note sur une iteration training, vise ML-Training-Pipeline/docs/M<N>_*.md ou QC Cloud notes, pas un memo coordinateur. Pour une leçon trans-iteration : docs/archive/ml-trading-state.md.
Livre de reference
Hands-On AI Trading de Jared Broad — https://www.hands-on-ai-trading.com/
- Repo exemples : https://github.com/QuantConnect/HandsOnAITradingBook
- 22 exemples : Ch06 (19 strategies ML), Ch07 (1 RL hedging options), Ch08 (2 portfolio)
- Issues associées : #107 (mapping), #143 (implementation ML)
Le livre couvre les patterns ML actuels (RF, XGBoost, LSTM, CNN temporel, Chronos foundation models, RL hedging) avec exemples QC Cloud directement importables. Cf MyIA.AI.Notebooks/QuantConnect/projects/ pour les imports realises.
Reference QC partnership
QuantConnect (Jared Broad, CEO) sponsorise l’usage éducatif via le code promo education2025 (annule 100% du coût des seats Trading Firm). Architecture éducative recommandée :
- Org sponsorisée = espace commun (algos d’exemple, evaluation collective, masterclass), avec coupon
- Comptes perso FREE pour les étudiants = suffisants pour term projects sur leur poste
- Coût minimum par org éducative avec coupon : 14$/mois (1 noeud B2-8 backtest)
Mécanique du coupon : cart vide non accepte pour checkout, minimum 1 noeud compute requis. Rate limit API : 15 min de cooldown si on clique trop vite sur +/-. Le coupon couvre les seats Trading Firm (unlimited members), pas le compute.
Hands-On AI Trading book : recommandation officielle de Jared pour le cursus (cf section “Livre de reference”).