Maximum drawdown (MDD) is the deepest observed percentage decline from a running peak in an equity, net asset value, or cumulative-return series. It includes an unfinished decline at the end of the sample unless the calculation explicitly excludes active drawdowns.
Maximum drawdown measures one realized path. It does not estimate the worst possible future loss, probability of ruin, or capital required to survive. Those questions need a return model, leverage and margin rules, liquidity assumptions, and stress scenarios.
Formula
For positive equity E_t at time t:
peak_t = max(E_0, E_1, ..., E_t)
drawdown_t = E_t / peak_t - 1
maximum_drawdown = min(drawdown_t)
drawdown_t is zero at a running high and negative below it. Some reports present drawdown depth as a positive magnitude, so the same event may appear as -15% or 15%. State the sign convention.
Percentage drawdown becomes undefined or misleading when equity is zero or negative. Leveraged strategies that can cross zero need absolute loss, margin, liquidation, and insolvency measures in addition to a percentage series.
Python example with an unfinished drawdown
Include starting equity before the first return. Otherwise, an immediate loss can disappear because the first reduced value becomes the observed peak. This hand-checkable series has one recovered decline and one deeper decline that remains active at the end.
import pandas as pd
equity = pd.Series(
[100, 105, 100, 95, 98, 106, 104, 90, 92, 97],
index=pd.date_range("2025-01-01", periods=10, freq="D"),
dtype=float,
)
running_peak = equity.cummax()
drawdown = equity / running_peak - 1
trough_time = drawdown.idxmin()
peak_time = equity.loc[:trough_time].idxmax()
peak_value = equity.loc[peak_time]
later = equity.loc[trough_time:]
recovered = later[later >= peak_value]
recovery = "Active" if recovered.empty else recovered.index[0].date().isoformat()
print(f"Peak: {peak_time.date()} at {peak_value:.0f}")
print(f"Trough: {trough_time.date()} at {equity.loc[trough_time]:.0f}")
print(f"Maximum drawdown: {drawdown.min():.2%}")
print(f"Recovery: {recovery}")
print(f"Current drawdown: {drawdown.iloc[-1]:.2%}")
Peak: 2025-01-06 at 106
Trough: 2025-01-08 at 90
Maximum drawdown: -15.09%
Recovery: Active
Current drawdown: -8.49%
The lowest point is 15.09% below the peak of 106. Equity later rises to 97, so the current drawdown improves to 8.49%, but the episode remains active because equity has not regained 106. Reporting only recovered episodes would instead ignore this worst decline and select the earlier 9.52% drop from 105 to 95.
Depth, decline, recovery, and time underwater
A useful drawdown record has at least four timestamps:
- Peak: the running high from which the decline begins.
- Trough: the lowest value reached before recovery or the sample end.
- Recovery: the first later value that regains the prior peak.
- End of observation: the cutoff for an active, unrecovered drawdown.
Duration has several valid definitions. Peak-to-trough time measures the decline phase. Trough-to-recovery time measures the recovery phase. Peak-to-recovery time measures the full underwater episode. Bar counts and calendar time differ across weekends, holidays, missing observations, and irregular data, so name the chosen definition and unit.
Recovery is asymmetric. After a loss magnitude L, the gain required to regain the peak is:
required_gain = L / (1 - L)
A 50% loss needs a 100% gain. This arithmetic explains why depth matters, but it does not mean maximum drawdown alone determines whether a strategy survives. Leverage, cash needs, investor redemptions, margin calls, and the duration of the decline can force closure before or after a particular percentage threshold.
Build the right equity series first
Drawdown quality cannot exceed the quality of the marked equity input. The series should include cash, open-position marks, realized PnL, fees, spread, slippage, financing, borrow costs, dividends, and other relevant cash flows.
External deposits and withdrawals require special handling. A deposit can create a false new peak and an apparent recovery if raw account balance is used. Use a unitized NAV or a properly chained time-weighted return series when measuring investment performance across external flows. Keep actual cash-balance drawdown as a separate liquidity view when it matters operationally.
Sampling frequency also changes the result. Daily closes miss intraday troughs. Mark-to-market data can show a deeper loss than realized PnL, while stale or model-based prices can hide one. Compare strategies only over aligned histories, currencies, valuation rules, and frequencies.
How to interpret maximum drawdown
Maximum drawdown is an extreme statistic selected from one finite sample. A longer history has more opportunity to contain a deep decline. A strategy selected because its historical drawdown was small is also exposed to selection bias. The observed MDD is therefore neither an upper bound nor a stable population parameter.
Report it with:
- Current drawdown and whether the maximum episode is active.
- Peak, trough, recovery, and underwater durations.
- Several large episodes, not just the single maximum.
- Drawdown coverage, or the fraction of time spent underwater.
- Return and leverage over the same period.
- Stress and resampling results that preserve serial dependence where possible.
- Out-of-sample and live results under the same valuation convention.
Ratios such as Calmar divide annualized return by maximum drawdown magnitude. They can help compare aligned runs, but the numerator and a single sample extreme remain sensitive to period choice. Sharpe ratio and drawdown answer different questions and neither replaces the other.
Tool behavior and risk controls
The VectorBT family builds a Drawdowns record set from a time series, including peaks, valleys, recovery endpoints, durations, and active status. The community VectorBT documentation warns that active and recovered records coexist. Some default summary metrics exclude active drawdowns unless incl_active=True, so check settings before comparing the summary with the minimum of the raw drawdown series.
VectorBT PRO applies the same record-oriented analysis across multidimensional portfolios, parameter grids, and grouped results. That is useful when the job is to inspect drawdown distributions across a large research surface rather than rank configurations by one MDD.
NautilusTrader's documented risk engine checks cover order validity, quantities, notionals, balances, rate limits, and trading states. The current documented list does not include a built-in portfolio drawdown threshold. A live drawdown circuit breaker therefore needs explicit account-equity monitoring and a tested action such as switching to reducing or halted state, cancelling eligible orders, or flattening positions. Backtest MDD by itself does not implement that control.