Apakah Maximum Drawdown? Kedalaman dan Pemulihan
Maximum drawdown ialah kejatuhan terbesar dari paras puncak ke paras terendah. Fahami kedalaman kejatuhan dan sebab pemulihan ke paras tertinggi baharu mengambil masa lebih lama.
Maximum drawdown ialah kejatuhan terbesar daripada paras puncak ke paras terendah dalam siri nilai, yang diukur sebagai peratusan daripada paras puncak semasa. Akaun yang meningkat kepada $120,000, merosot kepada $84,000, kemudian pulih, mempunyai maximum drawdown sebanyak 30%. Angka itu kekal selama-lamanya kerana statistik tersebut merekodkan tempoh terburuk dalam sejarah, bukannya keadaan semasa. Kebanyakan orang hanya menyebut magnitud kejatuhan itu. Namun, terdapat dua lagi angka dalam statistik yang sama: tempoh dari paras puncak ke paras terendah, dan tempoh yang jauh lebih lama dari paras terendah kembali ke paras tertinggi baharu.
Bagaimanakah pengeluaran maksimum dikira?
Keseluruhan pengiraan dilakukan dalam satu laluan merentasi siri tersebut. Pada setiap pemerhatian, anda mengemas kini maksimum berjalan, mengukur nilai semasa berbanding maksimum itu, kemudian menyimpan bacaan paling buruk yang telah direkodkan setakat itu.
- Tetapkan kemuncak berjalan kepada nilai pertama.
- Pada setiap nilai baharu, naikkan kemuncak jika nilai itu lebih tinggi.
- Kira pengeluaran pada titik tersebut: nilai dibahagi dengan kemuncak, kemudian tolak satu.
- Simpan bacaan yang paling negatif. Itulah pengeluaran maksimum.
Tiada siri pulangan, anggaran volatiliti atau andaian taburan digunakan dalam pengiraan ini. Gelung tersebut berjalan pada senarai nombor biasa menggunakan pustaka standard Python. Pada sistem Ubuntu baharu, pasang interpreter terlebih dahulu:
apt-get update && apt-get install -y python3
Simpan gelung itu sebagai maxdd.py. Harga di bawah ialah siri sepuluh titik rekaan, yang dikekalkan ringkas supaya boleh disemak secara manual:
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}%")
Jalankan python3 maxdd.py dan hasilnya ialah maximum drawdown: -15.4%. Semak secara manual: kemuncak sebelum paras terendah ialah 104, paras terendah ialah 88, dan 88 dibahagi dengan 104 ialah 0.846. Siri itu kemudian berakhir pada 106, iaitu paras tertinggi sepanjang masa, tetapi pengeluaran 15.4% masih kekal sebagai rekod. Pengeluaran maksimum ialah rekod kekal bagi detik paling buruk dalam sesuatu sampel. Ia tidak menunjukkan kedudukan siri tersebut pada masa ini. Dua pemboleh ubah tambahan dalam gelung yang sama boleh merekodkan masa berlakunya peristiwa itu: indeks ketika kemuncak ditetapkan dan indeks ketika bacaan paling buruk berlaku.
Rupa bentuk lengkung drawdown
Lengkung drawdown mengekalkan langkah 3 pada setiap titik, bukannya mengurangkannya kepada satu nilai terburuk. Garisan itu berada pada sifar setiap kali siri tersebut mencatat paras tertinggi baharu dan berada di bawah sifar di antaranya. Oleh itu, jurang tersebut dipanggil “underwater”. Berikut ialah lengkung bagi SPY, sebuah exchange traded fund yang menjejaki S&P 500, berdasarkan harga penutup akhir bulan sejak Januari 2016.
SQL tepat di sebalik setiap nombor
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_startSepanjang 127 bacaan akhir bulan, garisan itu berada hampir pada sifar untuk tempoh yang panjang sebelum menurun ke beberapa lekuk yang mendalam. Bacaan bulan terakhir dalam rekod ialah -1.27% berbanding paras kemuncak berjalan. Dua ciri bentuk ini membantu menjelaskan konsep tersebut. Pemulihan berlaku secara pendakian perlahan, bukannya lantunan mendadak. Setiap paras kemuncak baharu menetapkan semula lengkung kepada sifar dan memadamkan kesan visual daripada tempoh sebelumnya.
Berapa lama tempoh pemulihan selepas kemerosotan?
Satu kemerosotan mengandungi tiga angka berbeza. Menganggap semuanya sebagai satu angka ialah salah tafsir paling lazim terhadap jadual prestasi:
- Kedalaman: sejauh mana nilai jatuh di bawah paras puncaknya, dalam peratus.
- Tempoh hingga paras terendah: bilangan hari kalendar dari paras puncak ke paras terendah.
- Tempoh pemulihan: bilangan hari kalendar dari paras terendah kembali ke paras tinggi baharu.
Angka ketiga biasanya paling panjang. Angka inilah yang tidak pernah ditunjukkan oleh angka utama. Panel di bawah membina semula setiap tempoh lengkap apabila SPY berada di bawah paras puncak sejak 2016, berdasarkan harga penutupan harian. Sesuatu tempoh bermula pada hari paras puncak dicapai dan berakhir pada hari dana pertama kali ditutup melepasi paras tersebut.
SQL tepat di sebalik setiap nombor
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 8Tempoh paling dalam yang lengkap dalam senarai bermula pada Feb 2020 dan mencecah 34.2% di bawah paras puncak sebelumnya. Nilainya jatuh selama 33 hari kalendar dan mengambil masa 148 hari untuk pulih, dengan jumlah 181 hari berada di bawah paras puncak. Entri berikutnya, dari Jan 2022, lebih cetek pada 25.4%, tetapi dana itu kekal di bawah paras tinggi lamanya selama 746 hari.
Kedalaman dan tempoh boleh berbeza sepenuhnya. Kejatuhan mendadak yang pulih dengan cepat dan kemerosotan cetek yang berlarutan selama bertahun-tahun kedua-duanya diringkaskan sebagai satu angka peratusan. Kejatuhan pasaran pada Mac 2020 ialah contoh klasik bentuk pertama, manakala cara pasaran pulih daripada kejatuhan mengikuti fasa kedua perjalanan itu.
Mengapa maximum drawdown menjadi lebih buruk apabila tempoh pengukuran lebih panjang
Maximum drawdown ialah nilai maksimum. Oleh itu, penambahan sejarah hanya boleh mengekalkan nilainya atau menjadikannya lebih besar. Puncak berjalan dalam tetingkap yang lebih panjang sekurang-kurangnya setinggi puncak dalam tetingkap yang lebih pendek pada setiap titik. Perkara ini menentukan hasil pengiraan. Pengukuran dana yang sama bagi lima tetingkap, yang semuanya berakhir pada 31 Julai 2026, menunjukkan kesan tersebut.
SQL tepat di sebalik setiap nombor
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_yearsDalam tetingkap 1 year terkini, penurunan terburuk yang diukur ialah 9.1%. Apabila siri yang sama dipanjangkan kepada 10 years, bacaan itu menjadi 34.2%, dengan titik terburuk berlaku pada Mar 2020. Dana itu tidak menjadi lebih berisiko. Sampelnya menjadi lebih panjang.
Pengiraan yang sama turut memesongkan perbandingan strategi. Backtest tiga tahun dan backtest dua puluh tahun boleh menggambarkan tingkah laku yang sama, tetapi masih melaporkan drawdown yang sangat berbeza. Oleh itu, angka tersebut tidak banyak bermakna tanpa tempoh pengukuran. Bias melihat ke hadapan dalam backtesting menerangkan satu lagi cara backtest yang kelihatan bersih boleh memberikan gambaran yang terlalu baik tentang dirinya sendiri.
Maksimum drawdown berbanding volatiliti
Volatiliti mengukur saiz lazim pergerakan harian dalam mana-mana arah. Maksimum drawdown mengukur satu laluan penurunan tertentu. Kedua-duanya ialah ukuran risiko, tetapi menjawab soalan yang berbeza. Panel ini membandingkan kedua-duanya bagi lapan nama saham yang dikenali ramai sepanjang tempoh lima tahun hingga 31 Julai 2026, dengan volatiliti tahunan dikira berdasarkan harga penutup harian.
SQL tepat di sebalik setiap nombor
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 DESCBaca kedua-dua lajur itu secara bersama. VZ mencatatkan kejatuhan paling dalam dalam kumpulan tersebut, iaitu 45.4%, berbanding volatiliti tahunan sebanyak 22.6%. Pada hujung yang paling cetek, KO jatuh 20.9% dengan volatiliti sebanyak 16.7%. Volatiliti ialah purata bagi setiap hari dalam tempoh berkenaan, dan purata boleh menyembunyikan kemerosotan yang panjang serta beransur-ansur. Drawdown ialah laluan terburuk tunggal yang benar-benar dilalui oleh harga. Pegangan yang tenang tetapi merosot perlahan-lahan selama dua tahun boleh mencatatkan drawdown yang dalam walaupun bacaan volatiliti tidak ketara.
Anomali volatiliti rendah meneliti gelagat saham yang tenang dalam tempoh panjang, manakala Penentuan saiz posisi menggunakan kriteria Kelly menunjukkan bagaimana toleransi terhadap drawdown diterjemahkan kepada saiz posisi.
Perkara yang tidak dapat diberitahu oleh angka
Empat had wajar diambil kira:
- Ia ialah satu laluan yang telah direalisasikan. Proses yang sama boleh menghasilkan angka yang jauh lebih buruk berdasarkan sampel yang berbeza.
- Ia bergantung pada tempoh sampel. Oleh itu, dua drawdown hanya boleh dibandingkan bagi tetingkap yang sama panjang.
- Ia bergantung pada kekerapan pensampelan. Harga penutupan hujung bulan menyembunyikan paras rendah intrahari dan menghasilkan angka yang lebih kecil berbanding harga penutupan harian bagi tempoh yang sama.
- Ia tidak memberikan maklumat tentang masa hadapan. Berada 30% di bawah paras puncak tidak menunjukkan sama ada titik ke-31 akan dicapai esok.
Had terakhir itu menjelaskan sebab sistem automatik memerlukan dasar drawdown, bukannya ambang drawdown. “Hentikan pada 20%” menjawab satu soalan tetapi meninggalkan dua soalan tanpa jawapan: apakah yang berlaku kepada posisi terbuka ketika sistem dihentikan, dan apakah bukti yang membolehkan sistem diaktifkan semula. Pemutus litar untuk bot dagangan menerangkan bentuk dasar tersebut. Kos peraturan rata yang sewenang-wenangnya akan muncul dalam fasa pemulihan, apabila sistem yang berhenti hampir pada paras terendah dan diaktifkan semula terlalu lewat terlepas daripada kenaikan. Terlepas hari-hari terbaik menghitung kesan tersebut.
Satu perincian pengukuran penting perlu difahami sebelum membandingkan dua angka: drawdown berdasarkan siri harga dana berbeza daripada drawdown berdasarkan akaun sebenar apabila terdapat aliran tunai masuk atau keluar dan apabila dividen diterima. Perkara ini diterangkan sepenuhnya dalam cara pulangan bulanan diukur.
Soalan Lazim tentang Kemerosotan Maksimum
Apakah kemerosotan maksimum yang baik?
Tiada angka sejagat. Penilaiannya bergantung pada penanda aras dan tempoh pengukuran. Dalam tempoh sepuluh tahun hingga 31 Julai 2026, kejatuhan terburuk SPY daripada paras kemuncak bergerak, berdasarkan harga penutup harian, berjumlah 34.2%. Strategi yang melaporkan angka lebih kecil bagi sampel yang lebih singkat tidak semestinya lebih selamat.
Adakah kemerosotan maksimum sama dengan volatiliti?
Tidak. Volatiliti menerangkan pergerakan harian yang lazim. Kemerosotan maksimum menerangkan laluan tunggal paling buruk dari paras kemuncak ke paras terendah. Pegangan dengan volatiliti rendah yang merosot secara berterusan selama dua tahun boleh mengalami kemerosotan lebih besar berbanding pegangan yang turun naik tetapi terus mencatat paras tertinggi baharu.
Berapa lama masa yang diperlukan untuk pulih daripada kemerosotan maksimum?
Tempohnya berbeza, dan proses kenaikan semula selalunya mengambil separuh tempoh yang lebih panjang. Bagi SPY sejak 2016, tempoh paling panjang yang lengkap di bawah paras tertinggi sebelumnya berlangsung selama 181 hari kalendar dari kemuncak hingga paras tertinggi baharu. Daripada tempoh itu, 33 hari dihabiskan dalam kejatuhan.
Adakah kemerosotan maksimum meramalkan kerugian pada masa hadapan?
Tidak. Ia hanya menerangkan satu laluan yang telah berlaku. Sampel yang lebih panjang hampir sentiasa menghasilkan angka yang lebih besar. Ukuran ini merekodkan perkara yang telah berjaya dilalui oleh sesuatu strategi setakat ini, tanpa mengehadkan apa yang mungkin berlaku seterusnya.
Setiap panel di atas menyimpan SQL yang digunakan. Buka salah satu panel, tukar ticker atau tempoh, kemudian jalankan pengiraan kemerosotan yang sama pada terminal Strasmore.