Trend Metrics
Metric Distribution
GET /api/metrics/distribution How one metric is spread across all assets, and how that spread changes over time — for example, how many assets score 5 against how many score 0, month by month.
For each step in the date range, every daily value of metric inside the step is summarised into one row of statistics (mean, median, p25, p75, p90) and, for scores and other bucketed metrics, a histogram (buckets). With frequency=daily a step is one day, so each row describes the assets on that day; with weekly or monthly a row pools every asset-day in the step — see Asset-days, not assets.
Designed for “how is this metric distributed across the population, and how is that distribution drifting?” — not for per-symbol time series (use /api/metrics/:symbol for that).
Example
curl "https://api.bytetree.io/api/metrics/distribution?metric=byteTrendCapr200w&from=2026-07-01&to=2026-09-30&frequency=monthly" \
-H "Authorization: Bearer YOUR_API_KEY" const res = await fetch("https://api.bytetree.io/api/metrics/distribution?metric=byteTrendCapr200w&from=2026-07-01&to=2026-09-30&frequency=monthly", {
headers: { "Authorization": "Bearer YOUR_API_KEY" },
});
const body = await res.json(); import requests
res = requests.get(
"https://api.bytetree.io/api/metrics/distribution?metric=byteTrendCapr200w&from=2026-07-01&to=2026-09-30&frequency=monthly",
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
body = res.json() 200 First row shown, mean rounded {
"generatedAt": "2026-10-09T09:17:18.888Z",
"metric": "byteTrendCapr200w",
"frequency": "monthly",
"count": 3,
"data": [
{
"date": "2026-07-01",
"n": 115511,
"stats": { "mean": 1.9122, "median": 2, "p25": 0, "p75": 3, "p90": 5 },
"buckets": { "0": 39786, "1": 15135, "2": 17597, "3": 17061, "4": 10292, "5": 15640 }
},
"..."
]
} trendAge200w across active European stocks, weekly
curl "https://api.bytetree.io/api/metrics/distribution?metric=trendAge200w&from=2026-07-01&to=2026-09-30&type=stock&status=active&dimension=region&group=Europe" \
-H "Authorization: Bearer YOUR_API_KEY" Continuous metric (Sharpe) for a single sector, weekly
curl "https://api.bytetree.io/api/metrics/distribution?metric=sharpe52w&from=2026-06-01&to=2026-09-30§or=Technology" \
-H "Authorization: Bearer YOUR_API_KEY" Query Parameters
| Name | Type | Required | Description |
|---|---|---|---|
metric |
string |
Yes | Metric key. Allow-listed (40 entries — byteTrend{Local,Capr}{200w,30d}, trendAge200w, plus 35 continuous metrics). Send any unrecognised value to receive a 400 with the full allow-list echoed |
from |
string |
Yes | Inclusive ISO YYYY-MM-DD start date |
to |
string |
No | Inclusive ISO YYYY-MM-DD end date. Defaults to today. Keep from–to short: a long range over a large population can be refused — see Bounds |
frequency |
string |
No | Step granularity: daily, weekly, monthly. Default weekly |
type |
string |
No | Asset-type filter — stock, crypto, etf, index, commodity. fx is rejected (no synthesised distribution surface) |
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 across the asset population |
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 |
Dates must be real calendar dates, and metric, frequency, type and status must be values the endpoint lists, or the request is a 400 — see Value validation.
Group filters
universe restricts the population to that universe’s members — the assets whose universes[] includes the slug. Without it, the population is the whole registry.
dimension + group narrow the population by the asset’s resolved value in one of the five global dimensions. The pair is independent of universe — it works on the whole registry or within a 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.
# ByteTrend members only
curl "https://api.bytetree.io/api/metrics/distribution?metric=byteTrendLocal200w&from=2026-07-01&to=2026-09-30&universe=bytetrend" \
-H "Authorization: Bearer YOUR_API_KEY"
# Technology sector across the whole registry
curl "https://api.bytetree.io/api/metrics/distribution?metric=byteTrendLocal200w&from=2026-07-01&to=2026-09-30&dimension=sector&group=Technology" \
-H "Authorization: Bearer YOUR_API_KEY"
?universe=macro is a 400 — the macro dataset is a computed aggregation at /api/macro, not a universe. Filter by nothing to cover the whole registry.
Response
| Field | Type | Description |
|---|---|---|
generatedAt |
string |
ISO timestamp captured when the server ran the aggregation |
metric |
string |
Echo of the resolved metric key |
frequency |
string |
Echo of the requested frequency |
count |
number |
Number of timestep rows in data |
data |
object[] |
One row per timestep |
data[].date |
string |
ISO YYYY-MM-DD of the first day of this step (the day itself for daily; the Monday for weekly; the 1st for monthly) |
data[].n |
number |
Number of observations in this row — one per asset per day with a value. Equals the number of assets only for frequency=daily |
data[].stats |
object |
Always present — mean, median, p25, p75, p90. Percentiles are approximate |
data[].buckets |
object or absent |
Histogram, present only for bucketed metrics — see below |
Bucket-vs-percentile branching
The shape of buckets depends on the metric:
- Discrete-score metrics (the four ByteTrend variants —
byteTrendLocal200w,byteTrendCapr200w,byteTrendLocal30d,byteTrendCapr30d) —bucket-discrete. Keys are the integer scores"0","1","2","3","4","5"; values are the number of observations (asset-days) at that score. All six keys are emitted even when the count is zero. trendAge200w—bucket-range. Keys are the lower bound of each bin:"0"(0–4 days),"5"(5–29),"30"(30–89),"90"(90–364),"365"(365–1824),"1825"(1825+). Semantic age bins.- Continuous metrics (prices, CAPR, returns, volatility, Sharpe, beta, drawdowns, market cap, relative strength, score changes, etc.) —
bucketsis absent. Usestatsfor the shape.
Asset-days, not assets
Each row is built from every daily value that falls inside its step, so with weekly or monthly steps the same asset contributes once per day it has a value:
ncounts asset-days. About 5,100 assets over a month of trading days gives annabove 100,000 — not 5,100.bucketscount asset-days at each score or bin, so they sum ton.stats(mean,median, percentiles) are taken over the same pooled asset-days — a time-average of the cross-section across the step, not a snapshot of any single day.
For a per-asset snapshot, use frequency=daily — each row is one day, so n is the number of assets with a value that day and buckets count assets. On a weekly or monthly row, dividing a bucket count by n gives an asset-day share, which is not a snapshot: one asset at score 0 on Monday and 5 on Tuesday puts half its weight in each bucket, although Tuesday’s snapshot is all at 5. The page’s example is monthly: its n of 115,511 is asset-days across July 2026.
Weekends count too. With frequency=daily, a Saturday or Sunday row holds only the assets with a value that day — mostly crypto — so its n is a few hundred rather than thousands.
Bounds
-
Projected-rows cap. If the requested
(from, to, frequency)expansion would exceed 5000 timestep rows the server returns400with a hint to narrow the range or coarsen the frequency. This cap limits the number of rows, not the work behind them: a coarsemonthlyquery over a long range can still be refused under the query-time bound below. -
Query time. A query that can’t be computed in about 15 seconds is refused with
400rather than left to time out:{ "error": "distribution query too broad to compute in time — narrow the date range (from/to), coarsen frequency, or add an asset filter (type/sector/universe)" }The work grows with date range × population, so a whole-registry query over a long range hits this —
from=2025-01-01with no asset filter does. Narrow withtype,sector,universeordimension+group, and keep the range to a few months. This response carriesCache-Control: no-store, so a retry after narrowing is never served the error from a cache. -
type=fxis rejected with400. FX has its own dedicated surface; cross-asset-class distributions don’t make conceptual sense here.
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. - Only days on which an asset has a value for the metric count.
ntherefore reflects coverage as well as step length, and rises as new symbols accumulate enough history (e.g. forbyteTrend*200w, as symbols pass their 200-week eligibility threshold). - Backs the public ByteTree MCP’s
get_metric_distributiontool.