---
title: "Sector SPDR relative-strength leaderboard for one window"
method: GET
path: "/api/v1/etf/sectors/relative-strength"
tags: ["Funds & ETFs"]
---

# Sector SPDR relative-strength leaderboard for one window

`GET /api/v1/etf/sectors/relative-strength`

Cross-sector ranking of US sector SPDR ETFs by trailing return over a configurable window. Walks the 11 canonical S&P GICS sector SPDRs (XLB, XLC, XLY, XLP, XLE, XLF, XLV, XLI, XLRE, XLK, XLU), extracts the matching ``returns_<window>`` field from each ETF's latest B5 snapshot (or a dated snapshot via ``?date=YYYY-MM-DD``), and ranks DESC. Sectors missing a return (delisted, snapshot blob absent, or ETF history shorter than the window) are surfaced in ``missing_symbols`` with a structured reason and do not contribute to leader / laggard / spread / median. Use case: ``UC-3 Sector Rotation Detector`` - capital rotation signal without N round-trips.

## Query parameters

- `window` string — Trailing-return window. One of: 1m, ytd, 1y, 3y, 5y, 10y. Defaults to 1m.
- `date` string, nullable — Optional dated snapshot (YYYY-MM-DD). Defaults to the latest cycle.

## Response `200`

Sector relative-strength leaderboard payload.

- EnvelopeEtfSectorRelativeStrengthPayload
  - `data` EtfSectorRelativeStrengthPayload, required — UC-3.4 derived leaderboard of US sector SPDR returns over a configurable window. Reads the latest B5 ETF snapshot (or a dated snapshot via ``?date=``) for the 11 canonical S&P GICS sector SPDR ETFs, extracts the trailing return matching the requested ``window``, and ranks DESC. Missing sectors (symbol absent from universe / snapshot blob missing / return null because of insufficient ETF history) are surfaced in ``missing_symbols`` with a structured reason; they do not contribute to ``leader`` / ``laggard`` / ``spread`` / ``median``.
    - `window` string, required — Echoed window value (1m, ytd, 1y, 3y, 5y, or 10y).
    - `snapshot_date` string, required — ETF snapshot logical date (YYYY-MM-DD).
    - `sectors` EtfSectorStrengthEntry[], required — Ranked sector list, leader first. Excludes missing sectors.
      - `symbol` string, required — Sector SPDR ticker.
      - `sector_canonical` string, required — Canonical Sugra sector label (matches sector_taxonomy.CANONICAL_SECTORS).
      - `name` string, nullable — Fund full name from universe entry.
      - `return_pct` number, required — Trailing return for the requested window (matches the returns_<window> field on the snapshot, percentage units e.g. 2.45 = +2.45%).
      - `rank` integer, required — 1-indexed rank by return DESC. Ties broken by symbol alphabetical ASC.
      - `percentile` number, required — Position in the covered set as a percentile (top = 100.0, bottom = 0.0). Computed as (covered - rank) / max(covered - 1, 1) * 100.
    - `leader` EtfSectorStrengthExtremum — Top or bottom of the ranking.
      - `symbol` string, required
      - `sector_canonical` string, required
      - `return_pct` number, required
    - `laggard` EtfSectorStrengthExtremum — Top or bottom of the ranking.
      - `symbol` string, required
      - `sector_canonical` string, required
      - `return_pct` number, required
    - `spread_pct` number, nullable — leader.return_pct minus laggard.return_pct. Null when <2 sectors covered.
    - `median_pct` number, nullable — Median return across covered sectors. Null when zero sectors covered. For an even covered count this is the arithmetic mean of the two middle values.
    - `covered` integer, required — Number of sectors with a valid return for this window.
    - `missing_symbols` EtfSectorStrengthMissing[], required — Sectors excluded from the ranking with a structured reason.
      - `symbol` string, required
      - `sector_canonical` string, required
      - `reason` string, required — One of: not_in_universe, snapshot_missing, return_unavailable, delisted_candidate.
    - `data_source` string, nullable — Provenance of the underlying B5 ETF snapshot BLOBS (price + holdings origin). Since DATA-N4.4 the snapshot is rebuilt from Sugra Finance + SEC sources (exchange quotes + N-PORT); legacy blobs may still carry a retired commercial fund-summary token (DATA-N1). This describes the SNAPSHOT, not the ranked ``return_pct`` - since DATA-N4.1 the returns come from ``returns_source`` (``sugra_finance_historical``). Compare ``as_of`` against today to gauge snapshot freshness.
    - `returns_source` string, nullable — Provenance of the ranked ``return_pct`` values. Since DATA-N4.1 the trailing returns are computed at API read-time from Sugra's own historical module (``sugra_finance_historical``), NOT read from the snapshot blob (which defers these fields). Distinct from ``data_source``, which describes the snapshot blob's price + holdings origin.
    - `as_of` string, nullable — ISO-8601 timestamp of when the underlying snapshot blobs were taken (``snapshot_taken_at`` from the first covered ETF). For DATA-N1 this is the last good upstream cycle before disable.
  - `meta` SugraMeta, required — Metadata attached to every /api/v1/* response envelope.
    - `endpoint` string, required — Requested endpoint path.
    - `data_time` string, required — ISO 8601 UTC timestamp of the source data, not of the request.
    - `response_time` string, required — ISO 8601 UTC timestamp when this response was produced.
    - `provider` string, required — API name and version.
    - `source` string, nullable — Identifier of the primary upstream source used for this response.
    - `attribution` string, nullable — Human-readable attribution mandated by an upstream source (e.g. a securities regulator or self-regulatory organization). Present only on responses whose source requires the owner and source to be clearly identified. Do not remove or alter it when using the response.
    - `fallback_used` boolean, nullable — True when the primary source failed and a fallback produced the data.
    - `fallback_chain` string[], nullable — Ordered list of sources attempted, in the order they were tried.
    - `cached` boolean, nullable — True when this response was served from the internal cache.
    - `stale` boolean, nullable — True when the cached response was returned after the upstream rate-limited or errored. Clients can use this to detect degraded data.

## Other responses

- `401` — Missing or invalid `x-api-key` header. JSON body with a stable `code` distinguishing `missing_api_key` (no header sent) from `invalid_api_key` (header sent, key not accepted); any other 401 source carries the generic `unauthorized` with its detail as `reason`. Plus `hint`. `plan` is always null on 401 - an unauthenticated request has no plan; quota exhaustion is 429, not 401.
- `422` — Validation Error
- `429` — Daily rate limit exceeded. Check `X-RateLimit-Reset` for the next window.
- `503` — Upstream source is temporarily unavailable. Retry after a short delay.

---

[API](https://skmtc.net/sugra/apis/sugra-api.md) · [All operations](https://skmtc.net/sugra/apis/sugra-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/sugra/sugra-api/versions/4c4530760ba1/schema)
