4 stratégies momentum en production : Cross-Section Momentum (CSM), Time-Series Momentum (TSMOM), Post-Earnings Drift (PEAD), et Industry Rotation. Backtest 2010-2025, code complet, et métriques réelles.
Le momentum est le facteur le mieux documenté en finance (Jegadeesh & Titman, 1993). Les actions qui ont bien performé sur les 3-12 derniers mois tendent à continuer de bien performer sur les 1-6 prochains mois. Ce phénomène persiste depuis 200 ans, sur tous les marchés, toutes les classes d'actifs.
Le momentum a un risque connu : les crashs de momentum (ex : mars 2009, novembre 2020). C'est pourquoi on combine avec mean-reversion et dual momentum (Partie 7 et 8).
| Stratégie | Univers | Holding | Rôle | Allocation typique |
|---|---|---|---|---|
| Cross-Section Momentum | 1500 actions US+EU+APAC | 1 mois | Moteur principal (stock-picking) | 20% |
| Time-Series Momentum | 50 ETF sectoriels + pays | 1-3 mois | Direction macro | 16% |
| Post-Earnings Drift | Actions post-earnings surprise | 5-20 jours | Alpha événementiel | 15% |
| Industry Rotation | 11 secteurs GICS | 1 mois | Rotation cyclique | 14% |
CSM est la stratégie la plus classique : acheter les gagnants, éviter les perdants. Notre version l'enrichit avec un momentum composite multi-facteurs et un filtre de qualité pour éviter les "momentum traps".
claude -p "Implémente CSMStrategy dans strategies/csm.py :
class CSMStrategy(BaseStrategy):
'''Cross-Section Momentum — Buy winners, avoid losers.
Univers:
- Fetch les 1500 actions les plus liquides (ADV > $5M) des marchés:
US (NYSE+NASDAQ), EU (Euronext+Xetra+LSE), APAC (TSE+HKEX+ASX)
- Exclure: financials, utilities, REITs, biotech pre-revenue
- Exclure: actions en earnings dans les 5 prochains jours
- Exclure: actions avec short_interest > 20%
Signal momentum composite (score 0-100):
score = 0.40 × rank(MOM_12_1) + # Momentum 12M excl dernier mois
0.25 × rank(MOM_6_1) + # Momentum 6M excl dernier mois
0.20 × rank(ACCEL_MOM) + # Accélération (MOM_3M - MOM_6_3)
0.15 × rank(HIGH_PROX) # Proximité du 52W High
Filtre qualité (obligatoire, élimine les momentum traps):
- ROE > 5% (exclure les zombies qui montent sur du short squeeze)
- Debt/Equity < 3 (exclure les surendettés)
- Revenue growth > -20% (exclure les entreprises en déclin)
Portfolio construction:
- Top 30 actions par score composite (après filtres)
- Poids: Kelly fractionnel × HRP (voir Partie 4)
- Contraintes: max 10% par position, max 30% par secteur
- Rebalancement: mensuel (premier lundi du mois)
- Slippage budget: 5 bps US, 15 bps EU, 25 bps APAC
Anti-overfitting:
- Walk-forward: 5 ans IS / 1 an OOS, rolling annual
- CPCV avec 10 splits
- Deflated Sharpe Ratio > 0.5 requis
'''
def generate_signals(self) -> pd.DataFrame:
'''Retourne un DataFrame avec colonnes [symbol, score, region, sector]
trié par score décroissant. Top 30 = positions.'''
def backtest(self, start='2010-01-01', end='2025-12-31') -> BacktestResult:
'''Backtest walk-forward avec rebalancement mensuel.
Retourne: CAGR, Sharpe, MaxDD, Calmar, turnover, hit_rate'''
"
| Métrique | CSM Long-Only | SPY (benchmark) | Excès |
|---|---|---|---|
| CAGR | 24.3% | 13.2% | +11.1% |
| Sharpe Ratio | 1.35 | 0.72 | +0.63 |
| Max Drawdown | -22.1% | -33.9% | 11.8% mieux |
| Calmar Ratio | 1.10 | 0.39 | +0.71 |
| Win Rate (mois) | 64% | 62% | +2% |
| Turnover annuel | 180% | 5% | — |
| Nombre positions moy | 28 | 500+ | — |
| Hit rate (trades) | 52% | — | — |
| Avg win / Avg loss | 1.8 | — | — |
CSM a subi un drawdown de -22.1% en mars 2020 (COVID). C'est le talon d'Achille du momentum : quand le marché se retourne violemment, les gagnants récents chutent plus que le marché. C'est exactement pourquoi on combine avec mean-reversion (Partie 7) et un détecteur de régime (Partie 9) qui réduit l'allocation momentum en Risk-Off.
Contrairement au CSM (relatif : "quoi acheter"), le TSMOM est absolu : "faut-il être investi ?". Si un actif a un trend positif → long. Si négatif → cash (on ne shorte pas, contrainte long-only).
claude -p "Implémente TSMOMStrategy dans strategies/tsmom.py :
class TSMOMStrategy(BaseStrategy):
'''Time-Series Momentum sur un univers d'ETF.
Univers (50 ETF):
US sectoriels: XLK, XLV, XLF, XLE, XLI, XLY, XLP, XLU, XLB, XLRE, XLC
US thématiques: QQQ, ARKK, ICLN, SMH, XBI, IYR, KRE
Europe: VGK, EWG, EWQ, EWU, EWI, EWP, EWN, EWL
APAC: EWJ, EWY, EWH, EWA, EWT, MCHI
Commodities: GLD, SLV, USO, UNG, DBA, DBC
Fixed Income: TLT, IEF, SHY, HYG, LQD
Volatility: SVXY
Signal par ETF:
trend_score = (0.5 × sign(r_12m) + 0.3 × sign(r_6m) + 0.2 × sign(r_3m))
- Si trend_score > 0.3 → LONG (allocation = trend_score × kelly_weight)
- Si trend_score <= 0.3 → CASH (pas de position)
Volatility targeting:
- Chaque ETF est scalé pour contribuer 10% de vol annualisée
- weight_i = target_vol / realized_vol_i × trend_score_i
- Cela donne naturellement plus de poids aux ETF calmes (utilities, bonds)
et moins aux ETF volatils (ARKK, USO)
Rebalancement: bi-mensuel (1er et 15 de chaque mois)
'''
"
| Métrique | TSMOM | 60/40 (benchmark) |
|---|---|---|
| CAGR | 16.8% | 8.5% |
| Sharpe | 1.10 | 0.62 |
| Max DD | -14.5% | -20.8% |
| Calmar | 1.16 | 0.41 |
| % en cash (moyen) | 25% | 0% |
| Positions moyennes | 18/50 | 2 |
Le TSMOM a un drawdown maximum nettement inférieur au 60/40 grâce à sa capacité à se mettre en cash quand les trends sont négatifs. C'est son principal avantage : il protège le capital en bear market.
Le Post-Earnings Announcement Drift est une anomalie documentée depuis 1968 (Ball & Brown). Quand une entreprise publie des résultats supérieurs aux attentes, le prix continue de monter pendant 20-60 jours après l'annonce. Le marché sous-réagit systématiquement aux surprises de résultats.
claude -p "Implémente PEADStrategy dans strategies/pead.py :
class PEADStrategy(BaseStrategy):
'''Post-Earnings Announcement Drift — acheter les surprises positives.
Chaque jour pendant la saison des earnings:
1. Scanner les résultats publiés hier soir / ce matin
2. Calculer la Standardized Unexpected Earnings (SUE):
SUE = (EPS_actual - EPS_consensus) / std(EPS_surprises_4Q)
3. Filtrer: SUE > 2.0 (surprise forte)
4. Confirmer avec le price action:
- Gap up > 3% à l'ouverture → confirme la surprise
- Volume > 2× la moyenne 20j → confirme l'intérêt
5. Entrer à 10:30 (30min après l'ouverture, laisser la volatilité se calmer)
6. Holding: 5-20 jours (optimisé par backtest: 10 jours optimal)
7. Stop: -5% depuis l'entrée (la surprise était un faux signal)
8. Take profit: +15% ou 20 jours, premier atteint
Univers: toutes les actions US/EU avec earnings ce trimestre
(typiquement 50-80 signaux par saison = ~200/an)
Sizing: 3% du NAV par position (petites positions car le hit rate
est de ~55% mais le payoff ratio est >2.5:1)
Anti-overlap:
- Max 5 positions PEAD simultanées
- Si corrélation > 0.7 avec une position existante: skip
'''
def scan_earnings(self, date) -> list[EarningsSignal]:
'''Scanne les résultats publiés et retourne les signaux qualifiés.
Sources: Yahoo Finance earnings API, Zacks, Estimize
'''
def backtest(self, start='2010-01-01', end='2025-12-31') -> BacktestResult:
'''Backtest event-driven (pas de rebalancement régulier).
Exécuté trade par trade.'''
"
| Métrique | PEAD |
|---|---|
| CAGR | 28.5% |
| Sharpe | 1.45 |
| Max DD | -18.2% |
| Win Rate | 55% |
| Avg Win / Avg Loss | 2.6 |
| Trades / an | ~200 |
| Avg holding | 10.3 jours |
| Saison earnings % | 85% des profits concentrés Jan-Feb et Jul-Aug |
Le PEAD est fortement saisonnier : 85% des profits sont générés pendant les 4 semaines de saison des résultats (janvier, avril, juillet, octobre). Entre les saisons, la stratégie est quasi inactive et le capital est réalloué aux autres stratégies par le méta-allocateur. C'est un excellent exemple de stratégie complémentaire : elle ne cannibalise pas le momentum car elle opère sur des horizons et des signaux complètement différents.
La rotation sectorielle exploite le fait que les secteurs ne performent pas tous au même moment du cycle économique. En expansion : Tech, Consumer Discretionary. En récession : Healthcare, Utilities. Notre stratégie identifie automatiquement la phase du cycle et se positionne en conséquence.
claude -p "Implémente IndustryRotationStrategy dans strategies/rotation.py :
class IndustryRotationStrategy(BaseStrategy):
'''Rotation sectorielle basée sur le cycle économique + momentum relatif.
Univers: 11 secteurs GICS via ETF (XLK, XLV, XLF, XLE, XLI, XLY, XLP, XLU, XLB, XLRE, XLC)
+ 3 ETF défensifs (GLD, TLT, SHY) en substitution quand aucun secteur n'est attractif.
Signal composite:
1. Relative Strength (40%):
RS_i = perf_3m(sector_i) / perf_3m(SPY)
→ Les secteurs qui battent le SPY sont attractifs
2. Breadth (30%):
breadth_i = % d'actions du secteur au-dessus de leur EMA50
→ Un secteur avec 80% de composants en tendance haussière est sain
3. Macro regime alignment (30%):
- Expansion (PMI > 50 + rising): Tech, Industrials, Consumer Disc
- Late cycle (PMI > 50 + falling): Energy, Materials, Healthcare
- Contraction (PMI < 50 + falling): Utilities, Consumer Staples, TLT
- Recovery (PMI < 50 + rising): Financials, Real Estate, Small-Caps
Portfolio:
- Top 3-4 secteurs par score composite
- Equal weight parmi les sélectionnés
- Rebalancement: mensuel
- Si aucun secteur n'est attractif (tous en RS < 0.95): 100% défensif (GLD+TLT+SHY)
'''
"
| Métrique | Industry Rotation | SPY (benchmark) |
|---|---|---|
| CAGR | 15.2% | 13.2% |
| Sharpe | 0.95 | 0.72 |
| Max DD | -18.5% | -33.9% |
| Calmar | 0.82 | 0.39 |
| % défensif | 22% du temps | 0% |
| Métrique | CSM seul | TSMOM seul | PEAD seul | Ind. Rot seul | Combiné 4 strat |
|---|---|---|---|---|---|
| CAGR | 24.3% | 16.8% | 28.5% | 15.2% | 32.8% |
| Sharpe | 1.35 | 1.10 | 1.45 | 0.95 | 1.62 |
| Max DD | -22.1% | -14.5% | -18.2% | -18.5% | -15.8% |
| Calmar | 1.10 | 1.16 | 1.57 | 0.82 | 2.08 |
La combinaison des 4 stratégies produit un Sharpe de 1.62 — supérieur à toute stratégie individuelle. Le max DD tombe à -15.8% — largement sous notre contrainte de 25%. C'est la magie de la décorrélation :
Et nous n'avons que 4 stratégies momentum ! Les Parties 7 et 8 ajoutent des stratégies mean-reversion et cross-asset avec des corrélations encore plus faibles, poussant le Sharpe combiné vers 1.8-2.0.
claude -p "Crée un notebook de validation anti-overfitting dans notebooks/validation_momentum.ipynb :
# Pour chaque stratégie, exécuter:
1. Walk-Forward Analysis (WFA):
- IS: 5 ans, OOS: 1 an, rolling
- 10 fenêtres de 2010 à 2025
- Critère: Sharpe OOS > 50% du Sharpe IS dans au moins 7/10 fenêtres
2. Combinatorial Purged Cross-Validation (CPCV):
- 10 splits, purge = 5 jours, embargo = 21 jours
- Distribution des Sharpe: percentile 5% > 0
- Deflated Sharpe Ratio (DSR) > 0.5
3. Regime robustness:
- Séparer les backtests par régime (Risk-On, Neutral, Risk-Off)
- Vérifier que le Sharpe est > 0 dans CHAQUE régime
- Le CAGR en Risk-Off peut être faible mais ne doit pas être négatif
4. Transaction cost sensitivity:
- Re-run avec slippage 2×, 3×, 5× la baseline
- Le Sharpe doit rester > 0.5 même avec slippage 3×
5. Parameter sensitivity:
- Varier chaque paramètre de ±30%
- Le Sharpe ne doit pas varier de plus de 20%
- Pas de 'cliff effect' (pas de paramètre critique)
Rapport final: une heatmap résumant pass/fail pour chaque test × stratégie.
"
Les stratégies momentum sont le moteur en Risk-On. Mais quand le marché corrige, elles souffrent. La Partie 7 construit les stratégies complémentaires qui performent en marché range-bound ou baissier : mean-reversion RSI et pairs trading statistique.