# Maximum drawdown

Also written max drawdown, max_drawdown.

*https://stockmarketstack.com/glossary/maximum-drawdown · next to Retirement & FIRE Calculators*

**Definition:** The largest percentage fall from a running peak to a later trough in a value series, before a new peak is reached. The number depends on which series is measured and how often it is sampled: account equity or an asset's price, daily closes or month-end or year-end values, nominal or after inflation. A coarser sample can only miss troughs, never add them, so one history reads shallower in a monthly tool than in a daily one.

## How it works

The mechanism is a running maximum over a value series. At each observation, divide the value by
the highest value seen so far and subtract one; that is the drawdown at that point, zero at a new
high and negative below it. ffn's documentation puts it as `current / hwm - 1`, the high-water mark
being the running peak. The maximum drawdown is the most negative of those numbers over the whole
series. Portfolio Visualizer's documentation defines it as the maximum observed loss from a peak to a
trough before a new peak is attained, and abbreviates it MDD.

Three properties follow from the arithmetic alone, and they are what make two figures incomparable:

**Sampling can only make it shallower.** Month-end values are a subset of the daily closes. Every
peak-and-trough pair visible in the monthly series is also in the daily one, and the daily one has
pairs the monthly series does not. So on the same history a monthly maximum drawdown is at most as
deep as a daily one, a year-end figure at most as deep as a monthly one, and a close-to-close figure
at most as deep as one that saw the intraday lows.

**Length can only make it deeper.** Extending the series adds pairs and removes none, so a longer
history's maximum drawdown is at least as deep as a shorter history's inside it.

**It is one event.** The number describes the worst path segment in the sample, not a distribution,
and a single observation cannot say how likely a repeat is. The companion figures — how long the fall
took, how long recovery took, and the whole underwater period from peak to new peak — are separate
numbers that Portfolio Visualizer reports beside it.

## Why it matters here

The allocation backtesters in [retirement planning](https://stockmarketstack.com/categories/retirement-planning) and the
libraries next to them compute this differently, and read against their own documentation and
source code on 26 September 2026 the differences fall into four places.

**Sampling frequency.** [Portfolio Visualizer](https://stockmarketstack.com/tools/portfolio-visualizer) calculates maximum
drawdown from monthly portfolio balances. [Portfolio Charts](https://stockmarketstack.com/tools/portfolio-charts) measures
drawdowns with year-end data and says so, adding that losses in the middle of a year may have been
deeper than shown. [testfolio](https://stockmarketstack.com/tools/testfolio) works on daily values — its average drawdown is
taken across all days below an all-time high. [Backtesting.py](https://stockmarketstack.com/tools/backtesting-py) and
[Backtrader](https://stockmarketstack.com/tools/backtrader) record equity on every bar, and both value open positions at that
bar's close, so on daily bars an intraday low that recovered by the close is not in the figure.

**Nominal or real.** Portfolio Charts adjusts all returns for inflation, expressed in the home
country's currency. A real drawdown in a high-inflation decade is deeper than the nominal one other
tools print for the same years.

**Equity or price.** [ffn](https://stockmarketstack.com/tools/ffn)'s drawdown functions take a price series and
[empyrical-reloaded](https://stockmarketstack.com/tools/empyrical-reloaded)'s `max_drawdown` a returns series; hand either an
asset and you get the asset's drawdown. The backtesters measure account equity, cash included, so a
strategy that is half in cash draws down less than the asset it trades. Where money moves in and out,
Backtrader measures total net asset value by default and can switch to a fund-style value in which
cash added or withdrawn changes a share count instead; only the second keeps a withdrawal from
reading as a loss — the same separation a [time-weighted return](https://stockmarketstack.com/glossary/time-weighted-return)
makes. [QuantStats](https://stockmarketstack.com/tools/quantstats) accepts prices or returns and decides which it was given
from the values: a series whose maximum is below 1, or whose minimum is zero or less, is read as
returns and compounded, so a price series that never reached 1 is not measured as a price.

**Sign and units.** empyrical-reloaded, ffn and QuantStats return a negative fraction, `-0.35`.
Backtesting.py reports `Max. Drawdown [%]` as a negative percentage. Backtrader's `max.drawdown` is a
positive percentage, and [QuantConnect](https://stockmarketstack.com/tools/quantconnect)'s LEAN engine stores the absolute value
of a fraction. A spreadsheet that collects these side by side and sorts them has to normalise first.

The data underneath decides the rest. A drawdown over a universe of companies that still exist omits
every fall that ended at zero, which is [survivorship bias](https://stockmarketstack.com/glossary/survivorship-bias) at its most
literal. And a drawdown read off a stitched [walk-forward](https://stockmarketstack.com/glossary/walk-forward) record depends on
whether the equity curve runs continuously across the segments or restarts at each one.

## Where you will meet this

- [Portfolio Visualizer](https://stockmarketstack.com/tools/portfolio-visualizer.md)
- [Portfolio Charts](https://stockmarketstack.com/tools/portfolio-charts.md)
- [testfolio](https://stockmarketstack.com/tools/testfolio.md)
- [ffn](https://stockmarketstack.com/tools/ffn.md)
- [empyrical-reloaded](https://stockmarketstack.com/tools/empyrical-reloaded.md)
- [QuantStats](https://stockmarketstack.com/tools/quantstats.md)
- [Backtesting.py](https://stockmarketstack.com/tools/backtesting-py.md)
- [Backtrader](https://stockmarketstack.com/tools/backtrader.md)
- [QuantConnect](https://stockmarketstack.com/tools/quantconnect.md)
- [Adaptrade Builder](https://stockmarketstack.com/tools/adaptrade-builder.md)
- [justETF](https://stockmarketstack.com/tools/justetf.md)
- [Riskfolio-Lib](https://stockmarketstack.com/tools/riskfolio-lib.md)

## FAQ

### Why does a longer backtest never show a smaller maximum drawdown?

Because the figure is a maximum over every peak-and-later-trough pair in the series, and extending the series only adds pairs. A thirty-year history can match a five-year one's worst fall or exceed it, never undercut it. Two maximum drawdowns over different spans are therefore not two measurements of one property; the longer one has had more chances.

### Does a withdrawal count as a drawdown?

It does if the tool measures the account balance, and it does not if the tool measures the return series with cash flows taken out. Backtrader makes the choice explicit, with a switch between total net asset value and a per-share fund value; testfolio notes that its daily return percentages ignore cash flows while its daily balances include them. Ask which one the drawdown figure was computed from.

## Sources

1. [Portfolio Visualizer Documentation](https://www.portfoliovisualizer.com/faq) — Portfolio Visualizer, read 2026-09-26
2. [Drawdowns](https://portfoliocharts.com/charts/drawdowns/) — Portfolio Charts, read 2026-09-26
3. [Help, Methodology, and Tool Guides](https://testfol.io/help/) — testfolio, read 2026-09-26
4. [ffn/core.py, to_drawdown_series() and calc_max_drawdown()](https://github.com/pmorissette/ffn/blob/master/ffn/core.py) — ffn (GitHub), read 2026-09-26
5. [empyrical/stats.py, max_drawdown()](https://github.com/stefan-jansen/empyrical-reloaded/blob/main/src/empyrical/stats.py) — empyrical-reloaded (GitHub), read 2026-09-26
6. [quantstats/utils.py, _looks_like_returns() and _prepare_prices()](https://github.com/ranaroussi/quantstats/blob/main/quantstats/utils.py) — QuantStats (GitHub), read 2026-09-26
7. [backtesting/_stats.py, compute_stats()](https://github.com/kernc/backtesting.py/blob/master/backtesting/_stats.py) — Backtesting.py (GitHub), read 2026-09-26
8. [backtesting/backtesting.py, _Broker.next() and last_price](https://github.com/kernc/backtesting.py/blob/master/backtesting/backtesting.py) — Backtesting.py (GitHub), read 2026-09-26
9. [backtrader/analyzers/drawdown.py, DrawDown](https://github.com/mementum/backtrader/blob/master/backtrader/analyzers/drawdown.py) — Backtrader (GitHub), read 2026-09-26
10. [backtrader/brokers/bbroker.py, BackBroker value](https://github.com/mementum/backtrader/blob/master/backtrader/brokers/bbroker.py) — Backtrader (GitHub), read 2026-09-26
11. [Common/Statistics/Statistics.cs, CalculateDrawdownMetrics()](https://github.com/QuantConnect/Lean/blob/master/Common/Statistics/Statistics.cs) — QuantConnect LEAN (GitHub), read 2026-09-26

*Last updated 2026-09-26. A reference page, corrected in place — not a dated post.*
