Risk report
VaR (historical + parametric), Expected Shortfall, max drawdown, beta, tracking error, position variance contributions, concentration metrics, and worst-N historical stress scenarios for a portfolio. Pairs with portfolio-mark (which marks the book — risk-report tells you what could happen to those marks). Use when a PM, risk officer, or quant needs the full risk picture on a current book.From its SKILL.md
npx -y skills add rgourley/quant-garage --skill risk-reportAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 6 stars6 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
7.9 KB, ~1.9k tokens by cl100k_base, as published. Nobody here has run it
risk-report
You hand over a book — either inline weights or a positions JSON — and the skill returns the empirical risk picture: how volatile this book has been, how it co-moves with the benchmark, how bad the tail gets (VaR + Expected Shortfall), how deep the recent drawdown was, which historical days hurt most and which names did the damage, and which positions are doing the heavy lifting in the variance budget.
This is descriptive risk math on a current book. The script does NOT predict future returns. It tells you what the last N days of history say about how a book like the one you have just handed over has behaved.
When to invoke
- PM needs the daily risk snapshot on a current book
- Risk officer running a tail-risk review
- Researcher comparing book risk vs a benchmark
- Pre-trade check: "what does this proposed book look like?"
- Post-portfolio-mark follow-up: "we know what the book is worth; what could it lose?"
What you need
- A book: either inline
--positions T=w,T=w,...or a--book book.json(seeexamples/sample-book.json) MASSIVE_API_KEYexported
Optional:
- Benchmark ticker (default
SPY) for beta + tracking error + R² - Lookback window in trading days (default 252)
- VaR confidence levels (default
0.95,0.99) - Number of worst historical days to surface (default 5)
- Vol estimator (default
realized;ewmafor RiskMetrics EWMA with configurable λ, default 0.94, that responds faster to recent regime shifts)
What you get back
Two output layers from one analysis.
Layer 1: canonical JSON matching output-schema.json.
Per-book stats (vol, return, Sharpe, beta, alpha, tracking error,
correlation, R²). A full VaR block keyed by each requested confidence
level with historical VaR, parametric VaR, historical ES, parametric
ES. Max drawdown with peak/trough/duration/recovery. Worst-N stress
days with per-name loss attribution. Per-position variance
contribution and per-position beta to the benchmark.
Concentration: top-1/3/5 weights, Herfindahl, effective N.
tier_caveats for excluded names and the always-on methodology
warnings.
Layer 2: rendered PM report. Header line with the book and
lookback, a Portfolio statistics block, a VaR table (rows: historical,
parametric, ES — columns: each confidence), one-liner max drawdown,
the worst-N stress days with per-name attribution and the
benchmark's return on the same date, a Position contribution table
sorted by variance share, a Concentration line, then the adaptive
Take. The Take reads what's actually true about the book (high beta,
concentrated, big drawdown, low tracking error) and surfaces 2-3 of
the most striking facts in plain English. See references/
for the full methodology.
How it works
- Parse the book. Inline
--positions(weights sum to ≤ 1.0; the residual is implicit cash) or--bookJSON. The JSON format supports eitherweightper position orshares+price, in which case weights are computed from the value share. - Pull daily aggs per position and per benchmark over
--lookback-days(default 252). Massive's/v2/aggs/ticker/{T}/range/1/day/{from}/{to}?adjusted=trueso dividends and splits don't contaminate the vol estimate. - Compute log returns close-to-close. Align all series to the intersection of date indices so every metric reads from the same panel.
- Drop short series. A position with fewer than 60 aligned
trading days is excluded (surfaced in
tier_caveatsandpositions_excluded); the equivalent weight folds into the cash bucket so the math stays consistent. - Per-name annualized vol via
np.std(daily_returns, ddof=1) * sqrt(252). - Pairwise Pearson correlation matrix, 5%-shrunk toward identity
for numerical safety (same pattern as
position-sizer). Covariance from per-name vols × the shrunk correlation. - Portfolio daily returns as the weighted sum across names per day. This is the single time series every metric reads from.
- Stats: annualized vol, annualized mean return, naïve Sharpe; beta + alpha + tracking error + correlation + R² vs the benchmark.
- VaR + ES at each confidence:
- Historical VaR = -percentile(returns, 100 × (1 - confidence))
- Parametric VaR = z × σ - μ, where z = Φ⁻¹(confidence)
- Historical ES = -mean(returns ≤ VaR threshold)
- Parametric ES = -(μ - σ × φ(z) / (1 - confidence)) (Gaussian)
See
references/var-and-es.md.
- Max drawdown on the cumulative NAV (reconstructed from log
returns). Returns peak, trough, duration, and whether the series
recovered to the peak. See
references/max-drawdown.md. - Worst-N stress picks the N most-negative days in the
portfolio return series and attributes each day's loss to
individual names via
w_i × r_i_on_that_day. Seereferences/stress-scenarios.md. - Position variance contributions via the
MRC_i = w_i × (Σw)_idecomposition normalized to sum to 1. - Concentration stats: top-1/3/5, Herfindahl (Σw²), effective
N (1 / HHI). See
references/concentration.md. - Adaptive Take. Reads beta, top variance contributor share, Herfindahl, drawdown, and tracking error. Surfaces the 2-3 that actually matter for this book, in plain English.
Foundations used
massive-api-patternsfor REST auth and rate limiting on the daily aggs pull.
Output mode: report
The render is a top-to-bottom report — header, stats block, VaR table,
drawdown one-liner, stress days, position table, concentration line,
take, caveats. Closer to a daily risk note than a pure data dump,
because the PM/risk audience needs the take alongside the numbers.
See references/ for the per-section methodology.
MC mode
N/A. risk-report uses empirical historical distributions; it does not
run Monte Carlo. For distribution-of-outcomes sweeps see
valuation-sanity-check --mc.
Endpoints used
GET /v2/aggs/ticker/{ticker}/range/1/day/{from}/{to}?adjusted=trueDaily aggregates per name + per benchmark. One call per ticker per run; results cached per ticker.
Verify endpoint paths against current docs at massive.com/docs before shipping; field names and versions shift.
Doesn't handle (yet)
- Single-regime lookback. All math reads from one window. A multi-window comparison (60-day vs 252-day VaR) would show regime sensitivity; queued.
- No factor decomposition. Variance contribution is at the
position level, not the factor level. A factor-attributed
decomposition (size, value, momentum, quality) needs the
factor-researchmachinery wired in; obvious follow-up. - Cornish-Fisher / Student-t parametric VaR. Parametric VaR assumes normality; surfaces in caveats. A higher-moment variant is a clean PR.
- No conditional / stressed-period VaR. Worst-N is the closest thing; a regime-conditional VaR (e.g., compute VaR only on days when SPY was down) is a follow-up.
- No correlation-shock stress. "What if every correlation goes to 0.9" is queued; the worst-N empirical stress carries the day for v1.
- Single benchmark. Beta is vs one ticker. Multi-benchmark (SPY + IWM + EFA + AGG) needs a multi-regression; queued.
These are clean PR extensions. The output schema reserves space for each so adding them later doesn't break consumers.
What ships with it: 9 files
37.1 KB alongside SKILL.md
examples/
- sample-book.json210 B
references/
- concentration.md3.9 KB
- max-drawdown.md4.1 KB
- rendering.md4.9 KB
- stress-scenarios.md4.8 KB
- var-and-es.md4.6 KB
- output-schema.json8.2 KB
- README.md4.1 KB
- requires.yml2.3 KB