---
title: "Cohort residual statistics (cross-section)"
method: GET
path: "/cohorts"
tags: ["Risk Metrics"]
---

# Cohort residual statistics (cross-section)

`GET /cohorts`

## Request

- Base URL: `https://riskmodels.app/api`
- URL: `https://riskmodels.app/api/cohorts`
- Auth: HTTP bearer

One-teo cross-section of cross-sectional residual statistics by cohort, from
`ds_erm3_cohorts`. A cohort is the market (level 1) or a GICS sector (level 2).

**Residuals are not zero-mean.** ERM3 regressions are fitted *without an
intercept*, deliberately, so each stock's residual retains its alpha. The
consequence is that the cross-sectional mean residual is **not zero**. If you
are building a relative-ranking signal, subtract `residual_mean` at the level
your residual is defined against — sector residuals demean within sector
cohorts. Any drift figure must be quoted with its window: the sign is not
stable across the sample.

`residual_sd` is the cross-sectional dispersion within a cohort — a measure of
how much there is to select from. It is a conditioning and allocation input,
not an alpha source; it multiplies skill and cannot create it. Read it with
`mean_pairwise_corr`, which separates idiosyncratic dispersion from common
movement.

Thin cohorts produce meaningless statistics — filter with `min_names`, and use
`n_effective` rather than `n_names` for anything breadth-related.

Public scope is SPY plus the 11 GICS sector SPDRs. The subsector cohort slate
is proprietary and is not addressable through this API.

## Query parameters

- `cohorts` string
- `variables` string
- `teo` string, date
- `date` string, date
- `min_names` integer

## Response `200`

Cohort cross-section

- CohortCrossSectionResponse: Cohort statistics across cohorts at one observation date.
  - `teo` string, date
  - `cohorts` CohortCrossSectionRow[]
    - `ticker` string: Cohort label (SPY or a GICS sector SPDR).
    - `level` 1 | 2: 1 = market, 2 = GICS sector.
    - `parent` string, nullable: Parent cohort's ticker; null for the market cohort.
    - `values` CohortStatistics: Cohort statistics for one (teo, cohort) cell. Keys present depend on the `variables` requested. Values are null where the statistic is undefined for that day.
      - `residual_mean` number, nullable: Equal-weighted mean member residual — the quantity to subtract when demeaning a relative-ranking signal at this level.
      - `residual_mean_cw` number, nullable: Cap-weighted equivalent; the EW/CW wedge is itself informative.
      - `residual_sd` number, nullable: Cross-sectional dispersion of member residuals — how much selection opportunity exists in the cohort. Read with `mean_pairwise_corr`.
      - `residual_skew` number, nullable
      - `residual_p10` number, nullable
      - `residual_p90` number, nullable
      - `mean_pairwise_corr` number, nullable: Mean pairwise correlation of member residuals, from a 63-day identity-based estimator. An estimate — do not present to high precision.
      - `n_names` integer, nullable: Member count that day. Guards every other statistic.
      - `n_effective` number, nullable: Inverse-Herfindahl breadth. Prefer this over `n_names` for anything power- or breadth-related — a cohort with one dominant constituent has far less effective breadth than its headcount suggests.
      - `weight_top1` number, nullable
      - `membership_churn` integer, nullable
      - `linked_beta` number, nullable: Beta of this cohort's factor to its parent's.
      - `link_fit_resid_sd` number, nullable: Residual standard deviation of the 252-day link regression (cohort factor on its parent), in daily-return units. A fit-quality / dispersion measure — NOT a standard error of `linked_beta`; do not build confidence intervals from it.
      - `linked_beta_r2` number, nullable: R² of the cohort factor on its parent. NOT the same quantity as `cohort_ER`.
      - `linked_beta_roll63` number, nullable: 63-day variant; instability in this is itself informative.
      - `cohort_factor_return` number, nullable
      - `cohort_residual_return` number, nullable: Factor return net of `linked_beta` × parent return.
      - `cohort_ER` number, nullable: Mean member's explained risk attributed to this level. An incremental attribution, not an R² share — it can be slightly negative and does not sum to 1.
      - `factor_source` integer, nullable: Provenance of the factor return that day. 0 = native; non-zero means a substitute instrument backed it. See `return_source_legend`.
  - `variables` string[]
  - `min_names` integer
  - `universe` string
  - `market_factor_etf` string
  - `store_build` string, nullable: Build timestamp of the underlying store.
  - `disclosures` CohortDisclosures: Interpretation notes that govern correct use of the cohort statistics. `no_intercept_contract` and `return_source_legend` are read from the store's own attributes rather than restated here, so they cannot drift from the data they describe.
    - `no_intercept_contract` string: ERM3 residuals are estimated WITHOUT an intercept and therefore retain each stock's alpha. The cross-sectional mean is NOT zero. If you are building relative-ranking signals, demean first using `residual_mean`.
    - `return_source_legend` string: Meaning of each `factor_source` code.
    - `coverage` string: Cohort coverage of the eligible universe (~88%) and the date from which full factor richness begins.
    - `dispersion_use` string: How to use `residual_sd` — a conditioning and allocation variable, not an alpha source.
    - `er_sign` string: Why `cohort_ER` is an incremental attribution that can be negative, and how it differs from `linked_beta_r2`.
    - `thin_cohorts` string: Why to filter on `min_names` and prefer `n_effective` for breadth.
  - `data_source` string

## Other responses

- `400`: Invalid request, or a cohort outside the addressable set.
- `404`: Cohort data unavailable
- `429`: Rate limit exceeded.
- `500`: Internal error

---

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