Skip to content
Research
KnowledgeVisuals
PricingRun a snapshotGet a free API key
Updates
Next filing · Form 10-Q · Q2 2026 · 53 days
Next filing · Form 10-Q · Q2 2026 · 53 daysFactor Research · Part 2 published: risk structure in 13F filings across five allocator stylesAPI Update · AOM portfolio chains — single snapshot call for multi-step analyze flowsAPI Update · POST /api/snapshot — canonical JSON portfolio snapshotPart 3 · The One Manager Skill That PersistsPart 1 · One Position, Four BetsNext filing · Form 10-Q · Q2 2026 · 53 daysFactor Research · Part 2 published: risk structure in 13F filings across five allocator stylesAPI Update · AOM portfolio chains — single snapshot call for multi-step analyze flowsAPI Update · POST /api/snapshot — canonical JSON portfolio snapshotPart 3 · The One Manager Skill That PersistsPart 1 · One Position, Four Bets
Ledger
    • Beyond Active Share
    • Cascade Hedging and the Cost of Interpretability
    • Decile One, Not Ticker by Ticker
    • ERM3 Cascade-Residual Persistence and the Allocator Skill Signal
    • Every Position Has a Level Too
    • RiskModels Quarterly Funds Report — Q1 2026
    • The Industry Beneath the Index
    • When does a spin-off start having returns?
    • Who got NVDA right before it became benchmark exposure?
  • Visuals
    • Concept graph (all)
    • Public glossary
  • Methodology
    • Filing calendar
    • API use-cases
    • Pricing↗
    • About

research/rankings-screen-stat-arb/article.md

raw ↗

Decile one, not ticker by ticker.

The most common quant question is the same shape every time. "Which names are in the top decile of [some metric] today?"

The honest answer for most APIs is also the same. "Loop over the universe, pull the metric per ticker, sort client-side, take the top 10%."

That answer scales like the universe. Three thousand names, one HTTP call each. Ten metrics, three windows, three cohorts — and you're paying for ninety thousand calls to ask one cross-sectional question.

There is a better question shape, and an API surface that matches it.


One call, one cross-section

POST /api/rankings/screen takes a metric, cohort, window triple and a filter (percentile, decile, or sector), and returns up to 500 rows from the universe — already ranked, already filtered, ready to act on.

POST /api/rankings/screen
{
  "metric":  "subsector_residual",
  "cohort":  "subsector",
  "window":  "21d",
  "decile":  1,
  "limit":   50
}

That's the entire request. The response is a sorted list of the top-decile 21-day subsector residual names — what stat-arb desks call "the long book before the carry filter." Same call shape works for market-cap leadership inside a sector, for short-window outperformers, for any of the seven indexed metrics across any of the three cohorts and four windows.

$0.02 per call. One round-trip.


Why this shape exists

The ranking is precomputed. ds_rankings_{etf}_{universe}.zarr holds 96 ranking variables per (teo, symbol) — every metric × cohort × window combination already sorted and percentile-tagged by the ERM3 pipeline at 1d cadence. The screen endpoint isn't doing the math; it's doing server-side selection on a panel that's already ranked.

The alternative — pulling each ticker's row and ranking client-side — recomputes what the pipeline already computed, costs N times more, and asks for N times more network round-trips. The screen endpoint replaces N with 1.


What it changes

BeforeAfter
Loop 3,000 tickers through /rankings to find decile 1One call returning the 300 names in decile 1
Fetch metric column, sort in pandas, take top 5%min_percentile: 95, limit: 150 server-side
Subset by sector after the factsector_filter: "XLK" in the request body
Pay per-ticker for a question that's cross-sectionalPay per screen

The mechanic isn't surprising once you've seen it. The product change is that the screening is a first-class request shape on the API, not a workflow you have to assemble.


Use cases

Stat-arb residual screen

The classic. Subsector residual return, top decile, 21-day window. Stat-arb long book candidates.

from riskmodels import RiskModelsClient
client = RiskModelsClient.from_env()

longs = client.screen_rankings(
    metric="subsector_residual",
    cohort="subsector",
    window="21d",
    decile=1,           # 1 = best
    limit=100,
    as_dataframe=True,
)

Cap-rank leadership inside a sector

Which financials are the biggest by market cap today, ranked within their sector cohort.

top_xlf = client.screen_rankings(
    metric="mkt_cap",
    cohort="sector",
    window="1d",
    sector_filter="XLF",
    limit=20,
)

Cross-windows momentum check

Same metric, two windows, one decile. Names in top decile of 252d AND top decile of 21d are the persistent winners.

persistent = (
    client.screen_rankings(metric="gross_return", cohort="universe", window="21d", decile=1, limit=300)
    .merge(
        client.screen_rankings(metric="gross_return", cohort="universe", window="252d", decile=1, limit=300),
        on="ticker",
        suffixes=("_21d", "_252d"),
    )
)

Where it sits next to the rest of the stack

The rank screen is the cross-sectional gateway. Pair it with:

  • POST /api/batch/lstar — feed the screen's ticker list into a batch Lstar history pull for the names that passed. The combination is "what's the residual-clean Lstar history for today's top-decile screen?" — two HTTP calls instead of N + N.
  • GET /api/industry-panel — the macro view (industries × β) sitting alongside the micro view (tickers × rank). Cross-reference: high within-industry beta_variance × top-decile residual screen = "industries where stock-picking is paying off and the picks are running."
  • POST /decompose — for each name that passes the screen, the four-bet hedge map is one more call away.

The principle

Don't loop a cross-sectional question. Ask it cross-sectionally.

The ERM3 pipeline already ranks the universe daily. The screen endpoint just lets you query that rank like a database — one filter, one response, one bill.

Try the rankings screen on the API → · Full endpoint docs →

← Cascade Hedging and the Cost of InterpretabilityResearch · 3 / 9ERM3 Cascade-Residual Persistence and the Allocator Skill Signal →
Get a free API keyRun on your portfolio

RiskModels.org

A research surface for hierarchical orthogonal decomposition, variance attribution, and allocator-grade risk measurement. Operational APIs and developer workflows live at riskmodels.app.

Subscribe to the Quarterly Attribution Review.

Research notes on risk decomposition, fund attribution, 13F filings, and benchmark structure — a few times a quarter.

By registering, you agree to receive technical factor research and API deployment logs. RM-Registry-2026. Privacy Policy.

Sign inHomePrimerWorkspaceResearchKnowledgeConceptsReviewsLedgerReferencesAboutSubscribeMethodology noteOne-pagerAPI docsWeb appContactPrivacyStatusRSS
RiskModelsResearch/Workspace/API
Skip to content
Research
KnowledgeVisuals
PricingRun a snapshotGet a free API key
Updates
Next filing · Form 10-Q · Q2 2026 · 53 days
Next filing · Form 10-Q · Q2 2026 · 53 daysFactor Research · Part 2 published: risk structure in 13F filings across five allocator stylesAPI Update · AOM portfolio chains — single snapshot call for multi-step analyze flowsAPI Update · POST /api/snapshot — canonical JSON portfolio snapshotPart 3 · The One Manager Skill That PersistsPart 1 · One Position, Four BetsNext filing · Form 10-Q · Q2 2026 · 53 daysFactor Research · Part 2 published: risk structure in 13F filings across five allocator stylesAPI Update · AOM portfolio chains — single snapshot call for multi-step analyze flowsAPI Update · POST /api/snapshot — canonical JSON portfolio snapshotPart 3 · The One Manager Skill That PersistsPart 1 · One Position, Four Bets
Ledger
    • Beyond Active Share
    • Cascade Hedging and the Cost of Interpretability
    • Decile One, Not Ticker by Ticker
    • ERM3 Cascade-Residual Persistence and the Allocator Skill Signal
    • Every Position Has a Level Too
    • RiskModels Quarterly Funds Report — Q1 2026
    • The Industry Beneath the Index
    • When does a spin-off start having returns?
    • Who got NVDA right before it became benchmark exposure?
  • Visuals
    • Concept graph (all)
    • Public glossary
  • Methodology
    • Filing calendar
    • API use-cases
    • Pricing↗
    • About

research/rankings-screen-stat-arb/article.md

raw ↗

Decile one, not ticker by ticker.

The most common quant question is the same shape every time. "Which names are in the top decile of [some metric] today?"

The honest answer for most APIs is also the same. "Loop over the universe, pull the metric per ticker, sort client-side, take the top 10%."

That answer scales like the universe. Three thousand names, one HTTP call each. Ten metrics, three windows, three cohorts — and you're paying for ninety thousand calls to ask one cross-sectional question.

There is a better question shape, and an API surface that matches it.


One call, one cross-section

POST /api/rankings/screen takes a metric, cohort, window triple and a filter (percentile, decile, or sector), and returns up to 500 rows from the universe — already ranked, already filtered, ready to act on.

POST /api/rankings/screen
{
  "metric":  "subsector_residual",
  "cohort":  "subsector",
  "window":  "21d",
  "decile":  1,
  "limit":   50
}

That's the entire request. The response is a sorted list of the top-decile 21-day subsector residual names — what stat-arb desks call "the long book before the carry filter." Same call shape works for market-cap leadership inside a sector, for short-window outperformers, for any of the seven indexed metrics across any of the three cohorts and four windows.

$0.02 per call. One round-trip.


Why this shape exists

The ranking is precomputed. ds_rankings_{etf}_{universe}.zarr holds 96 ranking variables per (teo, symbol) — every metric × cohort × window combination already sorted and percentile-tagged by the ERM3 pipeline at 1d cadence. The screen endpoint isn't doing the math; it's doing server-side selection on a panel that's already ranked.

The alternative — pulling each ticker's row and ranking client-side — recomputes what the pipeline already computed, costs N times more, and asks for N times more network round-trips. The screen endpoint replaces N with 1.


What it changes

BeforeAfter
Loop 3,000 tickers through /rankings to find decile 1One call returning the 300 names in decile 1
Fetch metric column, sort in pandas, take top 5%min_percentile: 95, limit: 150 server-side
Subset by sector after the factsector_filter: "XLK" in the request body
Pay per-ticker for a question that's cross-sectionalPay per screen

The mechanic isn't surprising once you've seen it. The product change is that the screening is a first-class request shape on the API, not a workflow you have to assemble.


Use cases

Stat-arb residual screen

The classic. Subsector residual return, top decile, 21-day window. Stat-arb long book candidates.

from riskmodels import RiskModelsClient
client = RiskModelsClient.from_env()

longs = client.screen_rankings(
    metric="subsector_residual",
    cohort="subsector",
    window="21d",
    decile=1,           # 1 = best
    limit=100,
    as_dataframe=True,
)

Cap-rank leadership inside a sector

Which financials are the biggest by market cap today, ranked within their sector cohort.

top_xlf = client.screen_rankings(
    metric="mkt_cap",
    cohort="sector",
    window="1d",
    sector_filter="XLF",
    limit=20,
)

Cross-windows momentum check

Same metric, two windows, one decile. Names in top decile of 252d AND top decile of 21d are the persistent winners.

persistent = (
    client.screen_rankings(metric="gross_return", cohort="universe", window="21d", decile=1, limit=300)
    .merge(
        client.screen_rankings(metric="gross_return", cohort="universe", window="252d", decile=1, limit=300),
        on="ticker",
        suffixes=("_21d", "_252d"),
    )
)

Where it sits next to the rest of the stack

The rank screen is the cross-sectional gateway. Pair it with:

  • POST /api/batch/lstar — feed the screen's ticker list into a batch Lstar history pull for the names that passed. The combination is "what's the residual-clean Lstar history for today's top-decile screen?" — two HTTP calls instead of N + N.
  • GET /api/industry-panel — the macro view (industries × β) sitting alongside the micro view (tickers × rank). Cross-reference: high within-industry beta_variance × top-decile residual screen = "industries where stock-picking is paying off and the picks are running."
  • POST /decompose — for each name that passes the screen, the four-bet hedge map is one more call away.

The principle

Don't loop a cross-sectional question. Ask it cross-sectionally.

The ERM3 pipeline already ranks the universe daily. The screen endpoint just lets you query that rank like a database — one filter, one response, one bill.

Try the rankings screen on the API → · Full endpoint docs →

← Cascade Hedging and the Cost of InterpretabilityResearch · 3 / 9ERM3 Cascade-Residual Persistence and the Allocator Skill Signal →
Get a free API keyRun on your portfolio

RiskModels.org

A research surface for hierarchical orthogonal decomposition, variance attribution, and allocator-grade risk measurement. Operational APIs and developer workflows live at riskmodels.app.

Subscribe to the Quarterly Attribution Review.

Research notes on risk decomposition, fund attribution, 13F filings, and benchmark structure — a few times a quarter.

By registering, you agree to receive technical factor research and API deployment logs. RM-Registry-2026. Privacy Policy.

Sign inHomePrimerWorkspaceResearchKnowledgeConceptsReviewsLedgerReferencesAboutSubscribeMethodology noteOne-pagerAPI docsWeb appContactPrivacyStatusRSS
RiskModelsResearch/Workspace/API