Maximum Drawdown: Lalim at Tagal ng Pagbangon
Ang maximum drawdown ay pinakamalaking pagbaba mula peak hanggang trough. Alamin kung gaano ito kalalim at bakit mas matagal ang recovery tungo sa bagong high.
Ang maximum drawdown ay pinakamalaking pagbaba mula peak hanggang trough sa isang value series, na sinusukat bilang porsiyento ng running peak. Kung umakyat ang isang account sa $120,000, bumaba sa $84,000, at pagkatapos ay nakabawi, ang maximum drawdown nito ay 30%. Mananatili ang numerong ito, dahil itinatala ng statistic ang pinakamalalang yugto sa buong history, hindi ang kalagayan nito ngayon.
Kadalasang binabanggit ng mga tao ang lalim ng pagbaba at doon na nagtatapos. Ngunit may dalawa pang numerong kasama sa parehong statistic: ang panahong mula peak hanggang low, at ang mas mahabang panahong mula low pabalik sa bagong high.
Paano kinakalkula ang maximum drawdown?
Isang pasada lamang sa buong series ang kailangan sa kalkulasyon. Sa bawat observation, ina-update mo ang running maximum, sinusukat ang kasalukuyang halaga laban dito, at itinatala ang pinakamalalang reading na nakita hanggang sa puntong iyon.
- Itakda ang running peak sa unang halaga.
- Sa bawat bagong halaga, itaas ang peak kung mas mataas ang halaga.
- Kalkulahin ang drawdown sa puntong iyon: hatiin ang halaga sa peak, saka ibawas ang one.
- Itala ang pinaka-negatibong reading. Iyon ang maximum drawdown.
Walang returns series, volatility estimate, o distribution assumption na kasama rito. Tumatakbo ang loop sa isang simpleng listahan ng mga numero gamit ang Python standard library. Sa isang bagong Ubuntu box, i-install muna ang interpreter:
apt-get update && apt-get install -y python3
I-save ang loop bilang maxdd.py. Ang mga presyo sa ibaba ay isang gawa-gawang ten-point series. Pinanatili itong maliit para madaling i-check nang mano-mano:
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}%")
Patakbuhin ang python3 maxdd.py at ilalabas nito ang maximum drawdown: -15.4%. I-check nang mano-mano: ang peak bago ang low ay 104, ang low ay 88, at ang 88 na hinati sa 104 ay 0.846. Nagtatapos ang series sa 106, na isang all-time high, ngunit nananatili ang 15.4%. Ang maximum drawdown ay permanenteng tala ng pinakamasamang sandali sa isang sample. Wala itong sinasabi kung nasaan ang series ngayon. Dalawa pang variable sa parehong loop ang makapagtatala ng timing: ang index kung saan itinakda ang peak, at ang index kung saan nangyari ang pinakamalalang reading.
Ano ang itsura ng drawdown curve
Pinananatili ng drawdown curve ang step 3 sa bawat punto sa halip na gawing isang pinakamalalang value lamang. Nasa zero ang linya sa tuwing nagtatala ang series ng bagong high at nananatili itong nasa ibaba ng zero sa pagitan ng mga iyon. Dahil dito, tinatawag na “underwater” ang pagitan. Narito ang curve para sa SPY, isang exchange traded fund na sumusubaybay sa S&P 500, batay sa month-end closing prices mula Enero 2016.
Ang eksaktong SQL sa likod ng bawat numero
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_startSa 127 month-end readings, matagal na nananatiling malapit sa zero ang linya at bumabagsak ito sa ilang malalalim na notch. Ang huling month na nasa file ay nasa -1.27% kumpara sa running peak. Dalawang katangian ng hugis nito ang malinaw na nagtuturo ng konsepto. Mabagal na pag-akyat, hindi matitinding bounce, ang mga recovery. At nire-reset ng bawat bagong peak ang curve sa zero, kaya nabubura sa visual na anyo ang bakas ng mga naunang drawdown.
Gaano katagal ang pagbangon mula sa drawdown?
May tatlong magkahiwalay na numero sa loob ng isang drawdown, at ang pagtingin sa mga ito bilang iisa ang pinakakaraniwang maling pagbasa sa isang performance table:
- Lalim: kung gaano kalaki ang ibinaba ng value mula sa peak nito, bilang porsiyento.
- Panahon bago maabot ang low: mga araw sa kalendaryo mula sa peak hanggang sa bottom.
- Panahon ng recovery: mga araw sa kalendaryo mula sa bottom pabalik sa bagong high.
Karaniwan, ang ikatlo ang pinakamatagal. Ito rin ang hindi ipinapakita ng isang headline number. Muling binubuo ng panel sa ibaba ang bawat natapos na underwater stretch ng SPY mula noong 2016 gamit ang daily closes. Nagsisimula ang isang stretch sa araw na naitatag ang peak at nagtatapos sa araw na unang nagsara ang fund nang mas mataas dito.
Ang eksaktong SQL sa likod ng bawat numero
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 8Ang pinakamalalim na natapos na stretch sa listahan ay nagsisimula sa Feb 2020 at umabot sa 34.2% sa ibaba ng dating peak. Bumaba ito sa loob ng 33 calendar days at umakyat pabalik sa loob ng 148, o kabuuang 181 araw na nanatili itong underwater. Ang kasunod na entry, mula noong Jan 2022, ay mas mababaw sa 25.4%, ngunit nanatiling mas mababa ang fund sa dating high nito nang 746 araw.
Lubos na magkahiwalay ang lalim at tagal. Ang isang matinding pagbagsak na mabilis na nakabawi at ang mabagal na pagbaba na tumatagal nang maraming taon ay kapwa napipiga sa iisang porsiyento. Ang crash noong March 2020 ang textbook case ng unang anyo, at kung paano nakakabawi ang mga merkado mula sa mga crash ang sumusunod na yugto ng paglalakbay.
Bakit lumalala ang maximum drawdown habang humahaba ang panahon ng pagsukat
Maximum ang drawdown, kaya ang pagdagdag ng historical data ay maaari lamang magpanatili rito sa parehong antas o magpalalim dito. Sa mas mahabang window, hindi bababa sa taas ng running peak sa mas maikling window ang running peak sa bawat punto. Dahil dito, ganoon ang resulta ng arithmetic. Makikita ang epekto kapag sinukat ang parehong fund gamit ang limang window na lahat ay nagtatapos sa July 31, 2026.
Ang eksaktong SQL sa likod ng bawat numero
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_yearsSa trailing 1 year window, umabot sa 9.1% ang pinakamalaking pagbaba. Nang i-extend ang parehong series sa 10 years, naging 34.2% ang reading, at naganap ang pinakamababang punto sa Mar 2020. Hindi naging mas risky ang fund. Humaba lamang ang sample.
Binabaluktot din ng parehong arithmetic ang paghahambing ng mga strategy. Maaaring ilarawan ng three-year backtest at twenty-year backtest ang magkaparehong behavior, ngunit mag-ulat pa rin ng magkaibang drawdown. Kaya kakaunti ang kahulugan ng figure kung hindi nakasaad ang window na ginamit. Tinalakay sa Look-ahead bias sa backtesting ang isa pang paraan kung paano napapaboran ng malinis tingnang backtest ang sarili nito.
Maximum drawdown kumpara sa volatility
Sinusukat ng volatility ang karaniwang laki ng galaw ng presyo bawat araw, pataas man o pababa. Sinusukat naman ng maximum drawdown ang isang partikular na pababang trajectory. Pareho silang sukatan ng risk, pero magkaiba ang tanong na sinasagot nila. Magkatabi sa panel ang dalawang sukatan para sa walong kilalang kumpanya sa loob ng limang taon hanggang July 31, 2026, kung saan annualized mula sa daily closing prices ang volatility.
Ang eksaktong SQL sa likod ng bawat numero
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 DESCBasahin nang magkasama ang dalawang column. Nagtala ang VZ ng pinakamalalim na pagbaba sa grupo, sa 45.4%, kumpara sa annualized volatility na 22.6%. Sa kabilang dulo, bumaba ang KO ng 20.9%, na may volatility na 16.7%. Ang volatility ay average sa bawat araw sa loob ng panahon, at maaaring hindi maipakita ng average ang matagal at mabagal na pagbaba. Ang drawdown ay ang iisang pinakamasamang path na aktuwal na dinaanan ng presyo. Maaaring makapagtala ang isang tahimik na holding na unti-unting bumaba sa loob ng dalawang taon ng malalim na drawdown kahit hindi kapansin-pansin ang volatility reading.
Ang low volatility anomaly ay sumusuri kung paano kumikilos ang mga kalmadong pangalan sa mahahabang panahon, habang ipinapakita ng position sizing gamit ang Kelly criterion kung paano nagiging position size ang tolerance sa drawdown.
Ang hindi masasabi ng numero
May apat na limitasyong dapat tandaan:
- Isa lamang itong natantong path. Maaaring nakalikha ang parehong proseso ng mas masamang resulta sa ibang draw.
- Nakadepende ito sa haba ng sample, kaya maihahambing lamang ang dalawang drawdown kung magkatugma ang mga window.
- Nakadepende ito sa dalas ng sampling. Itinatago ng month-end closes ang mga intraday low, kaya mas maliit ang numerong lalabas kumpara sa daily closes sa parehong panahon.
- Wala itong impormasyong maaasahan para sa hinaharap. Ang pagiging 30% na mas mababa sa isang peak ay walang sinasabi kung darating bukas ang ika-31 na punto.
Dahil sa huling limitasyong ito, kailangan ng automated system ng drawdown policy, hindi lamang drawdown threshold. Sinasagot ng “Halt at 20%” ang isang tanong ngunit iniiwan ang dalawa: ano ang mangyayari sa open positions kapag nag-halt, at anong ebidensiya ang magpapaandar muli sa system. Tinutukoy ng Circuit breakers para sa trading bots ang hugis ng policy na iyon. Ang halaga ng isang arbitraryong flat rule ay lumilitaw sa recovery leg, kung saan hindi nasasakyan ng system ang pag-akyat kapag huminto ito malapit sa low at huli itong nag-restart. Naglalagay ng mga numero sa kalkulasyong iyon ang Pagkawala sa pinakamagagandang araw.
Mahalaga ang isang detalye sa pagsukat bago paghambingin ang dalawang numero: magkaiba ang drawdown sa price series ng isang fund at ang drawdown sa aktuwal na account kapag may pumapasok o lumalabas na cash at kapag may pumapasok na dividend. Sinasaklaw ito nang buo ng kung paano sinusukat ang monthly returns.
FAQ tungkol sa maximum drawdown
Ano ang maituturing na magandang maximum drawdown?
Walang unibersal na halaga. Kailangan itong ikumpara sa isang benchmark at sa partikular na panahong sinusukat. Sa sampung taon hanggang July 31, 2026, ang pinakamalaking pagbagsak ng SPY mula sa running peak ay umabot sa 34.2% batay sa daily closes. Hindi awtomatikong mas ligtas ang isang strategy dahil mas maliit ang iniulat nitong halaga sa mas maikling sample.
Pareho ba ang maximum drawdown at volatility?
Hindi. Inilalarawan ng volatility ang karaniwang daily move. Inilalarawan naman ng maximum drawdown ang pinakamalaking pagbaba mula peak hanggang trough. Ang isang holding na may mababang volatility ngunit tuluy-tuloy na bumababa sa loob ng dalawang taon ay maaaring magkaroon ng mas malalim na drawdown kaysa sa isang pabagu-bagong holding na patuloy namang nagtatakda ng mga bagong high.
Gaano katagal ang recovery mula sa maximum drawdown?
Nag-iiba ito, at madalas na mas matagal ang pag-akyat pabalik. Para sa SPY mula 2016, ang pinakamalalim na nakumpletong panahon sa ibaba ng dating high ay umabot sa 181 calendar days mula peak hanggang sa bagong high. Sa panahong iyon, 33 ang ginugol sa pagbaba.
Nahuhulaan ba ng maximum drawdown ang mga pagkalugi sa hinaharap?
Hindi. Inilalarawan nito ang isang path na nangyari na, at halos palaging nagreresulta sa mas malaking halaga ang mas mahabang sample. Itinatala nito ang mga kondisyong nalagpasan na ng isang strategy, ngunit walang limitasyon sa maaaring mangyari sa hinaharap.
Naka-store ang SQL sa likod ng bawat panel sa itaas. Buksan ang isa, palitan ang ticker o ang window, at patakbuhin ang parehong drawdown arithmetic sa Strasmore terminal.