---
title: "ETF L1/L2/L3 return decomposition time series"
method: GET
path: "/data/etf/{ticker}/portfolio"
tags: ["Funds Data Plane"]
---

# ETF L1/L2/L3 return decomposition time series

`GET /data/etf/{ticker}/portfolio`

## Request

- Base URL: `https://riskmodels.app/api`
- URL: `https://riskmodels.app/api/data/etf/{ticker}/portfolio`
- Auth: one of:
  - HTTP bearer
  - none

An ETF's portfolio return decomposition (Funds_DAG `surface_portfolios_zarr`) — same `(teo,)` schema as `/api/funds/{bw_fund_id}/portfolio`: `portfolio_{gross,market,sector,subsector,idiosyncratic}_return`, `identity_residual`, `weight_sum`, `n_holdings_active`, `effective_n`, `top10_weight_sum`. The response reports `weight_basis` — v1 = `latest_holdings_constant` (the factor profile of the ETF's *current* composition over ERM3 monthly's full history; the time-varying month-end basis matching the per-fund semantic is a follow-on) — and `variance_shares` (the diversification-credited full-window market/sector/subsector/residual shares). Soft gateway auth (public read).

## Path parameters

- `ticker` string, required

## Query parameters

- `start_date` string, date
- `end_date` string, date

## Response `200`

ETF portfolio decomposition time series.

- SurfacePortfolioSeries: L1/L2/L3 return-decomposition time series for an ETF / benchmark PortfolioSurface (same shape funds expose). The first key is the surface id (`ticker` for ETFs, `benchmark_context_id` for benchmarks).
  - `portfolio_id` string
  - `ticker` string
  - `benchmark_context_id` string
  - `source_kind` 'fund' | 'etf' | 'benchmark' | 'filer_13f'
  - `weight_basis` 'latest_holdings_constant' | 'time_varying', nullable: How the per-teo weights were derived. v1 = latest_holdings_constant.
  - `teo_frequency` string
  - `variance_shares` object, nullable: Diversification-credited full-window variance shares (≈ sum to 1).
    - `market` number, nullable
    - `sector` number, nullable
    - `subsector` number, nullable
    - `residual` number, nullable
  - `n_rows` integer
  - `rows` object[]
    - `teo` string, date
    - `portfolio_gross_return` number, nullable
    - `portfolio_market_return` number, nullable
    - `portfolio_sector_return` number, nullable
    - `portfolio_subsector_return` number, nullable
    - `portfolio_idiosyncratic_return` number, nullable
    - `identity_residual` number, nullable
    - `weight_sum` number, nullable
    - `n_holdings_active` integer, nullable
    - `effective_n` number, nullable
    - `top10_weight_sum` number, nullable

## Other responses

- `404`: ETF not found or no portfolio decomposition available.

---

[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)
