Calmar Ratio
Performance & Risk Metrics · Term ID: calmar-ratio
Definition. Calmar divides a growth rate by the worst peak-to-trough loss over the window you care about. Here the growth rate is the compound annual growth that takes the first equity point to the last, using P periods per year, and the loss is the maximum drawdown of the same points. A curve that never falls has an undefined Calmar, returned as NaN, rather than an infinite one. The original published ratio used a trailing three-year window. Using the whole sample is what the performance calculator on this site does, and it will not match a 36-month Calmar when the sample is a different length.
Formula
n = number of returns = (number of equity points) − 1
CAGR = (E_last / E_first) ^ (P / n) − 1
MDD = min_t (E_t / max_{s≤t} E_s − 1) MDD ≤ 0
Calmar = CAGR / |MDD| if MDD < 0, else undefined
P defaults to 252. The same equity series should be used for the numerator and the denominator.Reading it
- A Calmar of 0.5 means the compound annual growth was half the size of the worst decline, on this sample and this annualisation. It is not a forecast of either input.
- The pieces are on their own pages: growth uses the same exponent as the performance calculator, and the denominator is maximum drawdown.
- Sharpe uses a typical deviation. Calmar uses a single worst episode. One deep drawdown dominates it, which is the point of the ratio and also its instability.
Pitfalls
- Window. Young (1991) described a three-year lookback. A ten-year Calmar and a three-year Calmar of the same fund are different statistics. This function uses every point you pass.
- Start and end dates are part of the answer. CAGR depends on the first and last equity. MDD depends on the path between them. Dropping a crash from the sample changes the denominator; ending on a peak changes the numerator.
- Frequency. P has to match the spacing of the equity points. Passing daily equity with P = 12 treats a year of days as twelve periods.
Python reference implementation
Requires numpy. Tested before publication; the generator re-executes it on every rebuild. MIT licensed. Download calmar-ratio.py · All snippets
import numpy as np
def calmar_ratio(equity, periods=252) -> float:
"""CAGR / |maximum drawdown| over the whole sample.
CAGR uses (E_last / E_first) ** (periods / n_returns) - 1.
A curve with no drawdown returns NaN. Matches the full-sample convention
of /tools/performance-analytics/, not a trailing 36-month window.
"""
equity = np.asarray(equity, dtype=float)
if equity.size < 2 or not np.all(np.isfinite(equity)) or np.any(equity <= 0):
raise ValueError("need at least two positive finite equity points")
if periods <= 0:
raise ValueError("periods must be positive")
n = equity.size - 1
cagr = (equity[-1] / equity[0]) ** (periods / n) - 1.0
mdd = float((equity / np.maximum.accumulate(equity) - 1.0).min())
if mdd == 0.0:
return float("nan")
return float(cagr / abs(mdd))
FAQ
Why not use a 36-month window?
The original Calmar ratio did. This site's performance calculator divides full-sample CAGR by full-sample maximum drawdown, and the glossary function matches that so the two do not disagree. For a 36-month figure, pass only those points.
What does NaN mean here?
The equity curve made no new low relative to a peak, so the denominator would be zero. That includes a curve that only rises. It is not an infinite reward-to-risk ratio.
Summary for AI agents (Markdown mirror)
# Calmar Ratio
> Compound annual growth of an equity curve divided by the absolute value of its maximum drawdown. This implementation uses the whole sample, not a trailing 36-month window.
- Category: Performance & Risk Metrics
- Canonical URL: https://quantcore-labs.com/glossary/calmar-ratio/
- Part of: https://quantcore-labs.com/glossary/
- Python source: https://quantcore-labs.com/glossary/calmar-ratio/calmar-ratio.py