GET /api/metrics/regime-transitions Regime Transitions
A log of the moments assets changed trend regime — for example, every stock that entered a Leading Trend last year, and when. Each entry records the label before and after, plus a snapshot of the asset’s metrics on the day it changed.
Request
# Assets that entered Leading Trend on the 200w-CAPR window in 2024
curl "https://api.bytetree.io/api/metrics/regime-transitions?window=200w-CAPR®ime=Leading%20Trend&from=2024-01-01&to=2024-12-31"
# Any 30d-CAPR transition in the last 90 days for active stocks
curl "https://api.bytetree.io/api/metrics/regime-transitions?window=30d-CAPR&direction=any&from=2026-02-01&type=stock&status=active"
# Custom metric snapshot at transition
curl "https://api.bytetree.io/api/metrics/regime-transitions?window=200w-CAPR®ime=Leading%20Trend&from=2025-01-01&fields=closeUsd,sharpe52w,returnUsd1M"
Query Parameters
| Name | Type | Required | Description |
|---|---|---|---|
window | string | Yes | Score window. One of 200w-CAPR, 200w-Local, 30d-CAPR, 30d-Local |
regime | string | Yes when direction !== 'any' | Target regime label — one of Leading Trend, Emerging Trend, Weakening Trend, Bear Trend, Neutral. The label is matched as given: any other value matches nothing and returns an empty data, not an error. May be omitted when direction=any |
direction | string | No | One of into, outOf, any (case-insensitive). Default into. any returns every transition regardless of regime |
from | string | No | Inclusive ISO YYYY-MM-DD lower bound on transitionDate. Omitting it applies a 90-day look-back rather than scanning all history — see Default date window |
to | string | No | Inclusive ISO YYYY-MM-DD upper bound on transitionDate |
type | string | No | Asset-type filter — stock, crypto, etf, index, commodity. fx is rejected |
status | string | No | Asset status — active, pending, inactive |
sector | string | No | Sector filter (case-insensitive) |
q | string | No | Free-text symbol/name search |
universe | string | No | Universe slug (e.g. bytetrend, bytefolio) — see Universes. Membership filter: the population becomes that universe’s members. Unknown slugs and macro return 400 — see Group filters |
dimension | string | No | One of the five global dimensions: region, sector, industry, type, or country. Paired with group; independent of universe |
group | string | No | Group label within dimension, exact match. Paired with dimension |
fields | string | No | Comma-separated metric keys included in metricsAtTransition. Default: closeUsd, byteTrendCapr200w, byteTrendCapr30d, returnUsd1M, marketCapUsd, sharpe52w |
format | string | No | Response format: json (default), csv, or toon |
Group filters
universe restricts the scanned population to that universe’s members — the assets whose universes[] includes the slug. Without it, the scan covers the whole registry.
dimension + group narrow the scan by the asset’s resolved value in one of the five global dimensions. The pair is independent of universe and both-or-neither: one without the other is a 400, as is an unknown dimension. type, status, sector and q compose with all of these. Both filters genuinely narrow the scan, which matters for the row cap under Bounds.
?universe=macro is a 400 — the macro dataset is at /api/macro, not a universe. Filter by nothing to scan the whole registry.
Response
| Field | Type | Description |
|---|---|---|
generatedAt | string | ISO timestamp captured when the server ran the aggregation |
regime | string or null | Echo of the resolved target regime. null when direction=any |
window | string | Echo of the resolved window |
direction | string | Echo of the resolved direction |
appliedRange | object | The date window actually queried — see Default date window |
appliedRange.from | string | ISO YYYY-MM-DD lower bound applied, whether you supplied it or it was defaulted |
appliedRange.to | string or null | ISO YYYY-MM-DD upper bound applied, or null when you supplied none. Here null is meaningful rather than missing: it means open-ended to the latest available data, not “defaulted to today” |
appliedRange.defaulted | boolean | true when from was defaulted, false when you supplied it |
count | number | Number of transition rows in data |
data | object[] | One row per transition event |
data[].symbol | string | Asset ticker symbol |
data[].transitionDate | string | ISO YYYY-MM-DD. For raw windows, this IS the confirmation date; see below |
data[].fromRegime | string | Regime label immediately before the transition |
data[].toRegime | string | Regime label after the transition |
data[].metricsAtTransition | object | Snapshot of fields evaluated at transitionDate |
data[].trendAgeAtTransition | number | Confirmed window only. Days the prior regime had been in force at the transition |
data[].confirmedTransitionDate | string | Confirmed window only. Same value as transitionDate — kept for explicitness |
data[].pendingStartDate | string | Confirmed window only. Date the pending transition first appeared. Confirmation lag is the trading-day delta to confirmedTransitionDate |
Two output shapes
window=200w-CAPR(confirmed window) — every row carriestrendAgeAtTransition,confirmedTransitionDate, andpendingStartDate. The 4-trading-day delta betweenpendingStartDateandconfirmedTransitionDateis the confirmation lag built into the long-window CAPR score.window=200w-Local,30d-CAPR,30d-Local(raw windows — no confirmation lag) — those three fields are omitted entirely from each row.transitionDateIS the confirmation date.
{
"generatedAt": "2026-05-07T19:42:00.613Z",
"regime": "Leading Trend",
"window": "200w-CAPR",
"direction": "into",
"appliedRange": { "from": "2024-01-01", "to": "2024-12-31", "defaulted": false },
"count": 160,
"data": [
{
"symbol": "NVDA",
"transitionDate": "2024-03-12",
"fromRegime": "Emerging Trend",
"toRegime": "Leading Trend",
"trendAgeAtTransition": 5,
"confirmedTransitionDate": "2024-03-12",
"pendingStartDate": "2024-03-07",
"metricsAtTransition": {
"closeUsd": 880.21,
"byteTrendCapr200w": 5,
"byteTrendCapr30d": 5,
"returnUsd1M": 0.084,
"marketCapUsd": 2200000000000,
"sharpe52w": 1.42
}
}
]
}
Default date window
A call without from does not scan all history. When from is omitted the server applies a 90-day look-back, anchored on to if you supplied one and on the current date otherwise. An explicit from is always honoured as given — widening the range is opt-in.
Every response reports the window it actually used:
// No dates supplied — 90-day look-back, open-ended at the recent end
"appliedRange": { "from": "2026-04-24", "to": null, "defaulted": true }
// from supplied — honoured as-is
"appliedRange": { "from": "2020-01-01", "to": null, "defaulted": false }
// to supplied without from — look-back anchored on `to`
"appliedRange": { "from": "2023-10-03", "to": "2024-01-01", "defaulted": true }
Two things to read carefully:
defaulted—truemeans you are looking at a 90-day slice, not the whole history. Check it before interpreting a small result set as a genuine absence of transitions.to: null— not an omission. The upper bound reports what you bounded;nullmeans the query ran open-ended to the latest available data. The 90-day look-back is anchored internally on the current date, but that anchor is not reported as atoyou didn’t ask for.
This default matches the equivalent ByteTree MCP tool, so both surfaces bound an unqualified query the same way.
Regime transitions accumulate over decades across the whole population, and an unbounded scan was slow enough to exceed upstream timeouts — returning an unhelpful error instead of data. The default keeps a date-less exploratory call fast and useful.
Bounds
- 5001-row short-circuit. The query is capped at
$limit: 5001; if 5001 rows return the server replies400with a hint to narrow the date range, the asset filter, ordirection. The cap protects both sides —direction=anyover the entire population without filters will reliably trip it. type=fxis rejected with400.- Widen deliberately. An explicit multi-year
fromcombined withdirection=anyand no asset filter is the shape most likely to hit either the row cap or a server-side time limit. Narrow withtype,universe+dimension+group, or a tighter range.
Regime labels
Regime labels are the values of confirmedRegime* / pendingRegime* produced by the scoring engine. See the Latest Metrics field reference for the full label set per window. The MCP bytetree://glossary resource holds authoritative wording sourced from engine doc-strings.
Notes
- Requires an API key.
- Backs the public ByteTree MCP’s
get_regime_transitionstool. - The
metricsAtTransitionblock is a point-in-time snapshot — values are read from the symbol’s metric record ontransitionDate, not recomputed.