Turtle Trading System 2 : Un Backtest de 20 Ans sur 26 Marchés Futures
Quant Trading
Un backtest complet sur 20 ans du Turtle System 2 sur 26 marchés futures diversifiés — devises, taux, énergies, métaux, céréales, softs et bétail. Nous analysons les performances du système de 2006 à 2026, exposons ses faiblesses (6 ans de stagnation, Sharpe faible en bull market), et introduisons le Turtle Overlay : une approche de construction de portefeuille qui combine une base 75% SPX / 25% Cash avec le P&L décorrélé du Turtle par-dessus. Implémentation Python complète incluse, Jupyter Notebook téléchargeable.
Antoine
CEO - CodeMarketLabs
2026-04-17
Turtle Trading System 2 : Un Backtest de 20 Ans sur 26 Marchés Futures
En 1983, Richard Dennis fait un pari : n'importe qui peut apprendre à trader. Il recrute 23 personnes, leur remet un ensemble de règles simples, et les appelle les Turtle Traders. Certains ont généré des centaines de millions de dollars. Quarante ans plus tard, la question n'est plus de savoir si le système a fonctionné — mais comment le déployer dans un portefeuille moderne. Cet article présente un backtest complet sur 20 ans du Turtle System 2 sur 26 marchés futures diversifiés, une analyse honnête de ses forces et faiblesses, et trois configurations overlay — du cash pur à un split agressif 80/20 — pour montrer toute l'étendue de ce que la stratégie peut faire.
Ce que couvre cet article
Les trois règles du Turtle System 2 : entrée sur breakout 55 jours, sortie 20 jours, sizing basé sur l'ATR sur 26 marchés futures.
Un backtest complet de 2006 à 2026 sur devises, taux, énergies, métaux, céréales, softs et bétail.
Une analyse détaillée des trois stratégies overlay : Turtle seul (0/100), Turtle + 60/40, et Turtle + 80/20 — avec leurs paramètres exacts et leurs résultats.
Pourquoi la Stratégie 3 (80/20, risk_pct=0,9%) bat effectivement le SPY sur ce backtest — et ce que ça signifie en pratique.
Une implémentation Python complète sur un framework de backtest modulaire, avec courbe d'equity, panneau drawdown et dashboard de performance.
Un Jupyter Notebook téléchargeable avec le code complet, prêt à tourner sur les données Yahoo Finance.
1. La Stratégie : Trois Règles, 26 Marchés
Le Turtle System 2 est une stratégie de suivi de tendance pur. Les règles sont publiques depuis les années 1990. L'entrée se déclenche quand le prix de clôture casse le plus haut des 55 derniers jours (long) ou le plus bas (short) — en utilisant shift(1) sur la fenêtre glissante pour éliminer tout biais de look-ahead. La sortie intervient quand le prix revient au-delà du plus haut ou plus bas des 20 derniers jours. La taille de position est fixée par l'ATR sur 20 jours : unit_size = (capital × risk_pct) / ATR20. Chaque unité risque un montant dollar identique quel que soit le marché tradé — un mouvement de 5 $ sur le maïs et 5 $ sur le brut portent le même poids dans le portefeuille.
Le pyramidage ajoute jusqu'à 3 unités supplémentaires par marché quand le trade progresse, chaque fois que le prix avance de 0,5 × ATR depuis la dernière entrée. Chaque entrée pyramidale porte son propre stop-loss à 2 × ATR. Les limites d'exposition évitent la concentration : maximum 4 unités par marché, 6 par catégorie, 10 par direction, et 12 au total sur les 26 marchés. Le système tourne entièrement en automatique — aucune intervention discrétionnaire.
tableau-tickers-categories-contrats-futures
python
# ── Téléchargement des données ────────────────────────────────PERIOD ="20y"EXCLUDE =set()# ajouter des noms ici pour exclure des marchésACTIVE_FUTURES ={k: v for k, v in FUTURES.items()if k notin EXCLUDE}tickers =[v["ticker"]for v in ACTIVE_FUTURES.values()]raw = yf.download(tickers, period=PERIOD, interval="1d", progress=True, auto_adjust=True)["Close"]raw.index = pd.to_datetime(raw.index).tz_localize(None)ticker_to_name ={v["ticker"]: k for k, v in ACTIVE_FUTURES.items()}raw.columns =[ticker_to_name.get(c, c)for c in raw.columns]data = raw.dropna()print(f"Période : {data.index[0].date()} → {data.index[-1].date()}")print(f"Nb Jours : {len(data)} | Marchés : {len(data.columns)}")# ── SPY et ^IRX (taux T-bill comme proxy du cash) ────────────spx_raw = yf.download("SPY", period=PERIOD, progress=False, auto_adjust=True)["Close"]ifisinstance(spx_raw, pd.DataFrame): spx_raw = spx_raw.iloc[:,0]spx_raw.index = pd.to_datetime(spx_raw.index).tz_localize(None)spx_raw = spx_raw.dropna()cash_raw = yf.download("^IRX", period=PERIOD, progress=False, auto_adjust=True)["Close"]ifisinstance(cash_raw, pd.DataFrame): cash_raw = cash_raw.iloc[:,0]cash_raw.index = pd.to_datetime(cash_raw.index).tz_localize(None)cash_raw = cash_raw.dropna()# ── Alignement sur le même calendrier de trading ─────────────common_start =max(data.index[0], spx_raw.index[0], cash_raw.index[0])data = data[data.index >= common_start]spx = spx_raw.reindex(data.index, method="ffill")irx = cash_raw.reindex(data.index, method="ffill").fillna(0)daily_rfr = irx /100/252# taux annualisé % → taux journalierprint(f"Période alignée : {data.index[0].date()} → {data.index[-1].date()}")
2. Stratégie 1 — Turtle Seul (0% SPX / 100% Cash)
La baseline : 1 000 000 $ entièrement en cash (taux T-bill via ^IRX), et le Turtle tourne par-dessus en utilisant uniquement les marges futures. Aucune exposition actions. C'est la lecture la plus pure du système — P&L trend-following plus rendement du cash, rien d'autre.
La première décennie raconte une histoire convaincante. En 2008, pendant que le SPY perd 50%, le Turtle shorte les marchés en chute et est long sur les obligations en hausse. La courbe d'equity monte jusqu'à près de 3M$ en 2014. Puis la réalité frappe : de 2015 à 2020, le système stagne pendant six ans. Faible volatilité macro, matières premières en range, taux quasi nuls — exactement les conditions qui tuent le suivi de tendance. La courbe s'aplatit pendant que le SPY gagne 150%. Ce n'est pas un bug. C'est le coût structurel d'une stratégie qui a besoin de grands mouvements soutenus pour survivre. La vraie question n'est pas de savoir si elle se redresse — elle se redresse. La question c'est : est-ce que vous tenez six ans de sous-performance sans couper la stratégie au pire moment ?
turtle-overlay-suivi-de-tendance-pur
python
# ── Paramètres Stratégie 1 ────────────────────────────────────INITIAL_CAP =1_000_000W_SPX =0.0# 0% en SPYW_CASH =1- W_SPX # 100% en cash (^IRX)REBAL_FREQ ="monthly"TURTLE_SYSTEM =2# System 2 = breakout 55 joursTURTLE_RISK_PCT =0.0050# 0,5% du capital risqué par unité# ── Portefeuille de base (cash pur) ───────────────────────────base = compute_basis_portfolio(spx, daily_rfr, INITIAL_CAP, w_spx=W_SPX, rebal_freq=REBAL_FREQ)print(f"Valeur finale du portefeuille de base : ${base.iloc[-1]:,.0f}")# ── Exécution du Turtle ───────────────────────────────────────engine = SpotPricingEngine(data)bt = TurtleStrategy(data=data, initial_capital=INITIAL_CAP, system=TURTLE_SYSTEM, risk_pct=TURTLE_RISK_PCT, futures_dict=ACTIVE_FUTURES)turtle_equity = bt.run(data, engine, verbose=False)["equity"]# ── Overlay : base + P&L incrémental Turtle ───────────────────turtle_pnl = turtle_equity - INITIAL_CAP
combined = base + turtle_pnl.reindex(base.index, method="ffill").fillna(0)# ── Métriques ─────────────────────────────────────────────────spx_full =(spx / spx.iloc[0])* INITIAL_CAP
print(f"\n{'='*65}")dd_base = metrics(base, INITIAL_CAP,"0% SPX / 100% Cash (base)")dd_turtle = metrics(turtle_equity, INITIAL_CAP,"Turtle seul")dd_combined = metrics(combined, INITIAL_CAP,"Turtle Overlay on 0/100")_ = metrics(spx_full, INITIAL_CAP,"SPY B&H")print(f"{'='*65}")
3. Stratégie 2 — Turtle + 60/40
L'allocation institutionnelle classique — 60% SPY, 40% cash — avec le Turtle par-dessus. Le Turtle utilise toujours uniquement les marges futures, donc le buffer de 40% en cash est largement suffisant pour les couvrir. L'insight clé : vous ne choisissez pas entre l'allocation actions et le Turtle. Les exigences de marge futures laissent la grande majorité du capital libre pour l'investir ailleurs. C'est le concept de Portable Alpha en pratique.
L'overlay 60/40 absorbe mieux les crashs de 2008 et 2020 qu'un buy-and-hold SPY pur, parce que le Turtle est long sur les instruments qui montent pendant ces crises — obligations, or, futures actions short. Dans la période 2015–2020 de stagnation du Turtle, les 60% en SPY maintiennent le portefeuille en progression. Le résultat est une courbe d'equity plus lisse que chaque stratégie seule, avec un Sharpe qui justifie la complexité ajoutée.
turtle-overlay-60-spx-40-cash
python
# ── Paramètres Stratégie 2 ────────────────────────────────────INITIAL_CAP =1_000_000W_SPX =0.6# 60% en SPYW_CASH =1- W_SPX # 40% en cashREBAL_FREQ ="monthly"TURTLE_SYSTEM =2TURTLE_RISK_PCT =0.0050# même 0,5% de risque par unité qu'en Stratégie 1base = compute_basis_portfolio(spx, daily_rfr, INITIAL_CAP, w_spx=W_SPX, rebal_freq=REBAL_FREQ)print(f"Valeur finale du portefeuille de base : ${base.iloc[-1]:,.0f}")engine = SpotPricingEngine(data)bt = TurtleStrategy(data=data, initial_capital=INITIAL_CAP, system=TURTLE_SYSTEM, risk_pct=TURTLE_RISK_PCT, futures_dict=ACTIVE_FUTURES)turtle_equity = bt.run(data, engine, verbose=False)["equity"]turtle_pnl = turtle_equity - INITIAL_CAP
combined = base + turtle_pnl.reindex(base.index, method="ffill").fillna(0)spx_full =(spx / spx.iloc[0])* INITIAL_CAP
print(f"\n{'='*65}")dd_base = metrics(base, INITIAL_CAP,"60% SPX / 40% Cash (base)")dd_turtle = metrics(turtle_equity, INITIAL_CAP,"Turtle seul")dd_combined = metrics(combined, INITIAL_CAP,"Turtle Overlay on 60/40")_ = metrics(spx_full, INITIAL_CAP,"SPY B&H")print(f"{'='*65}")
4. Stratégie 3 — Turtle + 80/20 (Agressive)
La Stratégie 3 monte le poids actions à 80% et augmente le risk_pct Turtle à 0,9% — presque le double de la Stratégie 2. Le buffer cash réduit à 20% laisse moins de marge pour les appels de marge, donc le risk_pct plus élevé compense en sizant les positions de manière plus agressive sur le capital disponible. C'est la version qui, sur ce backtest de 20 ans, finit par battre le SPY buy-and-hold en rendement absolu.
Un mot d'honnêteté : battre le SPY sur une fenêtre spécifique de 20 ans ne signifie pas que cette configuration gagnera toujours. Le risk_pct à 0,9% produit des drawdowns plus importants quand le Turtle se trompe, et ces drawdowns s'additionnent au drawdown actions des 80% SPX. La période 2008 est particulièrement brutale pour cette configuration. La surperformance est réelle sur ce backtest, mais le chemin pour y arriver est nettement plus chaotique que le SPY pur. Le Sharpe est plus faible, le drawdown maximum est plus élevé. C'est un profil rendement plus élevé / volatilité plus élevée — pas un repas gratuit.
turtle-overlay-80-spx-20-cash
python
# ── Paramètres Stratégie 3 ────────────────────────────────────INITIAL_CAP =1_000_000W_SPX =0.8# 80% en SPYW_CASH =1- W_SPX # 20% en cashREBAL_FREQ ="monthly"TURTLE_SYSTEM =2TURTLE_RISK_PCT =0.00900# 0,9% — plus agressif pour compenser le buffer réduitbase = compute_basis_portfolio(spx, daily_rfr, INITIAL_CAP, w_spx=W_SPX, rebal_freq=REBAL_FREQ)print(f"Valeur finale du portefeuille de base : ${base.iloc[-1]:,.0f}")# Benchmark cash pur pour le dashboard de performancerfr = compute_basis_portfolio(spx, daily_rfr, INITIAL_CAP, w_spx=0, rebal_freq=REBAL_FREQ)engine = SpotPricingEngine(data)bt = TurtleStrategy(data=data, initial_capital=INITIAL_CAP, system=TURTLE_SYSTEM, risk_pct=TURTLE_RISK_PCT, futures_dict=ACTIVE_FUTURES)turtle_equity = bt.run(data, engine, verbose=False)["equity"]turtle_pnl = turtle_equity - INITIAL_CAP
combined = base + turtle_pnl.reindex(base.index, method="ffill").fillna(0)spx_full =(spx / spx.iloc[0])* INITIAL_CAP
print(f"\n{'='*65}")dd_base = metrics(base, INITIAL_CAP,"80% SPX / 20% Cash (base)")dd_turtle = metrics(turtle_equity, INITIAL_CAP,"Turtle seul")dd_combined = metrics(combined, INITIAL_CAP,"Turtle Overlay on 80/20")_ = metrics(spx_full, INITIAL_CAP,"SPY B&H")print(f"{'='*65}")
5. Dashboard de Performance Complet
La dernière cellule du notebook assemble un dashboard de performance complet via la librairie equity_curve, en utilisant le DataFrame de comparaison de la Stratégie 3. Il produit le CAGR glissant, le Sharpe glissant, la volatilité glissante, la matrice de corrélation, et les top 3 périodes de drawdown annotées — tout ce dont vous avez besoin pour évaluer si la stratégie combinée tient au-delà de la simple comparaison des courbes d'equity.
tableau-de-bord-analytique-backtest-complet
python
from equity_curve.graphs import dashboard
from equity_curve.performances import Performances
from equity_curve.utils.financial_ts import PortfolioTs
# DataFrame de comparaison — contexte Stratégie 3comparison = pd.DataFrame({"strategy": combined,# overlay Turtle sur 80/20"base_75_25": base,# base 80/20 sans Turtle"turtle": turtle_equity,# Turtle seul"benchmark": spx_full,# SPY B&H"risk_free": rfr,# cash pur (^IRX)}, index=base.index)print("\n5 dernières lignes :")print(comparison.tail(5).to_string())portfolio = PortfolioTs(comparison)perf = Performances( strat=portfolio, computation_date=datetime(2026,4,16), period_per_year=252)fig = dashboard( perf, window_roll=180,# fenêtre glissante de 180 jours top_dd=3,# annoter les 3 principaux drawdowns mode='dark', title='Global Portfolio Strategy')fig.show()
6. Trois Stratégies, Une Conclusion
Les trois stratégies répondent à des questions différentes. La Stratégie 1 (0/100) demande : comment le Turtle performe-t-il en isolation complète ? La réponse : bien dans les régimes de crise, mal dans les bull markets prolongés, avec un Sharpe difficile à justifier en standalone. La Stratégie 2 (60/40) demande : est-ce que le Turtle améliore un portefeuille équilibré classique ? La réponse est oui — drawdowns plus lisses en 2008 et 2020, meilleurs rendements ajustés du risque sur la période complète, et un coût marginal seulement pendant la phase 2015–2020. La Stratégie 3 (80/20, risk_pct=0,9%) demande : que se passe-t-il si on maximise à la fois le beta actions et l'exposition trend-following ? La réponse est une configuration qui surperforme le SPY en rendement absolu sur ce backtest — mais avec un drawdown plus élevé, un Sharpe plus faible, et un profil psychologique beaucoup plus exigeant.
La conclusion pratique n'est pas que la Stratégie 3 est supérieure. C'est que le Turtle Overlay est un outil flexible — les paramètres W_SPX et TURTLE_RISK_PCT vous permettent de régler le compromis entre rendement type actions et protection en crise n'importe où sur le spectre. Le notebook rend triviale la ré-exécution des trois configurations pour les comparer directement.
Image non trouvée (ID: youtube_thumbnail_clickable)
Télécharger le Jupyter Notebook
Le backtest complet est disponible sous forme de Jupyter Notebook. Il contient l'implémentation complète de TurtleStrategy, les trois stratégies overlay avec leurs blocs de paramètres exacts, le calcul de la courbe d'equity et du drawdown, et le dashboard de performance complet. Le code tourne directement sur les données Yahoo Finance. Modifiez W_SPX, TURTLE_RISK_PCT ou REBAL_FREQ et relancez n'importe quelle stratégie en quelques secondes.
Ce que contient le Notebook
Classe TurtleStrategy complète : breakout 55 jours, sortie 20 jours, sizing ATR, pyramidage jusqu'à 4 unités, et limites d'exposition appliquées à chaque barre.
Trois blocs de stratégie complets : Turtle seul (0/100, risk_pct=0,5%), Turtle + 60/40 (risk_pct=0,5%), et Turtle + 80/20 (risk_pct=0,9%).
Fonction de portefeuille de base : poids SPX configurable et fréquence de rebalancement — mensuel, trimestriel ou annuel.
Dashboard de performance via equity_curve : CAGR glissant, Sharpe, volatilité, top drawdowns annotés et matrice de corrélation.
Prêt à tourner sur les données Yahoo Finance — 20 ans, 26 marchés, aucun flux de données propriétaire nécessaire.
Quelles sont les règles exactes d'entrée et de sortie du Turtle System 2 ?
L'entrée se déclenche quand le prix de clôture casse le plus haut des 55 derniers jours (long) ou le plus bas (short). Les deux utilisent shift(1) sur la fenêtre glissante pour éviter le biais de look-ahead — le signal du jour est toujours basé sur les niveaux d'hier. La sortie intervient quand le prix revient au-delà du plus haut des 20 derniers jours (pour les shorts) ou plus bas (pour les longs). La taille de position est calculée comme (capital × risk_pct) / ATR20, où ATR20 est la moyenne sur 20 jours de la variation absolue de prix journalière.
Pourquoi le risk_pct est-il différent entre la Stratégie 2 (0,5%) et la Stratégie 3 (0,9%) ?
La Stratégie 3 n'alloue que 20% du capital au cash, contre 40% en Stratégie 2. Avec moins de buffer cash disponible pour les marges futures, le sizing doit être plus agressif sur le capital déployé dans le Turtle pour générer une contribution overlay significative. Le risk_pct à 0,9% compense approximativement le capital de marge réduit tout en maintenant le risque dollar absolu par unité dans une plage similaire.
La Stratégie 3 bat le SPY sur ce backtest — ça veut dire que c'est la meilleure ?
Pas nécessairement. La fenêtre de 20 ans inclut deux crises majeures (2008, 2020) où le Turtle contribue significativement, ce qui booste le rendement long terme de l'overlay 80/20 au-dessus du SPY. Mais la Stratégie 3 a aussi un drawdown maximum plus élevé et un ratio de Sharpe plus faible que le SPY sur la même période. Elle gagne en rendement absolu tout en perdant en rendement ajusté du risque. Que ce soit un bon compromis dépend entièrement de votre capacité à tenir des drawdowns importants et prolongés sans abandonner la stratégie.
Qu'est-ce que le Portable Alpha et pourquoi est-ce important ici ?
Le Portable Alpha désigne la séparation entre génération d'alpha et exposition beta. Les contrats futures ne nécessitent que 10 à 20% de leur valeur notionnelle en marge. Un compte de 1 000 000 $ qui fait tourner le Turtle sur 26 marchés utilise environ 150 000 $ à 200 000 $ en marge à tout moment. Le capital restant peut être investi en SPY sans conflit. Le P&L Turtle est simplement ajouté sur la série d'equity du portefeuille de base. Vous obtenez le beta actions et l'alpha trend-following depuis le même pool de capital.
Pourquoi le système stagne-t-il de 2015 à 2020 ?
Les systèmes de suivi de tendance nécessitent des mouvements directionnels soutenus sur les marchés. La période 2015–2020 a combiné une faible volatilité macro, des marchés de matières premières en range, et des taux quasi nuls qui ont supprimé les tendances sur les devises et les taux. Le système a généré de fréquents faux breakouts — des entrées qui se retournent rapidement et déclenchent la sortie en stop à perte. C'est le coût structurel : perdre petit sur de nombreux trades, gagner gros sur les rares tendances soutenues. Quand les tendances sont absentes simultanément sur les 26 marchés, les coûts s'accumulent et la courbe s'aplatit.
Puis-je modifier les marchés ou les paramètres dans le notebook ?
Oui. Chaque bloc de stratégie expose TURTLE_SYSTEM (1 ou 2), TURTLE_RISK_PCT, W_SPX et REBAL_FREQ en variables de premier niveau. Vous pouvez ajouter des marchés au dictionnaire FUTURES avec n'importe quel ticker futures Yahoo Finance, ou exclure des marchés spécifiques en ajoutant leur nom à l'ensemble EXCLUDE. Passer REBAL_FREQ de mensuel à annuel a un effet significatif sur les rendements du portefeuille de base et mérite d'être exploré.
Le backtest tient-il compte des frais de transaction ?
Oui — des frais fixes de 2 $ sont appliqués à l'entrée et à la sortie pour chaque signal de trade. Cela approxime les commissions aller-retour institutionnelles. Le spread bid-ask et le slippage de roll des futures ne sont pas modélisés. Les coûts de roll sont implicitement absorbés par les séries de prix continus ajustés de Yahoo Finance, bien que pour les contrats moins liquides comme Lean Hogs ou Cocoa le slippage réel soit plus élevé que ce que le backtest capture.