做什么(One-liner)
单标的 vs benchmark 的 historical 风险指标一站式计算:annual return / vol / Sharpe、max drawdown、beta、VaR 95% / 99% + CVaR 95% / 99%、audit-friendly windows tag。Canvas risk_management_v1 graphlet 的实际后端。
怎么用
POST /portfolio/risk-metrics body:
{
"symbol": "AAPL",
"benchmark": "SPY",
"period": "1y",
"confidence_levels": [0.95, 0.99]
}Canvas 自动 wire 这个 —— 用户无需手动 fetch。Batch Signals 面板也可以从 "Risk metrics" 按钮触发。
核心公式
详见 frontmatter。简要:
- VaR = absolute value of left-tail quantile
- CVaR = conditional mean of worst-case tail(ES = expected shortfall)
- Max Drawdown = min of running DD
- Beta = Cov(symbol, benchmark) / Var(benchmark)
- Sharpe = (annual_return - 0.045) / annual_vol
假设与适用场景
假设:historical simulation OK + daily 1y + 60s cache + rf = 4.5% + yfinance adjusted close。
适用:美股 / developed-market ETF 风险快照、Canvas risk node 执行、单标的 risk overlay。
不适用:parametric VaR、组合 aggregation、非美 / 非 equity、EVT 极端尾部、custom rf。
输入 / 输出契约
{symbol, benchmark?, period?, confidence_levels?} → {symbol, benchmark, period, n_observations, annual_return, annual_volatility, sharpe_ratio, max_drawdown, beta, var_95pct, cvar_95pct, var_99pct, cvar_99pct, windows}。
Beta 可能 null(benchmark fetch 失败或 <20 obs)。status=partial 表示 yfinance 失败。
已知局限
- Historical simulation 假设(crisis 期失败)
risk_free_rate = 0.045hardcoded- 单标的 only(无 portfolio aggregation)
- 60s cache(freshness 延迟)
- Beta=null 静默 fallback
- 不输出 skewness / kurtosis(legacy fn 曾输出,本 route 删了)
参考文献
Jorion (2006) Value at Risk + Artzner et al. (1999) Coherent Measures of Risk (CVaR) + Magdon-Ismail & Atiya (2004) MaxDD + BCBS d457 (2019) MAR50。详见 frontmatter。
Golden Test
tests/golden/fixtures/tier2/portfolio_risk_metrics/,yfinance-mock regression (2-symbol with embedded β=1.2)。1e-10 tolerance。6 tests:
matches_snapshot— 全 output byte-equaldeterminism— 5 reruns identicalvar_ordering— 99% VaR > 95% VaR (magnitude),CVaR ≥ VaR 同 confidence(coherent risk 不等式)beta_recovery— embedded β=1.2 recovered within ±0.1rejects_missing_symbol— ZZZZ → status=partial, _error_kind=networkresult_structure— 15 固定 top-level keys
Note on testing history
2026-04-20 post-audit 时发现早期 golden(closed PR #38)错误 target 了 services/analysis/risk.py::analyze_risk_management —— legacy dead function,Canvas 不用。触发来自用户观察 "Canvas 上看着没问题"。重建 golden 指向真 route + 删除 legacy function。
Changelog
- 1.0.0 (2026-04-20) — 首次 Active(real Canvas route after legacy cleanup)

