Méthodologie du Track Record public
Ce document explique exactement comment chaque chiffre est calculé. Aucun secret, aucun arrondi favorable, aucun cherry-picking. Si tu trouves une erreur ou un biais dans ce texte, dis-le : on corrigera et on documentera la correction.
1. Comment les scénarios sont émis
Chaque jour ouvré (lundi→vendredi) à 07:00 UTC, un cron job
sur notre VPS exécute scripts/emit_daily_scenarios.py --mode assets.
Ce script :
- Récupère les options ^NDX, ^SPX, GLD via yfinance et calcule les levels (call wall, put support, HVL, GEX, régime gamma)
- Applique une basis conversion vers les futures NQ=F, ES=F, GC=F via la parité put/call (implied forward).
- Construit 25 features (régime, walls, OHLC history, asset one-hot).
- Passe le vecteur au modèle LogisticRegression + Platt scaling entraîné sur 128 sessions historiques (NQ+ES+GC+EURUSD poolées).
- Produit 3 probabilités normalisées :
p_A(range),p_B(breakout haussier),p_C(flush baissier). - Écrit la ligne dans la table SQLite
scenario_emissions— écriture append-only, jamais modifiée après.
Modèle ML
LogisticRegression (lbfgs) + CalibratedClassifierCV (Platt scaling, cv=3) Features : 25 colonnes (9 MQ-equivalent + 7 geometry + 6 OHLC technique + 4 asset one-hot) Training : TimeSeriesSplit 5-fold sur 128 sessions historiques (février→avril 2026) Out-of-fold metrics : hit_top 58.6%, hit_any 88.3%, Brier 0.169
2. Comment une session est résolue
À chaque session, on attend la close US réelle. Le script
score_session.py pull l'OHLC du jour via yfinance, puis pour
chaque scénario émis calcule s'il a "joué" :
- Scénario A (range_hold) : close ∈ [put_wall, call_wall] ET high < call_wall + 0.3×(call_wall − put_wall) ET low > put_wall − 0.3×(call_wall − put_wall). Autrement dit le range a tenu sans excursion significative.
- Scénario B (breakout_up) : high > call_wall ET close > call_wall. Break net au-dessus.
- Scénario C (flush_down) : low < put_wall ET close < put_wall. Flush net en-dessous.
Un scénario peut jouer ou ne pas jouer — c'est binaire. Les flags
played_A, played_B, played_C sont
écrits dans la table session_outcomes après résolution.
top_played = 1 si le scénario avec la plus forte probabilité
est celui qui a joué, 0 sinon.
3. Les métriques calculées
Hit rate (top scénario)
hit_top = count(top_played == 1) / count(sessions résolues)
C'est la métrique la plus intuitive. Sur N sessions, combien de fois notre scénario le plus probable a-t-il joué ? Baseline aléatoire sur 3 scénarios ≈ 33%. Nous visons > 52%.
Hit rate (any scénario)
hit_any = count(played_A ∨ played_B ∨ played_C) / count(sessions)
Combien de fois au moins l'un de nos 3 scénarios a-t-il joué. Mesure la couverture : si hit_any est proche de 100%, nos 3 scénarios englobent correctement l'espace des possibilités. Cible : > 85%.
Brier score (multi-classe)
brier(session) = (pA − yA)² + (pB − yB)² + (pC − yC)² où yX = 1 si le scénario X a joué, 0 sinon. brier_mean = moyenne sur les sessions résolues.
Mesure de l'erreur quadratique des probabilités. Plus bas = mieux. Baseline aléatoire (1/3 partout) ≈ 0.667. Baseline "toujours miser sur A" ≈ 0.5. Un moteur calibré vise < 0.22.
Log-loss
log_loss(session) = −log(p_played) où p_played est la probabilité annoncée du scénario qui a effectivement joué. log_loss_mean = moyenne sur les sessions.
Pénalise plus fortement les prédictions très confiantes mais fausses. Baseline aléatoire ≈ 1.098. Un bon moteur est sous 0.9.
Courbe de calibration
On empile toutes les prédictions (3 par session × N sessions) et on les répartit en 10 tranches de probabilité [0-10%, 10-20%, …, 90-100%]. Pour chaque tranche :
predicted_mean = moyenne des probabilités annoncées dans la tranche actual_frequency = fraction des scénarios de cette tranche qui ont joué n = nombre de points dans la tranche
Si le moteur est parfaitement calibré, actual_frequency ≈ predicted_mean dans chaque tranche (points alignés sur la diagonale). Un point à (0.6, 0.4) signifie que "quand on a dit 60%, ça s'est produit seulement 40% du temps" — le moteur est sur-confiant sur cette plage.
4. Fenêtres temporelles
Les cinq fenêtres publiées :
last_7d— 7 derniers jours (échantillon faible, volatile)last_30d— 30 jours (référence principale affichée)last_90d— 90 jours (stabilité de la calibration)last_365d— 365 jours (performance long terme)all_time— depuis le premier jour de tracking public
5. Ce qui N'EST PAS mesuré
Honnêteté intellectuelle : cette méthodologie mesure la qualité prédictive brute du moteur de scénarios. Elle ne mesure PAS :
- Le P&L d'un trader qui suit le plan — cela dépend de son entry/exit timing, sizing, slippage, discipline. Le track record ne promet pas un rendement.
- Les profits potentiels intra-session — un scénario A peut toucher la borne haute à 11h avant de revenir dans le range — ça reste comptabilisé "played_A". Un trader qui short au call wall peut en tirer profit, ou se faire stopper, selon sa gestion.
- La qualité des niveaux en tant que tels — on mesure si le scénario gagne, pas si chaque niveau est "bon".
- Les faux breakouts intra-session qui sont "repris" avant close. Notre définition de played_B/C exige close de l'autre côté.
6. Anti-cherry-picking
Append-only. La table scenario_emissions a
une contrainte d'unicité (session_date, asset). Une émission peut être
ré-écrite uniquement avant résolution. Après résolution, toute tentative de
ré-écriture lève une exception.
CSV public. Tu peux télécharger le ledger complet en CSV brut et refaire tous les calculs toi-même. Si nos chiffres diffèrent, signale-nous le bug — on corrigera publiquement.
Horodatage UTC. Toutes les dates sont en UTC pour éviter la tentation des "fenêtres glissantes avantageuses".
7. Limites connues
- Petit échantillon début de vie : les premières
semaines, les fenêtres courtes (7d, 30d) sont très volatiles.
Utilise
last_90douall_timepour un signal stable. - Biais de survie des features MQ : le modèle a été entraîné avec 4 QScores Menthor Q. Depuis le 9 avril 2026, ces features sont absentes en inférence (imputées par la médiane). Un retrain sans QScores est planifié.
- Dépendance yfinance : les données options viennent de yfinance (gratuit, non-institutionnel). Occasionnellement, la chaîne peut être dégradée en pré-open — notre chain quality check refuse ces snapshots et préserve le précédent.
8. Historique des changements méthodologiques
Chaque modification de la méthodologie est datée publiquement et, si elle affecte la comparabilité des résultats, le ledger est reset pour éviter de mélanger deux régimes de mesure. Aucune session n'est supprimée silencieusement : les ledgers archivés restent disponibles sur demande.
- 2026-04-20 — Flip de convention dealer (SqueezeMetrics → GPP
/ Menthor Q). Le signe du GEX agrégé utilisait la convention
SqueezeMetrics (dealers short calls, long puts). Alignement sur la
convention Garleanu-Pedersen-Poteshman 2009 (dealers long calls,
short puts) — empiriquement vérifiée sur SPX/NDX et identique à
celle de Menthor Q. Même magnitude GEX, signe inversé ; l'interprétation
"positif = vol amortie, négatif = vol amplifiée" reste identique.
Le ledger a été reset pour repartir sur une base homogène.
Ancien ledger archivé :
data/ledger_archived_2026-04-20_pre_gpp_flip.sqlite3.
Dernière mise à jour du document : 2026-04-20. Source du code de scoring :
scripts/score_session.py et engine/live/track_record.py.