Trend Metrics
Regime Transitions
GET /api/metrics/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.
Example
curl "https://api.bytetree.io/api/metrics/regime-transitions?window=200w-CAPR®ime=Leading+Trend&from=2024-01-01&to=2024-12-31&q=NVDA" \
-H "Authorization: Bearer YOUR_API_KEY" const res = await fetch("https://api.bytetree.io/api/metrics/regime-transitions?window=200w-CAPR®ime=Leading+Trend&from=2024-01-01&to=2024-12-31&q=NVDA", {
headers: { "Authorization": "Bearer YOUR_API_KEY" },
});
const body = await res.json(); import requests
res = requests.get(
"https://api.bytetree.io/api/metrics/regime-transitions?window=200w-CAPR®ime=Leading+Trend&from=2024-01-01&to=2024-12-31&q=NVDA",
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
body = res.json() 200 {
"generatedAt": "2026-10-09T09:17:59.555Z",
"regime": "Leading Trend",
"window": "200w-CAPR",
"direction": "into",
"appliedRange": { "from": "2024-01-01", "to": "2024-12-31", "defaulted": false },
"count": 1,
"data": [
{
"symbol": "NVDA",
"transitionDate": "2024-03-07",
"fromRegime": "Neutral",
"toRegime": "Leading Trend",
"metricsAtTransition": {
"closeUsd": 92.62,
"byteTrendCapr200w": 5,
"byteTrendCapr30d": 5,
"returnUsd1M": 0.3585,
"marketCapUsd": 2281535400000,
"sharpe52w": 6.5771
},
"trendAgeAtTransition": 5,
"confirmedTransitionDate": "2024-03-07",
"pendingStartDate": "2024-03-01"
}
]
} Any 30d-CAPR transition in September 2026 for active Technology stocks
curl "https://api.bytetree.io/api/metrics/regime-transitions?window=30d-CAPR&direction=any&from=2026-09-01&to=2026-09-30&type=stock&status=active§or=Technology" \
-H "Authorization: Bearer YOUR_API_KEY" Custom metric snapshot at transition
curl "https://api.bytetree.io/api/metrics/regime-transitions?window=200w-CAPR®ime=Leading+Trend&from=2026-09-01&to=2026-09-30&type=stock§or=Technology&fields=closeUsd%2Csharpe52w%2CreturnUsd1M" \
-H "Authorization: Bearer YOUR_API_KEY" No dates: the 90-day default window, narrowed to crypto
curl "https://api.bytetree.io/api/metrics/regime-transitions?window=200w-CAPR&direction=any&type=crypto" \
-H "Authorization: Bearer YOUR_API_KEY" 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, exactly as written. Any other value, including a different case (leading trend), is a 400 listing the five labels — even with direction=any. 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 label, exact match (e.g. Technology) |
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 |
Dates must be real calendar dates, fields names must be well formed, and window, direction, regime, type and status must be values the endpoint lists, or the request is a 400 — see Value validation. A well-formed field name the record doesn’t have comes back as null in metricsAtTransition.
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. The new regime’s age (trendAge200w) on the confirmation day. Always 5: a regime is confirmed once it has held for five days, and its age counts from its first day |
data[].confirmedTransitionDate |
string |
Confirmed window only. Same value as transitionDate — kept for explicitness |
data[].pendingStartDate |
string or null |
Confirmed window only. Date the pending transition first appeared, or null when the transition falls in the first few trading days of the queried range — the lookup does not reach back before from. Widen from by a week to fill it in. 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.
closeUsd is on today’s adjusted basis, so it reflects NVDA’s later share split.
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-07-11", "to": null, "defaulted": true }
// from supplied — honoured as-is
"appliedRange": { "from": "2026-09-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.
The default stops a date-less call from scanning all history, but 90 days of the whole registry is still a lot of work: a date-less call with no asset filter is usually refused under the query-time bound below. Add an asset filter such as type, sector or universe, as in the last request example.
Bounds
-
Query time. A query that can’t be computed in about 15 seconds is refused with
400rather than left to time out:{ "error": "regime-transitions query too broad to compute in time — narrow the date range (from/to) or add an asset filter (type/sector/universe)" }The work grows with date range × population. A whole-registry query over a full year — or over the 90-day default — hits this, and so can a multi-year range for a single asset type. Narrow with
type,sector,universeordimension+group, or a tighter range. This response carriesCache-Control: no-store, so a retry after narrowing is never served the error from a cache. -
5001-row short-circuit. The query is capped at 5001 rows; if 5001 rows return the server replies
400with a hint to narrow the date range, the asset filter, ordirection.direction=anyis the shape most likely to reach it. -
type=fxis rejected with400.
Regime labels
The five labels — Leading Trend, Emerging Trend, Weakening Trend, Bear Trend and Neutral — are the same for all four windows. See Trend regime for what each one means.
Notes
- Requires an API key.
- Successful responses carry
Cache-Control: private, max-age=60: a repeat of the same request within a minute may be answered from your client’s cache. - 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.