Strasmore Research
Apprendre Matt ConnorPar Matt Connor · Mis à jour le 2026-08-08

Maximum drawdown : baisse, profondeur et récupération

Le maximum drawdown mesure la plus forte baisse entre un sommet et un point bas. Découvrez sa profondeur et pourquoi le retour à un nouveau sommet prend plus de temps.

Le maximum drawdown correspond à la plus forte baisse entre un sommet et un point bas d’une série de valeurs, exprimée en pourcentage du sommet atteint jusque-là. Un compte qui monte à 120 000 dollars, tombe à 84 000 dollars, puis se redresse affiche un maximum drawdown de 30 %. Ce chiffre reste inchangé, car la statistique enregistre la pire phase de l’historique, et non la situation actuelle. La plupart des investisseurs citent uniquement l’ampleur de la baisse. Pourtant, cette même statistique contient deux autres mesures : le temps écoulé entre le sommet et le point bas, puis la période, souvent bien plus longue, nécessaire pour revenir de ce point bas à un nouveau sommet.

Comment calculer le maximum drawdown ?

Le calcul s’effectue en un seul passage sur la série. À chaque observation, vous actualisez le plus-haut courant, mesurez la valeur actuelle par rapport à celui-ci et conservez la baisse la plus marquée observée jusque-là.

  1. Définissez le pic courant comme la première valeur.
  2. À chaque nouvelle valeur, relevez le pic si la valeur est supérieure.
  3. Calculez alors le drawdown : valeur divisée par le pic, moins un.
  4. Conservez la valeur la plus négative. Il s’agit du maximum drawdown.

Aucune série de rendements, aucune estimation de la volatilité et aucune hypothèse de distribution n’intervient. La boucle s’exécute sur une simple liste de nombres avec la bibliothèque standard Python. Sur une nouvelle installation d’Ubuntu, installez d’abord l’interpréteur :

apt-get update && apt-get install -y python3

Enregistrez la boucle sous maxdd.py. Les cours ci-dessous constituent une série fictive de ten points, suffisamment courte pour être vérifiée manuellement :

prices = [100.0, 104.0, 98.0, 92.0, 95.0, 88.0, 90.0, 101.0, 99.0, 106.0]

peak = prices[0]
max_dd = 0.0

for price in prices:
    if price > peak:
        peak = price
    drawdown = price / peak - 1.0
    if drawdown < max_dd:
        max_dd = drawdown

print(f"maximum drawdown: {max_dd * 100:.1f}%")

Exécutez python3 maxdd.py. Le programme affiche maximum drawdown: -15.4%. Vérifiez le résultat manuellement : le pic avant le point bas est de 104, le point bas est de 88 et 88 divisé par 104 donne 0,846. La série se termine ensuite à 106, un plus-haut historique, mais le drawdown de 15,4 % reste inchangé. Le maximum drawdown constitue une mesure définitive du pire moment observé dans un échantillon. Il n’indique pas où se situe la série aujourd’hui. Deux variables supplémentaires dans la même boucle permettent de situer cet épisode dans le temps : l’indice auquel le pic a été atteint et l’indice auquel la baisse maximale a été observée.

À quoi ressemble une courbe de drawdown

Une courbe de drawdown conserve l’étape 3 à chaque point, au lieu de la réduire à une seule valeur correspondant au pire niveau. La courbe reste à zéro lorsque la série inscrit un nouveau plus-haut. Elle passe sous zéro entre deux plus-hauts. C’est pourquoi cet écart est qualifié d’« underwater ». Voici cette courbe pour SPY, un ETF répliquant le S&P 500, à partir des clôtures de fin de mois depuis janvier 2016.

RequêteCourbe underwater de SPY : clôture de fin de mois par rapport à son plus-haut glissant, 2016 à 2026
Le SQL exact derrière chaque chiffre
WITH monthly AS (
    SELECT toStartOfMonth(toDate(toTimeZone(window_start, 'America/New_York'))) AS month_start,
           argMax(toFloat64(close), window_start) AS close_px
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'SPY'
      AND toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2016-01-01')
      AND toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-07-31')
      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
           + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
    GROUP BY month_start
),
runs AS (
    SELECT month_start,
           close_px,
           max(close_px) OVER (ORDER BY month_start
                               ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS running_peak
    FROM monthly
)
SELECT formatDateTime(month_start, '%Y-%m') AS month,
       round(100 * (close_px / running_peak - 1), 2) AS drawdown_pct
FROM runs
ORDER BY month_start
Run this yourself

Sur 127 observations de fin de mois, la courbe reste longtemps proche de zéro, puis plonge dans quelques creux marqués. Le dernier mois disponible ressort à -1.27% par rapport au plus-haut atteint depuis le début de la période. Deux caractéristiques de la courbe sont particulièrement instructives. Les phases de récupération prennent la forme de progressions lentes, plutôt que de rebonds rapides. Chaque nouveau plus-haut ramène ensuite la courbe à zéro et efface visuellement la trace de ce qui précédait.

Combien de temps faut-il pour se remettre d’un drawdown ?

Un même drawdown recouvre trois chiffres distincts. Les confondre est l’erreur d’interprétation la plus fréquente dans un tableau de performance :

  1. Ampleur : la baisse de la valeur par rapport à son point haut, en pourcentage.
  2. Temps jusqu’au point bas : nombre de jours calendaires entre le point haut et le point bas.
  3. Temps de récupération : nombre de jours calendaires entre le point bas et un nouveau point haut.

Le troisième est généralement le plus long. C’est aussi celui qu’un chiffre présenté en titre ne montre jamais. Le tableau ci-dessous reconstitue chaque période sous l’eau achevée pour SPY depuis 2016, à partir des cours de clôture quotidiens. Une période commence le jour où un point haut est atteint et se termine le jour où le fonds clôture pour la première fois au-dessus de ce niveau.

RequêteDrawdowns de SPY terminés depuis 2016 : profondeur, jours de baisse, jours de récupération
Le SQL exact derrière chaque chiffre
WITH daily AS (
    SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS session_date,
           argMax(toFloat64(close), window_start) AS close_px
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'SPY'
      AND toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2016-01-01')
      AND toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-07-31')
      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
           + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
    GROUP BY session_date
),
runs AS (
    SELECT session_date,
           close_px,
           max(close_px) OVER (ORDER BY session_date
                               ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS running_peak
    FROM daily
),
episodes AS (
    SELECT running_peak AS peak_px,
           min(session_date) AS peak_date,
           argMin(session_date, close_px) AS trough_date,
           min(close_px) AS trough_px
    FROM runs
    GROUP BY running_peak
),
sequenced AS (
    SELECT peak_px,
           peak_date,
           trough_date,
           trough_px,
           leadInFrame(peak_date, 1) OVER (ORDER BY peak_date
                                           ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) AS recovery_date
    FROM episodes
)
SELECT formatDateTime(peak_date, '%b %Y') AS episode_label,
       round(100 * (1 - trough_px / peak_px), 1) AS fall_from_peak_pct,
       dateDiff('day', peak_date, trough_date) AS days_to_trough,
       dateDiff('day', trough_date, recovery_date) AS days_to_new_high,
       dateDiff('day', peak_date, recovery_date) AS days_underwater
FROM sequenced
WHERE recovery_date > trough_date
  AND round(100 * (1 - trough_px / peak_px), 1) >= 5
ORDER BY fall_from_peak_pct DESC
LIMIT 8
Run this yourself

La période achevée la plus profonde de la liste commence en Feb 2020 et atteint 34.2% sous le précédent point haut. La baisse a duré 33 jours calendaires, puis le retour au point haut 148 jours, soit 181 jours au total sous l’eau. L’entrée suivante, à partir de Jan 2022, est moins profonde, à 25.4%, mais le fonds est resté sous son ancien point haut pendant 746 jours.

L’ampleur et la durée peuvent évoluer de manière totalement différente. Une chute brutale suivie d’un retour rapide et une baisse modérée qui s’étale sur plusieurs années se réduisent pourtant à un seul pourcentage. Le krach de mars 2020 illustre parfaitement le premier cas, tandis que la manière dont les marchés se remettent des krachs décrit la seconde phase du mouvement.

Pourquoi le maximum drawdown s’aggrave quand la période de mesure s’allonge

Le maximum drawdown est un maximum : l’ajout d’un historique ne peut donc que le laisser inchangé ou l’accentuer. À chaque instant, le plus-haut enregistré sur une fenêtre longue est au moins aussi élevé que celui d’une fenêtre courte. Le calcul l’impose. La mesure d’un même fonds sur cinq fenêtres se terminant toutes le 31 juillet 2026 illustre cet effet.

RequêteMême fonds, cinq fenêtres d’observation : drawdown maximum de SPY selon la longueur de l’échantillon au 31 juillet 2026
Le SQL exact derrière chaque chiffre
WITH daily AS (
    SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS session_date,
           argMax(toFloat64(close), window_start) AS close_px
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'SPY'
      AND toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2016-07-01')
      AND toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-07-31')
      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
           + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
    GROUP BY session_date
),
scoped AS (
    SELECT arrayJoin([1, 2, 3, 5, 10]) AS lookback_years,
           session_date,
           close_px
    FROM daily
),
windowed AS (
    SELECT lookback_years, session_date, close_px
    FROM scoped
    WHERE session_date >= subtractYears(toDate('2026-07-31'), lookback_years)
),
runs AS (
    SELECT lookback_years,
           session_date,
           close_px,
           max(close_px) OVER (PARTITION BY lookback_years ORDER BY session_date
                               ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS running_peak
    FROM windowed
)
SELECT concat(toString(lookback_years), if(lookback_years = 1, ' year', ' years')) AS lookback,
       round(100 * max(1 - close_px / running_peak), 1) AS max_drawdown_pct,
       formatDateTime(argMax(session_date, 1 - close_px / running_peak), '%b %Y') AS worst_point
FROM runs
GROUP BY lookback_years
ORDER BY lookback_years
Run this yourself

Sur la fenêtre glissante de 1 year, la baisse maximale mesurée atteignait 9.1%. En étendant la même série à 10 years, le chiffre passe à 34.2%, avec un point bas atteint en Mar 2020. Le fonds n’est pas devenu plus risqué. L’échantillon est simplement plus long.

Le même calcul fausse les comparaisons entre stratégies. Un backtest sur trois ans et un backtest sur vingt ans peuvent décrire un comportement identique tout en affichant des drawdowns très différents. Le chiffre n’a donc guère de sens sans la fenêtre de mesure associée. Le look-ahead bias dans les backtests présente une autre manière dont un backtest d’apparence rigoureuse peut se mettre en valeur.

Drawdown maximal et volatilité

La volatilité mesure l’ampleur habituelle d’une variation quotidienne, à la hausse comme à la baisse. Le drawdown maximal mesure une trajectoire baissière précise. Ce sont deux indicateurs de risque, qui répondent à des questions différentes. Le tableau les présente côte à côte pour huit valeurs très suivies sur les cinq années arrêtées au 31 juillet 2026, avec une volatilité annualisée calculée à partir des cours de clôture quotidiens.

RequêteDrawdown maximum par rapport à la volatilité annualisée : huit grandes capitalisations, cinq ans au 31 juillet 2026
Le SQL exact derrière chaque chiffre
WITH daily AS (
    SELECT ticker,
           toDate(toTimeZone(window_start, 'America/New_York')) AS session_date,
           argMax(toFloat64(close), window_start) AS close_px
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker IN ('SPY', 'AAPL', 'MSFT', 'KO', 'JNJ', 'CVX', 'VZ', 'PG')
      AND toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2021-08-01')
      AND toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-07-31')
      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
           + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
    GROUP BY ticker, session_date
),
runs AS (
    SELECT ticker,
           session_date,
           close_px,
           max(close_px) OVER (PARTITION BY ticker ORDER BY session_date
                               ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS running_peak,
           lagInFrame(close_px, 1) OVER (PARTITION BY ticker ORDER BY session_date
                                         ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS prev_close
    FROM daily
)
SELECT ticker,
       round(100 * max(1 - close_px / running_peak), 1) AS max_drawdown_pct,
       round(100 * sqrt(252) * stddevSampIf(close_px / prev_close - 1, prev_close > 0), 1) AS annualized_volatility_pct
FROM runs
GROUP BY ticker
HAVING countIf(prev_close > 0) > 20
ORDER BY max_drawdown_pct DESC
Run this yourself

Lisez les deux colonnes ensemble. VZ affiche la baisse la plus marquée du groupe, à 45.4%, contre une volatilité annualisée de 22.6%. À l’autre extrémité, KO a reculé de 20.9%, avec une volatilité de 16.7%. La volatilité est une moyenne calculée sur chaque journée de la période, et les moyennes atténuent l’effet d’une longue baisse progressive. Le drawdown correspond à la pire trajectoire effectivement suivie par le cours. Une valeur peu volatile qui dérive à la baisse pendant deux ans peut donc afficher un drawdown marqué tout en conservant une volatilité peu remarquable.

L’anomalie de faible volatilité examine le comportement des valeurs les plus calmes sur de longues périodes, tandis que le dimensionnement des positions selon le critère de Kelly montre comment une tolérance au drawdown se traduit en taille de position.

Ce que ce chiffre ne permet pas de savoir

Quatre limites méritent d’être gardées à l’esprit :

  1. Il correspond à une trajectoire réalisée. Le même processus aurait pu produire un chiffre bien plus mauvais avec un autre tirage.
  2. Il dépend de la longueur de l’échantillon. Deux drawdowns ne se comparent que sur des fenêtres de même durée.
  3. Il dépend de la fréquence d’échantillonnage. Les cours de clôture de fin de mois masquent les points bas intrajournaliers et donnent un chiffre inférieur à celui obtenu avec les clôtures quotidiennes sur la même période.
  4. Il ne contient aucune information prospective. Se situer 30 % sous un pic ne dit rien sur la date à laquelle le 31e point sera atteint.

Cette dernière limite explique pourquoi un système automatisé a besoin d’une politique de drawdown, et non d’un simple seuil de drawdown. « Arrêt à 20 % » répond à une question, mais en laisse deux autres sans réponse : que deviennent les positions ouvertes au moment de l’arrêt, et quels éléments justifient la remise en marche du système ? Disjoncteurs pour les bots de trading examine la structure de cette politique. Le coût d’une règle arbitraire et uniforme se fait sentir lors de la phase de reprise : un système qui s’arrête près du point bas et redémarre tard reste à l’écart pendant la remontée. Rater les meilleures séances chiffre cette mécanique.

Un détail de mesure compte avant de comparer deux chiffres : le drawdown calculé sur la série de cours d’un fonds et celui calculé sur un compte réel diffèrent dès que des liquidités entrent sur le compte ou en sortent, et dès que des dividendes sont versés. comment sont mesurés les rendements mensuels couvre ce point en détail.

FAQ sur le drawdown maximal

Quel est un bon drawdown maximal ?

Il n’existe pas de valeur universelle, mais seulement une référence et une période de mesure. Sur les dix années closes au 31 juillet 2026, la pire baisse de SPY depuis un plus-haut glissant, mesurée sur les clôtures quotidiennes, s’est établie à 34.2%. Une stratégie affichant un chiffre inférieur sur une période plus courte n’a pas nécessairement été plus sûre.

Le drawdown maximal est-il identique à la volatilité ?

Non. La volatilité décrit l’amplitude quotidienne habituelle des mouvements. Le drawdown maximal décrit le pire parcours entre un plus-haut et un point bas. Un actif peu volatil qui baisse régulièrement pendant deux ans peut afficher un drawdown plus profond qu’un actif très irrégulier qui inscrit régulièrement de nouveaux plus-hauts.

Combien de temps faut-il pour se remettre d’un drawdown maximal ?

Cela varie, et la remontée constitue souvent la moitié la plus longue. Pour SPY depuis 2016, la plus longue période achevée sous un précédent plus-haut a duré 181 jours calendaires entre le sommet et le retour à un nouveau plus-haut. Sur cette période, 33 jours ont été consacrés à la baisse.

Le drawdown maximal permet-il de prévoir les pertes futures ?

Non. Il décrit un parcours déjà réalisé, et une période d’observation plus longue produit presque toujours un chiffre plus élevé. Il mesure ce qu’une stratégie a supporté jusqu’à présent, sans préjuger de ce qui peut survenir ensuite.


Chaque panneau ci-dessus conserve la requête SQL correspondante. Ouvrez-en un, remplacez le ticker ou la période, puis appliquez le même calcul du drawdown sur le terminal Strasmore.

#risk#drawdown#backtesting#performance metrics#python