On February 19, 2025, the S&P 500 closed at a record 6,144.15. Seven weeks later, on April 8, it closed at 4,982.77: a close-to-close drawdown of 18.9%, just short of the 20% that would have made it an official bear market. Most of the damage came in four sessions after the April 2 "Liberation Day" tariff announcement, including a 4.8% drop on April 3 and a 6% drop on April 4.

Then, on April 9, the White House announced a 90-day pause on most of the new tariffs, and the index rose 9.5% in one day, its best day since October 2008. By the close on May 27, after the EU tariff delay, it stood at 5,921.54, about 3.6% below the February record.

If you held through it, the whole episode is a dip on a chart. If you sold on April 8, you locked in the loss and missed the best day in 16 years. The difference between those two investors is not a forecast. It is whether they understood the risk they were carrying before the sell-off started.

This cheatsheet covers the metrics that describe that risk, what each one hides, and how to compute them with pandas.

Educational content, not financial advice.

1. Drawdown, max drawdown and the underwater period

Term Definition Example (S&P 500, 2025, closes)
Running peak Highest value reached so far 6,144.15 on February 19
Drawdown Current value / running peak - 1. Always zero or negative April 8: 4,982.77 / 6,144.15 - 1 = -18.9%
Max drawdown (MDD) Most negative drawdown over the period -18.9% (close-to-close, for 2025 so far)
Drawdown duration Time from a peak to the trough February 19 to April 8: 34 trading days
Recovery time Time from the trough back to the previous peak Not complete as of May 27 (about 3.6% below)
Underwater period Total time spent below the previous peak: duration plus recovery February 19 to today, and counting

Notes that matter in practice:

  • Close-to-close vs intraday. Intraday lows were deeper than closing lows in early April. State which one you use; fund factsheets almost always use closes (often monthly), which understates the pain.
  • Sampling frequency hides drawdowns. A month-end series can miss a drawdown that started and recovered inside the month.
  • Max drawdown is a single event. It depends heavily on the sample period. A 10-year backtest without 2008, 2020 or 2022 in it has an MDD that tells you little about the next crisis.
  • Duration is often the harder part. Investors tolerate a sharp 20% drop that recovers in months better than a 20% drop that stays underwater for years. The S&P 500 took until 2013 to regain its 2007 peak on a price basis.

2. The asymmetry of losses

A loss of x requires a gain of x / (1 - x) to get back to even:

Loss Gain needed to recover
-5% +5.3%
-10% +11.1%
-18.9% (S&P 500, Feb-Apr 2025) +23.3%
-20% +25%
-30% +42.9%
-50% +100%
-80% +400%

Two consequences:

  • Small losses are cheap, large losses are expensive. The recovery cost grows faster than the loss. That is the mathematical reason risk management focuses on avoiding the large ones.
  • Volatility drags on compounding. Gaining 10% then losing 10% leaves you at 0.99, not 1.00. Approximately, geometric return = arithmetic return - variance / 2. Two strategies with the same average return compound differently if their volatility differs.

The rebound from April 8 to May 27 was +18.8%, which sounds like more than the 18.9% lost. It was not enough to recover: the asymmetry in one line.

3. The core risk metrics

Metric Formula (annualized from daily data) What it says What it hides
Volatility Std of daily returns x sqrt(252) Typical size of moves Up and down moves count equally; fat tails
Sharpe ratio (Mean return - risk-free) / volatility Return per unit of total volatility Penalizes upside volatility; assumes roughly normal returns
Sortino ratio (Mean return - target) / downside deviation Return per unit of bad volatility Needs a target (0 or risk-free); unstable with few down days
Calmar ratio CAGR / abs(max drawdown), often over 3 years Return per unit of worst pain Rests on one event; very period-dependent
VaR (95%, 1 day) Loss exceeded on only 5% of days "A bad normal day" Says nothing about how bad the worst 5% are
CVaR / Expected Shortfall Average loss on the days worse than VaR The size of the tail Needs many observations to be stable
Beta Cov(asset, market) / Var(market) Sensitivity to the market Unstable over time; a low beta can still crash
Correlation Pearson correlation of returns How assets move together Changes with regime, especially in crises

Rules of thumb:

  • A Sharpe above 1 on a long, out-of-sample record is good for a diversified strategy. A backtest Sharpe above 3 is usually a bug, overfitting, or a strategy that sells tail risk.
  • Use log or simple returns consistently, and annualize with the right factor: 252 for daily, 52 for weekly, 12 for monthly.
  • Historical VaR uses the empirical distribution; parametric VaR assumes a normal one. Normal VaR underestimates tail losses for equities, which have fat left tails. CVaR is the better tail measure and is what Basel's market risk framework moved to.
  • Report MDD next to any return number. "12% a year" with a -55% drawdown is a different product from "12% a year" with a -15% drawdown.

4. Correlations spike in crises

Diversification is measured in calm markets and needed in stressed ones, and those are not the same correlation matrix. Longin and Solnik (2001) found that correlations between international equity markets rise in bear markets, not in bull markets. In practice, during a sell-off many equity positions behave like one position.

Practical implications:

  • Estimate correlations on stress windows (2008, March 2020, 2022, April 2025) as well as full history.
  • Count your real bets. Ten tech stocks and a Nasdaq ETF are one bet with extra fees.
  • Do not assume the hedge works every time. Bonds hedged equity sell-offs in 2008 and 2020 and fell with them in 2022. Check what a hedge did in the specific kind of shock you worry about (inflation, growth, policy).

5. Position sizing and risk budgeting

Metrics describe risk. Sizing is where you control it.

Method Rule Use it when
Fixed fractional (per-trade risk) Size = (equity x risk %) / (entry - stop). Risk 0.5-2% of equity per trade Discretionary or systematic trading with defined stops
Volatility targeting Weight = target vol / asset vol Keeping portfolio risk stable as markets calm down or heat up
Equal risk contribution (risk parity) Each position contributes the same share of portfolio volatility Multi-asset portfolios where one asset would otherwise dominate
Drawdown limits Cut gross exposure at -10%, again at -15%, review at -20% Rules that must be decided before the drawdown, not during
Kelly fraction Size that maximizes long-run growth given an edge Theory only; real edges are uncertain, so practitioners use a fraction of Kelly at most

Example of fixed fractional: a $50,000 account risking 1% per trade, buying at $100 with a stop at $92, can buy 500 / 8 = 62 shares. The stop, not the conviction, sets the size. Note that a stop is not a guaranteed exit price: on gap days like April 3 and 4, prices can open far beyond it.

Risk budgeting at the portfolio level: decide the maximum drawdown you can live with, financially and emotionally, then size the equity allocation so that a historical-scale crash (say -35% to -50% for broad equities) stays inside that budget. If a -50% equity crash would put your portfolio at -30% and you know you would sell at -20%, your allocation is too high, whatever the Sharpe ratio says.

6. The behavioral side: selling at the bottom

Drawdowns are a math problem on a spreadsheet and a psychology problem in real time.

  • Loss aversion. Kahneman and Tversky's prospect theory: losses loom larger than equivalent gains, and their later estimates put the weight at roughly twice. An -18.9% drawdown feels larger than the +18.8% rebound that followed.
  • The best days cluster near the worst days. April 9 (+9.5%) came one session after the April 8 low. Selling to "wait until things calm down" usually means buying back higher.
  • Recency and narrative. In the middle of a sell-off the news explains why it will continue. At the April 8 close, nobody knew that the pause would come the next day.
  • Disposition effect. Investors sell winners too early and hold losers too long, the opposite of what most trend and risk rules ask.

Defenses that work better than willpower:

  1. Write the rules before the drawdown: allocation, rebalancing bands, drawdown limits, what you will do at -10%, -20%, -30%.
  2. Rebalance mechanically, on a schedule or at bands (for example, plus or minus 5 points from target). It forces buying after falls.
  3. Size for the worst case you can sit through, not the expected case.
  4. Keep a cash or bond buffer for known spending, so you never sell equities in a drawdown to pay bills.
  5. Look less. Checking a portfolio daily during a sell-off increases the urge to act.

7. Computing it with pandas

The code below takes a price series (closes) and returns the drawdown series, max drawdown, longest underwater period, and the ratios from section 3. Feed it real closes from any data source.

import numpy as np
import pandas as pd

TRADING_DAYS = 252


def drawdown_series(prices: pd.Series) -> pd.DataFrame:
    """Running peak, drawdown (as a negative fraction) and underwater flag."""
    peak = prices.cummax()
    dd = prices / peak - 1.0
    return pd.DataFrame({"price": prices, "peak": peak, "drawdown": dd, "underwater": dd < 0})


def max_drawdown(prices: pd.Series) -> tuple[float, pd.Timestamp, pd.Timestamp]:
    dd = prices / prices.cummax() - 1.0
    trough = dd.idxmin()
    peak = prices.loc[:trough].idxmax()
    return dd.min(), peak, trough


def longest_underwater(prices: pd.Series) -> int:
    """Longest run of consecutive observations below the previous peak."""
    under = (prices < prices.cummax()).astype(int)
    runs = under.groupby((under == 0).cumsum()).sum()
    return int(runs.max())


def risk_report(prices: pd.Series, rf_annual: float = 0.0, benchmark: pd.Series | None = None) -> dict:
    r = prices.pct_change().dropna()
    rf_daily = (1 + rf_annual) ** (1 / TRADING_DAYS) - 1
    excess = r - rf_daily

    years = len(r) / TRADING_DAYS
    cagr = (prices.iloc[-1] / prices.iloc[0]) ** (1 / years) - 1
    vol = r.std() * np.sqrt(TRADING_DAYS)
    sharpe = excess.mean() / r.std() * np.sqrt(TRADING_DAYS)
    downside = np.sqrt((np.minimum(excess, 0) ** 2).mean()) * np.sqrt(TRADING_DAYS)
    sortino = excess.mean() * TRADING_DAYS / downside
    mdd, _, _ = max_drawdown(prices)
    calmar = cagr / abs(mdd)
    var95 = -np.percentile(r, 5)            # historical 1-day VaR, as a positive loss
    cvar95 = -r[r <= -var95].mean()         # average loss beyond VaR

    out = {
        "CAGR": cagr, "Volatility": vol, "Sharpe": sharpe, "Sortino": sortino,
        "Max drawdown": mdd, "Calmar": calmar, "VaR 95% (1d)": var95,
        "CVaR 95% (1d)": cvar95, "Longest underwater": longest_underwater(prices),
    }
    if benchmark is not None:
        b = benchmark.pct_change().dropna().reindex(r.index)
        out["Beta"] = r.cov(b) / b.var()
        out["Correlation"] = r.corr(b)
    return out


# The 2025 sell-off, three closes
spx = pd.Series(
    [6144.15, 4982.77, 5921.54],
    index=pd.to_datetime(["2025-02-19", "2025-04-08", "2025-05-27"]),
)
print(drawdown_series(spx)["drawdown"].round(4))
# 2025-02-19    0.0000
# 2025-04-08   -0.1890
# 2025-05-27   -0.0362

Implementation notes:

  • Sortino's downside deviation here uses all observations with positive excess returns set to zero, which is the standard definition. Some libraries divide only by the count of negative days, which gives a different number. Check before comparing.
  • Rolling metrics are more informative than one full-period number: r.rolling(63).std() * np.sqrt(252) for a 3-month rolling volatility, r.rolling(126).corr(b) for a 6-month rolling correlation that shows crisis spikes.
  • Use total return series (dividends reinvested) for long periods. Price-only series overstate drawdown durations.
  • Beware survivorship. Metrics computed on today's index members or surviving funds look better than what investors actually experienced.

Why this matters

  • Drawdown is the risk investors feel. Volatility is an abstraction; -18.9% on a statement is not.
  • Losses compound against you. A -50% year needs a +100% year. Avoiding large losses matters more than catching every gain.
  • Every ratio hides something. Sharpe hides tails, VaR hides the size of the tail, MDD hides how often, correlation hides regime changes. Use several.
  • Sizing is the lever you control. You cannot control the next sell-off, but you can choose how big it is in your portfolio.
  • The plan has to be written before the drawdown. Decisions made at the bottom are made by the worst version of yourself.

Final Thoughts

The spring 2025 sell-off was short by historical standards: seven weeks down, a violent one-day reversal, and a steady climb back to within a few percent of the high by late May. Short episodes are where risk metrics are most useful, because they are a cheap rehearsal. Look at what your portfolio did between February 19 and April 8, how you felt on April 8, and what you did about it.

If the numbers and your behavior both stayed inside the plan, the plan is about right. If not, adjust the sizing now, while the market is calm, rather than in the next drawdown.

Sources