Risk Metrics
SkillMonitoring & opsCompute portfolio risk measures including drawdown, VaR, CVaR, and tail metrics. Use when assessing portfolio risk beyond simple return statistics.
Use Risk Metrics in Claude, ChatGPT or Ahel Desktop
Free. Sign in, add Risk Metrics and connect your AI. About a minute.
Also: Claude Code · Cursor · Codex
Then ask your AI: use the Risk Metrics skill
Details
Instructions available. Your AI can read the instructions. Execution depends on the setup they require.
Account requirements not reviewed. Check the skill instructions before use; Ahel provides instructions and does not run this skill.
No other account needed.
Add Ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.
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
| Metric | Formula | Measures |
|---|---|---|
| Sharpe | mean(r) / std(r) * sqrt(252) | Risk-adjusted return |
| Sortino | mean(r) / sqrt(E[min(r,0)^2]) * sqrt(252) | Downside-adjusted return |
| Max drawdown | max peak-to-trough decline | Worst cumulative loss |
| Calmar | ann_return / |max_dd| | Return per unit of drawdown |
| VaR(95%) | 5th percentile of returns | Daily loss threshold |
| CVaR(95%) | mean of returns below VaR | Expected 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
- 22
- Forks
- 11
- Last commit
- Oct 2026
Advanced
- Item type
- skill
- Key
ml4t-risk-metrics- Source
- github.com/ml4t/skills
Related picks
Skill · wshobson
The pick for Pythonpython-pro
Skill · jeffallan
The pick for Pythonpandas-dataframe-analyzer
Skill · a5c-ai
The pick for Pandasxlsx
Skill · anthropics
The pick for Pandasinternal-comms
Skill · anthropics
More in Monitoring & opsagent-eval
Skill · affaan-m
More in Monitoring & ops