documentation/cookbook/sql/finance/maximum-drawdown.md
Maximum drawdown measures the largest percentage decline from a peak to a trough before a new peak is reached. It's a key risk metric showing the worst-case loss an investor would have experienced.
You want to measure downside risk beyond simple volatility. Standard deviation treats up and down moves equally, but investors care more about losses. Maximum drawdown shows the actual worst decline experienced.
DECLARE
@symbol := 'EURUSD',
@lookback := '$now - 1M..$now'
WITH with_peak AS (
SELECT
timestamp,
symbol,
close,
max(close) OVER (
PARTITION BY symbol
ORDER BY timestamp
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS running_peak
FROM market_data_ohlc_15m
WHERE symbol = @symbol
AND timestamp IN @lookback
),
with_drawdown AS (
SELECT
timestamp,
symbol,
close,
running_peak,
(close - running_peak) / running_peak * 100 AS drawdown
FROM with_peak
)
SELECT
timestamp,
symbol,
round(close, 5) AS close,
round(running_peak, 5) AS peak,
round(drawdown, 4) AS drawdown_pct,
round(min(drawdown) OVER (
PARTITION BY symbol
ORDER BY timestamp
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
), 4) AS max_drawdown_pct
FROM with_drawdown
ORDER BY timestamp;
The query:
max() OVER (... UNBOUNDED PRECEDING)DECLARE @symbol := 'EURUSD'
WITH with_peak AS (
SELECT timestamp, symbol, close,
max(close) OVER (PARTITION BY symbol ORDER BY timestamp ROWS UNBOUNDED PRECEDING) AS running_peak
FROM market_data_ohlc_15m
WHERE symbol = @symbol
),
with_drawdown AS (
SELECT timestamp, symbol, close, running_peak,
(close - running_peak) / running_peak * 100 AS drawdown
FROM with_peak
)
SELECT timestamp, symbol, round(close, 5) AS close, round(drawdown, 2) AS drawdown_pct
FROM with_drawdown
WHERE drawdown < -1 -- Drawdowns greater than 1%
ORDER BY drawdown
LIMIT 10;
:::info Related documentation