---
title: "Composed fund snapshot (JSON)"
method: GET
path: "/funds/snapshot/{bw_fund_id}"
tags: ["Funds"]
---

# Composed fund snapshot (JSON)

`GET /funds/snapshot/{bw_fund_id}`

## Request

- Base URL: `https://riskmodels.app/api`
- URL: `https://riskmodels.app/api/funds/snapshot/{bw_fund_id}`
- Auth: HTTP bearer

Composed JSON snapshot for a single mutual fund. Bundles registry + latest metrics + top-25 holdings + L1/L2/L3 hedge + 12-month portfolio time series + cohort context (rank N of `cohort_size` on every metric the rankings table covers).

The matching server-rendered PDF is `/api/funds/snapshot.pdf/{bw_fund_id}` (Stage D.2.b, ✅ shipped). The SDK can render this JSON locally via `riskmodels.snapshots.f1_fund_tearsheet` (Stage D.3, planned).

## Path parameters

- `bw_fund_id` string, required

## Response `200`

Composed fund snapshot.

- FundSnapshotResponse: Composed JSON snapshot for a single mutual fund. Bundles registry + latest metrics + top-25 holdings + L1/L2/L3 hedge + 12-month portfolio time series + cohort context (rank-within-cell on every metric the rankings table covers).
  - `bw_fund_id` string, required
  - `ticker` string, nullable
  - `fund_name` string, nullable
  - `equity_style_9box` string, nullable
  - `report_date` string, date, required
  - `filing_date` string, date, required
  - `metrics` FundMetricsResponse, required: Latest knowledge-mode metrics for a single mutual fund. Joins `public.funds` (registry) with `public.funds_latest` (the wide-row snapshot) and groups return components / diagnostics / meta into nested objects. Bitemporal triple is at the top level; lineage in `_metadata`.
    - `bw_fund_id` string, required
    - `ticker` string, nullable
    - `fund_name` string, nullable
    - `equity_style_9box` 'Large Value' | 'Large Blend' | 'Large Growth' | 'Mid Value' | 'Mid Blend' | 'Mid Growth' | 'Small Value' | 'Small Blend' | 'Small Growth', nullable
    - `report_date` string, date, required
    - `filing_date` string, date, required
    - `extracted_at` string, date-time, required
    - `returns` object, required: Portfolio-level return components from the per-fund Slice 8 zarr.
      - `gross` number, float, nullable
      - `market` number, float, nullable
      - `sector` number, float, nullable
      - `subsector` number, float, nullable
      - `idiosyncratic` number, float, nullable
      - `identity_residual` number, float, nullable: L3 noise diagnostic (gross − sum of layer returns).
    - `diagnostics` object, required
      - `weight_sum` number, float, nullable: ERM3 universe coverage (fraction of fund AUM in mapped symbols).
      - `n_holdings_active` integer, nullable
      - `effective_n` number, float, nullable: HHI-derived diversification (1 / sum(w_i^2)).
      - `top10_weight_sum` number, float, nullable
    - `meta` object, required
      - `total_adj_mv` number, float, nullable
      - `n_funds_in_cell_at_report_date` integer, nullable
      - `morningstar_category` string, nullable
      - `primary_bw_fund_id` string, nullable
      - `status` 'active' | 'delisted', nullable
      - `death_date` string, date, nullable
      - `latest_report_date` string, date, nullable: Period end of the fund's last reported holdings.
    - `_metadata` object, required
      - `model_version` string, nullable
      - `factor_set_id` string, nullable
      - `data_as_of` string, date
      - `data_freshness` string, date-time
      - `last_synced_at` string, date-time
  - `holdings` object, nullable
    - `n_total_holdings` integer
    - `n_returned` integer
    - `top` FundHolding[]
      - `ticker` string, nullable: Ticker from the symbol registry. Null for the few holdings whose symbol is not in the registry; `bw_sym_id` still identifies them.
      - `bw_sym_id` string, required: Internal symbol id. Resolve to ticker via POST /api/data/symbols/batch with {"symbols": [...]}.
      - `adj_mv` number, float, required: Adjusted market value (USD) of this position at the report date. Negative for a short.
      - `weight` number, float, nullable: Signed fraction of the denominator named by the response's `weight_basis` (reported net assets on `/funds/{bw_fund_id}/holdings`; `aum_erm3` in fund snapshots). Null when that denominator is null/0.
  - `hedge` FundHedgeResponse: Latest L1/L2/L3 hedge ratios for a fund. Empty arrays are emitted for levels with no non-NaN entries (e.g. small / niche funds may only have an L1 market hedge). Composing a full hedge basket means concatenating L1 + L2 + L3 entries.
    - `bw_fund_id` string, required
    - `ticker` string, nullable
    - `fund_name` string, nullable
    - `equity_style_9box` string, nullable
    - `teo` string, date, required: Latest teo that carries a hedge. Trailing teos with no book (past the holdings forward-fill cap) are skipped.
    - `holdings_teo` string, date, nullable: Report date of the filed holdings behind `teo`'s weights. Holdings are carried forward onto later month-ends between filings, so this can be months before `teo`. Hedge ratios are per dollar of the fund's ERM3-universe book (holdings outside the ERM3 universe are excluded; a holding without a hedge ratio counts as unhedged).
    - `L1` FundHedgeLeg[], required
      - `etf` string, required: ETF symbol (e.g. SPY, XLK, SMH).
      - `hr` number, float, required: Hedge ratio (dollar_ratio) — ETF notional per $1 of fund exposure at this level.
    - `L2` FundHedgeLeg[], required
      - `etf` string, required: ETF symbol (e.g. SPY, XLK, SMH).
      - `hr` number, float, required: Hedge ratio (dollar_ratio) — ETF notional per $1 of fund exposure at this level.
    - `L3` FundHedgeLeg[], required
      - `etf` string, required: ETF symbol (e.g. SPY, XLK, SMH).
      - `hr` number, float, required: Hedge ratio (dollar_ratio) — ETF notional per $1 of fund exposure at this level.
  - `portfolio_history` object, required
    - `lookback_months` integer, required
    - `n_periods` integer, required
    - `rows` FundPortfolioRow[], required
      - `teo` string, date, required
      - `portfolio_gross_return` number, float, nullable
      - `portfolio_market_return` number, float, nullable
      - `portfolio_sector_return` number, float, nullable
      - `portfolio_subsector_return` number, float, nullable
      - `portfolio_idiosyncratic_return` number, float, nullable
      - `identity_residual` number, float, nullable
      - `weight_sum` number, float, nullable
      - `n_holdings_active` integer, nullable
      - `effective_n` number, float, nullable
      - `top10_weight_sum` number, float, nullable
  - `nav_history` object, nullable: Trailing 12-month yfinance NAV history. `null` when the fund has no yfinance-resolvable ticker (~35% of the universe — institutional SMAs, separately-managed accounts, mutual funds without retail tickers). Pair with `portfolio_history` on the same teos to surface the gap between 13F-derived attribution and realised NAV (intra-quarter trading, fees, cash drag).
    - `lookback_months` integer, required
    - `n_periods` integer, required
    - `rows` FundNavRow[], required
      - `teo` string, date, required
      - `nav_close` number, float, nullable: Month-end close price from yfinance.
      - `nav_return_monthly` number, float, nullable: pct_change of consecutive month-end closes (the realised return).
  - `cohort_context` object, nullable
    - `equity_style_9box` string, nullable
    - `n_funds_in_cell` integer, nullable
    - `ranks` FundCohortRankEntry[]
      - `metric` string, required
      - `period_window` '1m' | '3m' | '12m' | '36m', required
      - `rank` integer, required
      - `cohort_size` integer, nullable
      - `value` number, float, nullable
  - `_metadata` object, required
    - `model_version` string, nullable
    - `factor_set_id` string, nullable
    - `data_as_of` string, date
    - `data_freshness` string, date-time

## Other responses

- `402`: Insufficient prepaid balance.
- `404`: Fund not found, or no funds_latest row.
- `422`: Long-short fund; the F1 sheet is not available and nothing is billed. Returned when the latest filed book has a short leg of at least 5% of N-PORT net assets, a net book under 50% of net assets with a short leg of at least 1%, or (no NET_ASSETS header) a short leg of at least 5% of gross. Body: `error` = "long-short fund: sheet not available", `code` = `long_short_sheet_unavailable`, `detail` with the rule and the book ratios. Use `/api/funds/{bw_fund_id}/holdings` for the signed book.
- `429`: Rate limit exceeded.

---

[API](https://skmtc.dev/riskmodels/apis/riskmodels-api.md) · [All operations](https://skmtc.dev/riskmodels/apis/riskmodels-api/llms.txt) · [OpenAPI document](https://skmtc.dev/riskmodels/apis/riskmodels-api/revisions/1a034cad408a?raw)
