Skip to content

做什么(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:

json
{
  "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 失败。

已知局限

  1. Historical simulation 假设(crisis 期失败)
  2. risk_free_rate = 0.045 hardcoded
  3. 单标的 only(无 portfolio aggregation)
  4. 60s cache(freshness 延迟)
  5. Beta=null 静默 fallback
  6. 不输出 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-equal
  • determinism — 5 reruns identical
  • var_ordering — 99% VaR > 95% VaR (magnitude),CVaR ≥ VaR 同 confidence(coherent risk 不等式)
  • beta_recovery — embedded β=1.2 recovered within ±0.1
  • rejects_missing_symbol — ZZZZ → status=partial, _error_kind=network
  • result_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)

Verifiable intelligence for the decisions that demand scrutiny.