Risk Metrics

SkillMonitoring & ops

Compute portfolio risk measures including drawdown, VaR, CVaR, and tail metrics. Use when assessing portfolio risk beyond simple return statistics.

Available today. Use it from your connected AI after setup.

Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.

Then ask your AI: use the Risk Metrics skill

What this skill tells your AI

The instructions your AI receives, as published by ml4t/skills in portfolio/risk-metrics/SKILL.md and read by ahel’s review.

A strategy with Sharpe 1.5 and max drawdown -55% will get shut down before it recovers. Reporting returns without drawdowns, tail risk, and duration metrics hides the path dependency that determines whether a strategy survives.

The Problem

Sharpe ratio is the default performance metric, but it treats upside and downside volatility equally and says nothing about tail losses. A strategy can have a high Sharpe while hiding a -40% drawdown that takes 18 months to recover. Fund managers and allocators care about max drawdown, time underwater, and worst-case losses - because those determine whether the strategy (and the fund) survives. Always report drawdown alongside return metrics.

The Pattern

WRONG

import numpy as np

returns = strategy_returns  # daily
sharpe = returns.mean() / returns.std() * np.sqrt(252)
print(f"Sharpe: {sharpe:.2f}")  # Looks great - ships it

CORRECT

import numpy as np
from scipy.stats import norm

returns = strategy_returns  # daily, numpy array

# Return metrics
sharpe = returns.mean() / returns.std() * np.sqrt(252)
downside = np.minimum(returns, 0)  # All returns: negative kept, positive → 0
sortino = returns.mean() / np.sqrt((downside ** 2).mean()) * np.sqrt(252)

# Drawdown
cumulative = np.cumprod(1 + returns)
running_max = np.maximum.accumulate(cumulative)
drawdown = (cumulative - running_max) / running_max
max_dd = drawdown.min()
calmar = (returns.mean() * 252) / abs(max_dd)

# Tail risk (95% confidence)
var_95 = np.percentile(returns, 5)
cvar_95 = returns[returns <= var_95].mean()

print(f"Sharpe: {sharpe:.2f} | Sortino: {sortino:.2f} | Calmar: {calmar:.2f}")
print(f"Max DD: {max_dd:.1%} | VaR(95): {var_95:.1%} | CVaR(95): {cvar_95:.1%}")

Metric Reference

MetricFormulaMeasures
Sharpemean(r) / std(r) * sqrt(252)Risk-adjusted return
Sortinomean(r) / sqrt(E[min(r,0)^2]) * sqrt(252)Downside-adjusted return
Max drawdownmax peak-to-trough declineWorst cumulative loss
Calmarann_return / |max_dd|Return per unit of drawdown
VaR(95%)5th percentile of returnsDaily loss threshold
CVaR(95%)mean of returns below VaRExpected loss in tail

Parametric vs Historical VaR

# Historical: uses actual distribution (captures fat tails)
var_hist = np.percentile(returns, 5)

# Parametric: assumes normal (underestimates tails)
var_param = returns.mean() + norm.ppf(0.05) * returns.std()

# Always prefer historical unless you need scenario-based VaR

Guardrails

  • Never report Sharpe alone - always include max drawdown and Calmar at minimum
  • VaR underestimates tail risk by design - pair it with CVaR (Expected Shortfall)
  • Historical VaR assumes the past contains the worst case - it does not
  • Annualize consistently: multiply mean by 252, std by sqrt(252) for daily data
  • Monitor current drawdown in real time, not just historical max

Production Implementation

ml4t-diagnostic provides validated risk computation:

from ml4t.diagnostic.api import PortfolioAnalysis

pa = PortfolioAnalysis(returns=strategy_returns, benchmark=benchmark_returns)
metrics = pa.compute_summary_stats()
report = metrics.summary()  # Sharpe, Sortino, max_dd, Calmar, VaR, CVaR, etc.

Checklist

  • Sharpe, Sortino, and Calmar all reported (not Sharpe alone)
  • Max drawdown and drawdown duration computed
  • CVaR computed alongside VaR for tail risk
  • Metrics annualized consistently (daily * sqrt(252))
  • Current drawdown monitored in live systems (not just historical max)

Signals

GitHub stars
20
Forks
11
Last commit
Sep 2026
Advanced
Item type
skill
Key
ml4t-risk-metrics
Source
github.com/ml4t/skills