Strasmore Research
Навчання Matt ConnorВід Matt Connor · Оновлено 2026-08-05

Максимальна просадка: глибина та відновлення

Дізнайтеся, як рахують максимальну просадку, що вважається глибоким падінням і чому шлях від мінімуму до нового максимуму може тривати довше.

Максимальна просадка — це найбільше падіння показника від пікового значення до мінімуму, виражене у відсотках від попереднього максимуму. Якщо вартість рахунку зростає до $120,000, знижується до $84,000, а потім відновлюється, максимальна просадка становить 30%. Це значення зберігається назавжди, оскільки показник фіксує найгірший період за всю історію, а не поточний стан.

Більшість учасників ринку називають лише глибину просадки. Але в цій самій метриці є ще два показники: час від піку до мінімуму та значно довший період від мінімуму до нового максимуму.

Як розраховують максимальну просадку?

Увесь розрахунок виконується за один прохід по ряду. На кожному спостереженні оновлюється поточний максимум, поточне значення порівнюється з ним, а потім зберігається найгірший результат із усіх отриманих.

  1. Встановіть поточний максимум на рівні першого значення.
  2. Для кожного нового значення підвищуйте максимум, якщо нове значення вище.
  3. Розрахуйте просадку в цій точці: значення поділіть на максимум і відніміть одиницю.
  4. Збережіть найменше значення. Це і є максимальна просадка.

Ряд доходностей, оцінка волатильності та припущення щодо розподілу не потрібні. Цикл працює зі звичайним списком чисел і використовує стандартну бібліотеку Python. На чистій системі Ubuntu спочатку встановіть інтерпретатор:

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

Збережіть цикл як maxdd.py. Наведені нижче ціни утворюють умовний ряд із десяти значень, достатньо малий для перевірки вручну:

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}%")

Запустіть python3 maxdd.py — програма виведе maximum drawdown: -15.4%. Перевірте розрахунок вручну: максимум перед мінімумом становить 104, мінімум — 88, а 88, поділене на 104, дорівнює 0,846. Потім ряд завершується на рівні 106, тобто на історичному максимумі, але показник 15,4% залишається незмінним. Максимальна просадка назавжди фіксує найгірший момент у вибірці й нічого не говорить про поточне положення ряду. Ще дві змінні в тому самому циклі дають змогу зафіксувати час: індекс, на якому було встановлено максимум, та індекс, на якому зафіксовано найгірше значення.

Як виглядає крива просадки

Крива просадки зберігає крок 3 для кожної точки, а не зводить його до одного найгіршого значення. Лінія перебуває на нульовому рівні щоразу, коли ряд даних досягає нового максимуму, і опускається нижче нуля в проміжках між такими максимумами. Саме тому цей розрив називають «під водою». Нижче наведено таку криву для SPY — ETF, що відстежує S&P 500, — на основі значень закриття на кінець місяця з січня 2016 року.

ЗапитКрива просадки SPY: ціна закриття на кінець місяця порівняно з поточним піком, 2016–2026 рр.
Точний SQL-код для кожного числа
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

За 127 значеннями на кінець місяця лінія тривалий час залишається поблизу нуля, а потім опускається в кілька глибоких западин. Останній доступний місяць показує значення -1.27% відносно поточного піку. Форма кривої наочно демонструє дві особливості. Відновлення відбуваються повільно, а не у вигляді різких відскоків. Кожен новий максимум повертає криву до нуля, стираючи візуальну пам’ять про попередні просадки.

Скільки часу потрібно, щоб відновитися після просадки?

В одній просадці є три окремі показники. Найчастіша помилка під час аналізу таблиці дохідності — трактувати їх як один показник:

  1. Глибина: наскільки, у відсотках, вартість впала нижче пікового рівня.
  2. Час до мінімуму: кількість календарних днів від пікового рівня до дна.
  3. Час відновлення: кількість календарних днів від дна до нового максимуму.

Третій показник зазвичай є найдовшим. Саме його ніколи не відображає заголовкова цифра. Панель нижче відновлює всі завершені періоди перебування SPY нижче попереднього максимуму з 2016 року на основі денних цін закриття. Період починається в день встановлення максимуму й завершується в день, коли фонд уперше закривається вище нього.

ЗапитЗавершені просадки SPY з 2016 року: глибина, дні падіння, дні відновлення
Точний SQL-код для кожного числа
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

Найглибший завершений період у списку починається у Feb 2020 і досягає 34.2% нижче попереднього максимуму. Падіння тривало 33 календарних днів, а відновлення — 148 днів; загалом фонд залишався нижче попереднього максимуму 181 днів. Наступний період, починаючи з Jan 2022, був менш глибоким — 25.4%, але фонд залишався нижче попереднього максимуму 746 днів.

Глибина та тривалість можуть суттєво відрізнятися. Різке падіння зі швидким відновленням і неглибоке зниження, яке триває роками, зводяться до одного відсоткового показника. Обвал у березні 2020 року є класичним прикладом першого сценарію, а як ринки відновлюються після обвалів описує другий етап цього процесу.

Чому максимальна просадка погіршується зі збільшенням періоду вимірювання

Максимальна просадка є максимальним значенням, тому додавання історичних даних може лише залишити її без змін або збільшити. Поточний максимум у довшому періоді в кожен момент щонайменше такий самий, як і максимум у коротшому періоді. Це визначає результат розрахунку. Вимірювання динаміки одного фонду за п’ятьма періодами, що завершуються 31 липня 2026 року, показує цей ефект.

ЗапитОдин фонд, п’ять періодів ретроспективи: максимальна просадка SPY за тривалістю вибірки станом на 31 липня 2026 року
Точний SQL-код для кожного числа
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

За останній період тривалістю 1 year найгірше падіння становило 9.1%. Якщо розширити той самий часовий ряд до 10 years, показник становитиме 34.2%, а найгірша точка припаде на Mar 2020. Фонд не став ризикованішим. Збільшилася тривалість вибірки.

Та сама арифметика спотворює порівняння стратегій. Backtest за три роки та backtest за двадцять років можуть описувати ідентичну поведінку, але водночас показувати дуже різні значення просадки. Тому цей показник мало що означає без зазначення періоду вимірювання. У матеріалі Погляд уперед у backtesting описано інший спосіб, у який backtest із привабливим виглядом може створювати завищене враження про стратегію.

Максимальна просадка проти волатильності

Волатильність вимірює типовий розмір денного руху в будь-якому напрямку. Максимальна просадка вимірює конкретну траєкторію зниження. Обидва показники характеризують ризик, але відповідають на різні запитання. У таблиці їх наведено поруч для восьми широко відомих компаній за п’ятирічний період до 31 липня 2026 року; волатильність річна й розрахована на основі денних цін закриття.

ЗапитМаксимальна просадка проти річної волатильності: вісім акцій великої капіталізації, п’ять років станом на 31 липня 2026 року
Точний SQL-код для кожного числа
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

Розглядайте ці два стовпці разом. VZ продемонструвала найглибше падіння в групі — 45.4%, за річної волатильності 22.6%. Найменше падіння становило 20.9% у KO, а волатильність — 16.7%. Волатильність є середнім показником за кожен день періоду, а середні значення можуть не відображати тривале повільне зниження. Просадка — це найгірша траєкторія, яку фактично пройшла ціна. Спокійний актив, що поступово дешевшає протягом двох років, може мати глибоку просадку за цілком звичайного показника волатильності.

Аномалія низької волатильності показує, як спокійні активи поводяться на довгих горизонтах, а визначення розміру позиції за критерієм Келлі демонструє, як допустимий рівень просадки перетворюється на розмір позиції.

Що цей показник не може показати

Варто пам’ятати про чотири обмеження:

  1. Це один реалізований сценарій. Той самий процес за іншої траєкторії міг би дати значно гірший показник.
  2. Він залежить від довжини вибірки, тому два просідання можна порівнювати лише за однакові періоди.
  3. Він залежить від частоти спостережень. Закриття на кінець місяця приховують внутрішньоденні мінімуми й дають менший показник, ніж денні закриття за той самий період.
  4. Він не містить інформації про майбутнє. Те, що актив перебуває на 30% нижче піку, нічого не говорить про те, чи буде досягнуто 31-го пункту завтра.

Саме останнє обмеження пояснює, чому автоматизованій системі потрібна політика реагування на просідання, а не просто поріг просідання. Правило «зупинити роботу на рівні 20%» відповідає на одне запитання й залишає без відповіді ще два: що робити з відкритими позиціями після зупинки та які докази потрібні для повторного запуску системи. Автоматичні вимикачі для торговельних ботів розглядає структуру такої політики. Вартість довільного фіксованого правила проявляється на етапі відновлення: система, яка зупиняється поблизу мінімуму й відновлює роботу із запізненням, пропускає зростання. Пропущені найкращі дні показує цю арифметику в цифрах.

Перед порівнянням двох показників важливо врахувати одну деталь вимірювання: просідання за ціновим рядом фонду та просідання на реальному рахунку відрізняються, коли відбувається рух грошових коштів на рахунок або з нього, а також коли надходять дивіденди. Цю тему повністю розглянуто в матеріалі як вимірюють місячну дохідність.

FAQ про максимальну просадку

Якою є прийнятна максимальна просадка?

Універсального значення немає. Потрібні benchmark і період, з яким проводиться порівняння. За десять років до 31 липня 2026 року найглибше падіння SPY від поточного піку, виміряне за денними цінами закриття, становило 34.2%. Стратегія, для якої в коротшій вибірці вказано менше значення, не обов’язково була безпечнішою.

Чи є максимальна просадка тим самим, що й волатильність?

Ні. Волатильність описує типовий денний рух. Максимальна просадка описує найгірший шлях від піку до мінімуму. Актив із низькою волатильністю, який стабільно знижується протягом двох років, може мати глибшу просадку, ніж волатильний актив, що продовжує оновлювати максимуми.

Скільки часу потрібно для відновлення після максимальної просадки?

Це залежить від ситуації. Відновлення часто займає більшу частину часу. Для SPY з 2016 року найдовший завершений період нижче попереднього максимуму тривав 181 календарних днів — від піку до оновлення максимуму. Із них 33 днів припали на падіння.

Чи прогнозує максимальна просадка майбутні збитки?

Ні. Вона описує шлях, який уже відбувся, а довша вибірка майже завжди дає більше значення. Показник відображає те, що стратегія пережила досі, але не встановлює межі для майбутніх втрат.


Кожна панель вище зберігає SQL-запит, на якому вона побудована. Відкрийте потрібну панель, змініть ticker або період і виконайте ті самі розрахунки просадки в терміналі Strasmore.

#risk#drawdown#backtesting#performance metrics#python