39 endpoints · General · Tool · Alpha · Raw data
https://api.blave.orgapi-key + secret-key headers on every requestShared by every crypto get_alpha / get_exposure endpoint:
period — bar size, {n}min / {n}h / {n}d ({n}m is read as minutes). Documented values are 5min, 15min, 1h, 4h, 8h, 1d; indicators with a coarser minimum say so in their block. A missing or unparseable period is a 403 {"error": "period is required"} (a 400 on unusual_movement and liquidation).start_date / end_date — YYYY-MM-DD (UTC). end_date defaults to today; start_date defaults to end_date − 365 days. A range longer than 365 days is silently clamped (start_date moved to end_date − 365 days). A malformed date is not validated and ends in a 500 — always send YYYY-MM-DD.symbol — Binance USDT-M perpetual, e.g. BTCUSDT; BTC, btc, BTC/USDT, BTC-USDT are also accepted (a bare token gets USDT appended). The get_symbols endpoints list the covered symbols.{"data": {"timestamp": [...], "alpha": [...], ...}} — parallel arrays, one element per bar. timestamp is Unix seconds (UTC), the bar label.stat object — returned by indicators whose block lists it. A logistic model fitted on the symbol's past year of this indicator versus the next-24h price move:
| Field | Type | Description |
|---|---|---|
up_prob | float | Probability of a 24h up move given the latest indicator value (0–1) |
avg_up_return | float | Mean 24h return over past up moves (decimal, 0.02 = +2%) |
avg_down_return | float | Mean 24h return over past down moves (decimal, negative) |
return_ratio | float | -avg_up_return / avg_down_return |
exp_value | float | up_prob × avg_up_return + (1 − up_prob) × avg_down_return |
is_data_sufficient | bool | false when the symbol has less than one year of history — do not rely on the other fields then |
When there is no data the object falls back to up_prob 0.5 and zeros.
/price response = requests.get(f"{BASE_URL}/price", headers=headers, params={"symbol": "BTCUSDT"}, timeout=30)print(response.json())# {"symbol": "BTC", "price": 75838.2, "change_24h": -0.01739}A flat object.
| Field | Type | Unit | Description |
|---|---|---|---|
symbol | string | — | The token without USDT (e.g. BTC, even when BTCUSDT was sent) |
price | float | USDT | Latest price |
change_24h | float | decimal | 24h change as a fraction (0.025 = +2.5%) |
| Status | Body | When |
|---|---|---|
| 400 | {"error": "symbol is required"} | symbol missing |
| 404 | {"error": "symbol <SYMBOL> not found"} | No price for that token |
/alpha_table None.
response = requests.get(f"{BASE_URL}/alpha_table", headers=headers, timeout=60)body = response.json()row = body["data"]["0G"] # one token out of the 716 keys this response carried# {"holder_concentration": {"-": 0.9267}, "holder_concentration_chg": {"15min": -0.0118, "1h": 0.0075, "24h": 0.4723, "3d": -0.1852, "30d": "", ...},# "funding_rate": {"binance": 0.005, "bybit": 0.005, "okx": 0.005, "pionex": "", ...},# "liquidation": {"15min": 0.0, "1h": -0.2665, "24h": -0.5637, "1min": "", ...},# "market_cap": {"-": 42204386.29}, "market_cap_percentile": {"-": 56.55},# "price": {"-": 0.1832}, "price_change": {"15min": -0.00215, "24h": -0.05792, ...},# "statistics": {"up_prob": 0.4277, "exp_value": -0.00478, "is_data_sufficient": false, ...}, ...}# (shape captured from a live response; `""` marks insufficient data){"data": {<TOKEN>: {...}}, "fields": [...], "note": {...}}.
data is keyed by token (BTC, 1INCH, …). Each token maps indicator name → {param: value} ("-" when the indicator has no parameter). "" = insufficient data. Besides the indicators:
| Key | Description |
|---|---|
statistics | up_prob (prob. of a 24h up move), exp_value (expected return), avg_up_return, avg_down_return, return_ratio, is_data_sufficient |
price | {"-": 70000} — current price |
price_change | {"15min": ..., "1h": ..., "24h": ...} — % change |
market_cap | {"-": 1234567890} — USD market cap |
market_cap_percentile | {"-": 85.3} — percentile among all listed coins |
funding_rate | {"binance": -0.01, ...} — per exchange |
oi_imbalance | {"-": 0.12} — OI imbalance (full detail: /oi_imbalance/get_overview_data) |
fields — one entry per indicator: id, name (key used in data), param (parameter name or null), name_en, name_zh.
note — keyed by indicator id: a list of value bands {min, max, note: {en, zh}, direction: {en, zh}, color, background_color} used to label a value (e.g. max: -3 → "Overly Bearish").
Shared errors only.
statistics.is_data_sufficient before using statistics./kline Coverage. Every Binance USDⓈ-M perpetual whose symbol ends in USDT — 740 contracts as of October 2026, including tokenized stocks, commodities and other TradFi USDT perpetuals. All 740 have their full 1-minute history stored server-side, from 2020-01-01 or the listing date. A newly listed perpetual becomes queryable about 5–10 minutes after listing.
Not covered: contracts quoted in USDC, USD1, U or BTC (e.g. BTCUSDC, ETHBTC) and quarterly delivery contracts — these return the 400 unknown symbol or no data error below. Delisted contracts are not guaranteed: one may answer with whatever history is still stored or with that same 400 (those delisted before October 2026 have no 1min–4min history).
USDT perpetual. A bare token gets USDT appended; a bare token that only exists with a multiplier prefix resolves to it (PEPE → 1000PEPEUSDT)Per-request window: period ≥ 5min → at most 365 days; a longer range is silently clamped (start_date moved to end_date − 365 days, no error). Period < 5min → at most 30 days; a longer range is a 400.
params = {"symbol": "BTCUSDT", "period": "1h", "start_date": "2026-10-01", "end_date": "2026-10-02"}response = requests.get(f"{BASE_URL}/kline", headers=headers, params=params, timeout=60)data = response.json()# [{"time": 1790812800.0, "open": 83576.8, "high": 83612.6, "low": 83370.0, "close": 83460.0, "volume": 3123.991}, ...]A bare JSON array (not wrapped in {"data": ...}), ascending by time.
| Field | Type | Unit | Description |
|---|---|---|---|
time | float | Unix seconds (UTC) | Bar open time |
open / high / low / close | float | quote currency (USDT) | Prices |
volume | float | null | base asset | Traded volume; null when the source has no volume for that bar |
| Status | Body | When |
|---|---|---|
| 403 | {"error": "symbol is required"} | symbol missing |
| 403 | {"error": "period is required"} | period missing or not parseable |
| 400 | {"error": "minimum supported period is 1min"} | period below one minute |
| 400 | {"error": "periods below 5min must be a whole number of minutes"} | e.g. 90s |
| 400 | {"error": "date range exceeds max 30 days for periods below 5min"} | Period < 5min and range > 30 days |
| 400 | {"error": "invalid date format, expected YYYY-MM-DD"} | Malformed start_date / end_date |
| 400 | {"error": "unknown symbol or no data: <symbol>"} | Symbol not covered (see Not covered) or not a real contract, e.g. BTCUSDC, ETHBTC, a typo. <symbol> echoes the value you sent. Not transient — do not retry |
200 with [], not an error.1min every bar returned is closed. A longer period can end in a partial bar when end_date is today — it is built from the bars closed so far (at 07:09 UTC the 07:00 1h bar holds 07:00–07:05); drop it if you need closed bars only.5min = 3 requests; 1 year of 1min = 13 requests of ≤30 days)./market_direction/get_alpha No symbol: alpha is a single market-wide series, not a per-coin one. BTCUSDT is used internally only to align the bars; it is not returned and does not change alpha. See Crypto indicator conventions.
params = {"period": "1h", "start_date": "2026-09-13", "end_date": "2026-09-15"}response = requests.get(f"{BASE_URL}/market_direction/get_alpha", headers=headers, params=params, timeout=60)# {"data": {"alpha": [-0.5195979478976323, -0.5223392571665055, -0.5612490182062327, ...],# "timestamp": [1789257600.0, 1789261200.0, 1789264800.0, ...]}} # 72 bars{"data": {"timestamp": [...], "alpha": [...]}}. No stat.
| Field | Type | Description |
|---|---|---|
timestamp | float[] | Unix seconds (UTC) |
alpha | float[] | Market direction value |
| Status | Body | When |
|---|---|---|
| 403 | {"error": "period is required"} | period missing or unparseable |
/screener/get_saved_conditions None.
response = requests.get(f"{BASE_URL}/screener/get_saved_conditions", headers=headers, timeout=30)conditions = response.json()["data"]{"data": {<condition_id>: {...}}}, keyed by condition id (a JSON string key, e.g. "12"; send it back as the integer condition_id). Only this account's own conditions.
| Field | Type | Description |
|---|---|---|
filters | object[] | The condition's filters, all ANDed: indicator_id (int), indicator_name ({"en", "zh"}), param (string; "-" = the indicator's default), operator_id (int), operator_symbol (string, e.g. >), value (threshold) |
note | string | The name the account saved the condition under (a condition you save is named here) |
name_en / name_zh | string | null | Set only on official / community conditions; on your own conditions expect empty or null and read note instead |
description_en / description_zh | string | null | Set only on official / community conditions; may be empty or null |
| Status | Body | When |
|---|---|---|
| 403 | {"error": "unsupported api feature"} | Key not tied to a user account |
/screener/get_saved_condition_result response = requests.get(f"{BASE_URL}/screener/get_saved_condition_result", headers=headers, params={"condition_id": 12}, timeout=60){"data": {"alpha_names": [...], "symbols": [...]}}.
| Field | Type | Description |
|---|---|---|
alpha_names | object[] | One per distinct filter indicator, in filter order: en / zh (display name, with the parameter in parentheses when there is one), name (indicator key), type, url; plus value_format, value_decimals, polarity when the indicator defines them |
symbols | object[] | Tokens matching every filter |
symbols[].symbol | string | Token without USDT (e.g. BTC) |
symbols[].id | int | Token id (0 when unknown) |
symbols[].user_selected | bool | Token is on the account's watchlist |
symbols[].price | float | Latest price in USDT (same feed as /price; 0 when unavailable) |
symbols[].24h_chg | float | 24h change as a fraction (0.025 = +2.5%) |
symbols[].alphas | float[] | The token's value for each filter indicator, parallel to alpha_names |
symbols[].alpha_notes | object[] | Per indicator: indicator_id, color, direction, note (plus background_color when a rule matched; color null and empty strings when none did) |
| Status | Body | When |
|---|---|---|
| 400 | {"error": "Missing parameter: condition_id is required."} | Missing |
| 400 | {"error": "Invalid parameter: condition_id must be an integer."} | Not an integer |
| 404 | {"error": "Invalid condition_id: <id> not found for user."} | Not one of this account's conditions |
| 403 | {"error": "unsupported api feature"} | Key not tied to a user account |
/holder_concentration/get_symbols None.
symbols = requests.get(f"{BASE_URL}/holder_concentration/get_symbols", headers=headers, timeout=30).json()["data"]{"data": ["BNBUSDT", "BTCUSDT", ...]}, sorted.
Shared errors only.
*/get_symbols crypto endpoint currently returns the same Binance USDT-M symbol list./holder_concentration/get_alpha See Crypto indicator conventions.
params = {"symbol": "BTCUSDT", "period": "1h", "start_date": "2026-09-13", "end_date": "2026-09-15"}response = requests.get(f"{BASE_URL}/holder_concentration/get_alpha", headers=headers, params=params, timeout=60)# {"data": {"alpha": [-1.1931909718306861, -1.2035898186867282, -1.2037004015202886, ...],# "timestamp": [1789257600.0, 1789261200.0, 1789264800.0, ...],# "stat": {"up_prob": 0.509739818557561, "exp_value": -0.00051954905018229,# "avg_up_return": 0.015512131150026753, "avg_down_return": -0.017188220228787618,# "return_ratio": 0.9024861762037658, "is_data_sufficient": true}}} # 72 bars{"data": {"timestamp": [...], "alpha": [...], "stat": {...}}}.
| Field | Type | Description |
|---|---|---|
timestamp | float[] | Unix seconds (UTC) |
alpha | float[] | Z-score of the log long/short account ratio vs its 30-day mean, sign-flipped — higher = more concentrated |
stat | object | See stat object |
| Status | Body | When |
|---|---|---|
| 403 | {"error": "symbol is required"} / {"error": "period is required"} | Missing parameter |
/funding_rate/get_alpha See Crypto indicator conventions.
400params = {"symbol": "BTCUSDT", "period": "1h", "start_date": "2026-09-13", "end_date": "2026-09-15"}response = requests.get(f"{BASE_URL}/funding_rate/get_alpha", headers=headers, params=params, timeout=60)# {"data": {"timestamp": [1789257600.0, 1789261200.0, 1789264800.0, ...],# "alpha": [0.005064, 0.006165, 0.007765, ...],# "close": [77239.5, 77285.5, 77263.9, ...],# "stat": {"up_prob": 0.5009438427095587, "exp_value": -0.0008769555139270298,# "is_data_sufficient": false, ...}}} # 72 bars{"data": {"timestamp": [...], "alpha": [...], "close": [...], "stat": {...}}}.
| Field | Type | Unit | Description |
|---|---|---|---|
timestamp | float[] | Unix seconds (UTC) | Bar label |
alpha | float[] | percent | Funding rate × 100 (0.01 = 0.01%); positive = longs pay shorts |
close | float[] | USDT | Perpetual close price |
stat | object | — | See stat object |
| Status | Body | When |
|---|---|---|
| 403 | {"error": "symbol is required"} / {"error": "period is required"} | Missing parameter |
| 400 | {"error": "exchange must be one of binance, okx, bingx, bybit"} | exchange outside the list |
/market_sentiment/get_symbols None.
symbols = requests.get(f"{BASE_URL}/market_sentiment/get_symbols", headers=headers, timeout=30).json()["data"]{"data": ["BNBUSDT", "BTCUSDT", ...]}, sorted.
Shared errors only.
/market_sentiment/get_alpha See Crypto indicator conventions.
params = {"symbol": "BTCUSDT", "period": "1h", "start_date": "2025-01-01", "end_date": "2025-03-01"}response = requests.get(f"{BASE_URL}/market_sentiment/get_alpha", headers=headers, params=params, timeout=60){"data": {"timestamp": [...], "alpha": [...], "stat": {...}}}.
| Field | Type | Description |
|---|---|---|
timestamp | float[] | Unix seconds (UTC) |
alpha | float[] | Market sentiment value |
stat | object | See stat object |
| Status | Body | When |
|---|---|---|
| 403 | {"error": "symbol is required"} / {"error": "period is required"} | Missing parameter |
/capital_shortage/get_alpha No symbol; market-wide. See Crypto indicator conventions.
5min and 15min both return dataparams = {"period": "1h", "start_date": "2025-01-01", "end_date": "2025-03-01"}response = requests.get(f"{BASE_URL}/capital_shortage/get_alpha", headers=headers, params=params, timeout=60){"data": {"timestamp": [...], "alpha": [...], "stat": {...}}}.
| Field | Type | Description |
|---|---|---|
timestamp | float[] | Unix seconds (UTC) |
alpha | float[] | Capital shortage value |
stat | object | See stat object (computed against BTC) |
| Status | Body | When |
|---|---|---|
| 403 | {"error": "period is required"} | Missing parameter |
/sector_rotation/get_history_data None.
response = requests.get(f"{BASE_URL}/sector_rotation/get_history_data", headers=headers, timeout=60)# {"data": {"alpha": {"AI": {"data": [0.0, 0.04377017039444864, 0.04922749428543449, ...],# "name_en": "AI", "name_zh": "人工智能"},# "BNB Eco": {"data": [0.0, 0.008847752133756215, ...],# "name_en": "BNB Eco", "name_zh": "BNB 生態"}, ...},# "timestamp": [1757980800.0, 1758067200.0, 1758153600.0, ...]}} # 51 sectors, 366 points{"data": {"alpha": {<sector>: {"data": [...], "name_en": ..., "name_zh": ...}}, "timestamp": [...]}}. timestamp sits next to alpha at the top of data, not inside each sector; it is the shared time axis for every sector series.
| Field | Type | Description |
|---|---|---|
timestamp | float[] | Unix seconds (UTC), one per point — 366 daily points in the observed response |
alpha.<sector>.data | float[] | The sector series, same length and order as timestamp (366); the first element is 0.0 |
alpha.<sector>.name_en / name_zh | string | Sector display name |
Shared errors only.
/sector_rotation/get_overview_data None.
data = requests.get(f"{BASE_URL}/sector_rotation/get_overview_data", headers=headers, timeout=60).json()["data"]# {"AI": {"name_en": "AI", "name_zh": "人工智能",# "data": {"1h": {"pct_change": 0.0076}, "8h": ..., "90d": ...},# "symbols": {"0G": {"id": 38337, "data": {"1h": {"pct_change": 0.0061}, ...}}, ...}}, ...}{"data": {<sector>: {"name_en", "name_zh", "data", "symbols"}}} (~48 sectors).
| Field | Description |
|---|---|
data | {<timeframe>: {"pct_change": float}} for 1h, 8h, 24h, 3d, 7d, 30d, 90d; pct_change is a decimal (0.0061 = +0.61%) |
symbols | {<token>: {"id": int, "data": {<timeframe>: {"pct_change": float}}}} — per-token breakdown |
Shared errors only.
/oi_imbalance/get_overview_data None.
data = requests.get(f"{BASE_URL}/oi_imbalance/get_overview_data", headers=headers, timeout=60).json()["data"]# [{"token": "TSLA", "token_id": 39618, "token_price": 313.33, "token_chg": 0.031,# "market_cap": 40415.98, "oi_total": 59916616.78, "alpha": 1482.5}, ...]{"data": [...]}, sorted by alpha descending.
| Field | Type | Unit | Description |
|---|---|---|---|
token | string | — | Token |
token_id | int | — | Blave token id |
token_price | float | USD | Price |
token_chg | float | decimal | Price change |
market_cap | float | USD | Market cap |
oi_total | float | USD | Futures OI summed across Binance / OKX / BingX |
alpha | float | ratio | oi_total / market_cap — high = OI crowded relative to size (squeeze / volatility risk) |
Shared errors only.
/alpha_table's oi_imbalance carries only the final alpha; this endpoint has the full table./whale_hunter/get_symbols None.
symbols = requests.get(f"{BASE_URL}/whale_hunter/get_symbols", headers=headers, timeout=30).json()["data"]{"data": ["BNBUSDT", "BTCUSDT", ...]}, sorted.
Shared errors only.
/whale_hunter/get_alpha See Crypto indicator conventions.
params = {"symbol": "BTCUSDT", "period": "1h", "timeframe": "24h", "score_type": "score_oi"}response = requests.get(f"{BASE_URL}/whale_hunter/get_alpha", headers=headers, params=params, timeout=60){"data": {"timestamp": [...], "alpha": [...], "stat": {...}}}.
| Field | Type | Description |
|---|---|---|
timestamp | float[] | Unix seconds (UTC) |
alpha | float[] | Z-score of the timeframe-summed OI change (or volume) vs its 30-day mean |
stat | object | See stat object |
| Status | Body | When |
|---|---|---|
| 403 | {"error": "symbol is required"} / {"error": "period is required"} | Missing parameter |
| 403 | {"error": "Invalid score_type"} | score_type not allowed |
timeframe is not validated server-side. One value outside the list was tried, 2h, and it returned 200 with data. That is a single observation — it does not establish that any {n}h works. Stay on the listed values unless you verify the one you need./taker_intensity/get_symbols None.
symbols = requests.get(f"{BASE_URL}/taker_intensity/get_symbols", headers=headers, timeout=30).json()["data"]{"data": ["BNBUSDT", "BTCUSDT", ...]}, sorted.
Shared errors only.
/taker_intensity/get_alpha See Crypto indicator conventions.
params = {"symbol": "BTCUSDT", "period": "1h", "timeframe": "24h", "start_date": "2025-01-01", "end_date": "2025-03-01"}response = requests.get(f"{BASE_URL}/taker_intensity/get_alpha", headers=headers, params=params, timeout=60){"data": {"timestamp": [...], "alpha": [...], "stat": {...}}}.
| Field | Type | Description |
|---|---|---|
timestamp | float[] | Unix seconds (UTC) |
alpha | float[] | Z-score of timeframe-summed (taker buy − taker sell) volume vs its 30-day mean; positive = net buying |
stat | object | See stat object |
| Status | Body | When |
|---|---|---|
| 403 | {"error": "symbol is required"} / {"error": "period is required"} | Missing parameter |
/unusual_movement/get_symbols None.
symbols = requests.get(f"{BASE_URL}/unusual_movement/get_symbols", headers=headers, timeout=30).json()["data"]{"data": ["BNBUSDT", "BTCUSDT", ...]}, sorted.
Shared errors only.
/unusual_movement/get_alpha See Crypto indicator conventions.
params = {"symbol": "BTCUSDT", "period": "1h", "timeframe": "24h"}response = requests.get(f"{BASE_URL}/unusual_movement/get_alpha", headers=headers, params=params, timeout=60){"data": {"timestamp": [...], "alpha": [...], "close": [...], "stat": {...}}}.
| Field | Type | Description |
|---|---|---|
timestamp | float[] | Unix seconds (UTC) |
alpha | float[] | Return over timeframe divided by 365-day volatility scaled to that window — large |alpha| = outlier |
close | float[] | Close price (USDT) |
stat | object | See stat object |
| Status | Body | When |
|---|---|---|
| 400 | {"error": "symbol is required"} / {"error": "period is required"} | Missing parameter |
| 500 | server error | timeframe outside the allowed list |
/squeeze_momentum/get_symbols None.
symbols = requests.get(f"{BASE_URL}/squeeze_momentum/get_symbols", headers=headers, timeout=30).json()["data"]{"data": ["BNBUSDT", "BTCUSDT", ...]}, sorted.
Shared errors only.
/squeeze_momentum/get_alpha No period; fixed to 1d. See Crypto indicator conventions.
params = {"symbol": "BTCUSDT", "start_date": "2025-01-01", "end_date": "2025-03-01"}response = requests.get(f"{BASE_URL}/squeeze_momentum/get_alpha", headers=headers, params=params, timeout=60)# {"data": {"alpha": [-0.2256, ...], "scolor": ["black", ...], "timestamp": [...], "stat": {...}}}{"data": {"timestamp": [...], "alpha": [...], "scolor": [...], "stat": {...}}}.
| Field | Type | Description |
|---|---|---|
timestamp | float[] | Unix seconds (UTC), daily |
alpha | float[] | Momentum value |
scolor | string[] | black = squeeze on (Bollinger Bands inside Keltner Channels), grey = squeeze off |
stat | object | See stat object |
| Status | Body | When |
|---|---|---|
| 403 | {"error": "symbol is required"} | Missing parameter |
alpha is 0.0 until 2020-02-09. A request starting earlier than the Data from date returns those padded rows — they are filler, not signal. Drop leading zeros, or start at the Data from date./blave_top_trader/get_exposure No symbol: alpha is a single market-wide series, not a per-coin one. BTCUSDT is used internally only to align the bars; it is not returned and does not change alpha. See Crypto indicator conventions.
params = {"period": "1h", "start_date": "2025-05-01", "end_date": "2025-07-01"}response = requests.get(f"{BASE_URL}/blave_top_trader/get_exposure", headers=headers, params=params, timeout=60)# {"data": {"alpha": [34.32, 40.52, ...], "timestamp": [1747130400.0, ...]}}{"data": {"timestamp": [...], "alpha": [...]}}. No stat.
| Field | Type | Description |
|---|---|---|
timestamp | float[] | Unix seconds (UTC) |
alpha | float[] | Net exposure of Blave's top traders (top 10% by account assets) — the median, across those traders, of each trader's net notional position ÷ own assets, ×100 (positive = net long). A raw ratio, not a z-score |
| Status | Body | When |
|---|---|---|
| 403 | {"error": "period is required"} | Missing parameter |
/liquidation/get_symbols None.
symbols = requests.get(f"{BASE_URL}/liquidation/get_symbols", headers=headers, timeout=30).json()["data"]{"data": ["BNBUSDT", "BTCUSDT", ...]}, sorted.
Shared errors only.
/liquidation/get_alpha See Crypto indicator conventions.
params = {"symbol": "BTCUSDT", "period": "1h", "timeframe": "24h"}response = requests.get(f"{BASE_URL}/liquidation/get_alpha", headers=headers, params=params, timeout=60){"data": {"timestamp": [...], "alpha": [...], "stat": {...}}}.
| Field | Type | Description |
|---|---|---|
timestamp | float[] | Unix seconds (UTC) |
alpha | float[] | (short − long liquidations, in coins) summed over timeframe ÷ its 30-day rolling std; mean not subtracted. > 0 = more shorts than longs liquidated, < 0 = more longs |
stat | object | See stat object |
| Status | Body | When |
|---|---|---|
| 400 | {"error": "symbol is required"} / {"error": "period is required"} | Missing parameter |
alpha is 0.0 until 2023-01-01. A request starting earlier than the Data from date returns those padded rows — they are filler, not signal. Drop leading zeros, or start at the Data from date. Symbols other than BTC/ETH turn non-zero later still, so check per symbol./liquidation/get_map response = requests.get(f"{BASE_URL}/liquidation/get_map", headers=headers, params={"symbol": "BTCUSDT"}, timeout=60)# {"data": {"price": 77554.1, "labels": [54287.9, ...], "oi_value": [57693.86, ...],# "cumsum": [1543109619.0, ...], "liquidation": {"24h": {"buy_liq": [...], "sell_liq": [...]}}}}{"data": {"price", "labels", "oi_value", "cumsum", "liquidation"}}.
| Field | Type | Unit | Description |
|---|---|---|---|
price | float | USDT | Current price |
labels | float[] | USDT | 200 price buckets |
oi_value | float[] | USD | Estimated allocation of Binance open interest to each bucket (model estimate, not real positions) |
cumsum | float[] | USD | Cumulative liquidation exposure across buckets |
liquidation | object | USD | {"24h": {"buy_liq": [...], "sell_liq": [...]}} — actual Binance force-order liquidations over the last 24 h per bucket, each divided by a fixed 0.3 Binance-share assumption: buy_liq = short liquidations, sell_liq = long liquidations |
| Status | Body | When |
|---|---|---|
| 400 | {"error": "symbol is required"} | Missing parameter |
/liquidation/get_map_change response = requests.get(f"{BASE_URL}/liquidation/get_map_change", headers=headers, params={"symbol": "BTCUSDT"}, timeout=60)# {"data": {"price": 77554.1, "labels": [54287.9, ...], "hist_0_1h": [0.0, ...], "hist_1_8h": [...], "hist_8_24h": [...]}}{"data": {"price", "labels", "hist_0_1h", "hist_1_8h", "hist_8_24h"}}.
| Field | Type | Unit | Description |
|---|---|---|---|
price | float | USDT | Current price |
labels | float[] | USDT | 200 price buckets (lower edges) |
hist_0_1h | float[] | USD | New estimated liquidation exposure over the last 0–1 h, per bucket: positive difference between model map snapshots, not actual liquidations |
hist_1_8h | float[] | USD | Last 1–8 h |
hist_8_24h | float[] | USD | Last 8–24 h |
| Status | Body | When |
|---|---|---|
| 400 | {"error": "symbol is required"} | Missing parameter |
/liquidation/get_coin One coin's forced liquidations across every exchange feed Blave collects: four rolling windows with the per-exchange split, an hourly 24-point series, and each feed's coverage notes. This is real liquidation flow (like get_alpha's input), not the model estimate behind get_map.
symbol is the normalised coin nameresponse = requests.get(f"{BASE_URL}/liquidation/get_coin", headers=headers, params={"symbol": "BTC"}, timeout=30)data = response.json()["data"]day = data["windows"]["24"]print(data["symbol"], data["rank"], day["total_liq_usd"], day["long_pct"])peak = max(data["series"]["points"], key=lambda p: p["long_liq_usd"] + p["short_liq_usd"])# Live capture 2026-09-20 (abridged with ...; same payload the studio page serves):# {"data": {"symbol": "BTC", "rank": 1, "updated_at": "2026-09-20T17:15:00+00:00",# "windows": {"1": {"covered_hours": 1.0, "total_liq_usd": 3429619.97, "long_liq_usd": 129200.73, "short_liq_usd": 3300419.23,# "long_pct": 0.0377, "short_pct": 0.9623, "by_exchange": {...}},# "4": {...}, "12": {...},# "24": {"covered_hours": 24.0, "total_liq_usd": 58723607.89, "long_liq_usd": 38063430.51, "short_liq_usd": 20660177.37,# "long_pct": 0.6482, "short_pct": 0.3518,# "by_exchange": {"binance": {"long_liq_usd": 17075740.21, "short_liq_usd": 6697256.41, "total_liq_usd": 23772996.62}, ...}}},# "exchanges": [{"coverage": "sampled_1s", "exchange": "binance", "last_event_at": "2026-09-20T17:15:00+00:00", "listed": true, "price_basis": "trade_avg", "time_basis": "event"}, ... 6 rows],# "detail_complete": true,# "series": {"bucket_seconds": 3600, "points": [..., {"long_liq_usd": 60660.74, "short_liq_usd": 6129662.69, "ts": "2026-09-20T16:00:00+00:00"}, {"long_liq_usd": 95373.53, "short_liq_usd": 5473.13, "ts": "2026-09-20T17:00:00+00:00"}]}}}{"data": {"symbol", "rank", "updated_at", "windows", "exchanges", "detail_complete", "series"}}.
| Field | Type | Unit | Description |
|---|---|---|---|
symbol | string | — | Normalised coin name, e.g. BTC |
rank | int / null | — | Position among the top 50 coins by 24 h total across exchanges; null outside the top 50 or with no event |
updated_at | string / null | ISO 8601 UTC | Time of the latest 5-minute bucket used |
windows | object | — | Keys are the strings "1", "4", "12", "24" (hours). Each is a rolling window ending at the latest 5-minute bucket, with the fields below |
windows.<h>.total_liq_usd / long_liq_usd / short_liq_usd | float | USD | Summed across exchanges; long = long positions liquidated (price fell), short = shorts liquidated (price rose) |
windows.<h>.long_pct / short_pct | float / null | ratio 0–1 | Share of the window total; null when the window total is 0 |
windows.<h>.covered_hours | float | h | How many hours of the window actually have buckets (< h right after a collector restart) |
windows.<h>.by_exchange | object | USD | {exchange: {total_liq_usd, long_liq_usd, short_liq_usd}}. An exchange with no event in the window has no key — read exchanges[] to tell "feed alive, this coin quiet" from "feed absent" |
exchanges[] | object[] | — | One row per feed (six today, present even with no event), sorted by 24 h total desc, then roster order |
exchanges[].exchange | string | — | binance, bybit, gate, okx, htx, bitfinex |
exchanges[].listed | bool / null | — | Whether that exchange lists a USDT-margined perpetual for the coin; null when the contract list could not be fetched (Bitfinex always null) |
exchanges[].last_event_at | string / null | ISO 8601 UTC | Latest bucket seen from that feed (any coin); null if never seen |
exchanges[].price_basis | string | — | Price used for USD conversion: trade_avg, bankruptcy, unverified |
exchanges[].coverage | string | — | Feed completeness: full, full_unstated, sampled_1s, aggregated_1s, sampled_undisclosed |
exchanges[].time_basis | string | — | event — bucketed by the event's own timestamp |
detail_complete | bool | — | false when the coin may have been cut from a full per-bucket detail list (feeds keep the top 100 coins per 5-minute bucket): windows can then under-count. Top-50 coins are almost always true |
series.bucket_seconds | int | s | Always 3600 |
series.points | object[] | — | Always 24 entries, oldest → newest, on clock hours; the last is the current hour up to updated_at (the snapshot is rebuilt every 5 min, so it can trail the request by a few minutes). Each {ts, long_liq_usd, short_liq_usd}; hours with no event are 0, never missing |
windows["24"] is the same rolling frame as the exchange matrix, so the same coin shows the same 24 h number there. series is on clock hours, so Σ points ≠ windows["24"] by design: take totals from windows, timing from series.
| Status | Body | When |
|---|---|---|
| 400 | {"error": "symbol is required"} | symbol missing, blank, longer than 32 chars, or nothing left after the quote suffix is stripped (e.g. symbol=USDT) |
| 404 | {"error": "<SYMBOL> is not a collected symbol"} | No exchange lists the coin and no feed reported it in the last 24 h — an answer, not a transient |
| 503 | {"error": "liquidation data unavailable"} | Upstream buckets did not answer — retry later; never read as "0 liquidations" |
start_date / end_date, and nothing older than 24 h. For history use get_alpha (a normalised long/short imbalance, not USD amounts).get_alpha / get_map need the Binance perp form (BTCUSDT); here BTC and BTCUSDT are the same coin./liquidation/get_exchanges Whole-market forced liquidations, aggregated per exchange and as a coin × exchange matrix — the market-wide companion to /liquidation/get_coin. Same rolling 5-minute-aligned frame, so a coin's 24 h total is the same number on both.
400 (it is not clamped); a non-integer value silently falls back to the defaultothers. Same range / non-integer rules as hoursparams = {"hours": 24, "top_n": 10}data = requests.get(f"{BASE_URL}/liquidation/get_exchanges", headers=headers, params=params, timeout=30).json()["data"]print(data["total"]["total_liq_usd"], data["total"]["short_pct"])print([(e["exchange"], e["total_liq_usd"], e["coverage"]) for e in data["exchanges"]])# Live capture 2026-09-22 (abridged with ...; anonymous studio twin /studio/charts/liquidation/exchanges,# same inner shape — the API-key response wraps it in "data" and allows top_n up to 50):# {"exchanges": [{"exchange": "binance", "total_liq_usd": 390250999.16, "long_liq_usd": 69367041.38,# "short_liq_usd": 320883957.78, "long_pct": 0.1777, "short_pct": 0.8223, "events": 46200,# "last_event_at": "2026-09-22T05:50:00+00:00", "price_basis": "trade_avg",# "coverage": "sampled_1s", "time_basis": "event"}, ... 6 rows],# "coins": [{"token": "BTC", "token_id": 1, "total_liq_usd": 397165128.6, "long_liq_usd": 68908479.16,# "short_liq_usd": 328256649.44,# "by_exchange": {"binance": {"long_liq_usd": 17994806.07, "short_liq_usd": 173732353.71,# "total_liq_usd": 191727159.78}, ... 6 exchanges}}, ... 10 coins],# "others": {"coin_count": 835, "total_liq_usd": 82658628.27, "long_liq_usd": 34622797.57,# "short_liq_usd": 48035830.7, "by_exchange": {...}},# "total": {"total_liq_usd": 743631889.64, "long_liq_usd": 175240866.53, "short_liq_usd": 568391023.1,# "long_pct": 0.2357, "short_pct": 0.7643},# "buckets": 1846, "covered_hours": 24.0, "window_hours": 24,# "window_start": "2026-09-21T05:55:00+00:00", "window_end": "2026-09-22T05:55:00+00:00",# "updated_at": "2026-09-22T05:50:00+00:00"}{"data": {"exchanges", "coins", "others", "total", "buckets", "covered_hours", "window_hours", "window_start", "window_end", "updated_at"}}.
| Field | Type | Unit | Description |
|---|---|---|---|
exchanges[] | object[] | — | One row per feed, sorted by total desc: exchange, total_liq_usd, long_liq_usd, short_liq_usd, long_pct, short_pct, events, last_event_at. Every feed is always listed: amounts null = no data received from that feed in the window (sorted last), 0.0 = connected but no liquidations |
exchanges[].price_basis / .coverage / .time_basis | string | — | How comparable that row is: trade_avg / bankruptcy / unverified; full, full_unstated, sampled_1s, aggregated_1s, sampled_undisclosed; event. Keep them when re-publishing the numbers — a sampled feed is not a full one |
coins[] | object[] | — | The top top_n by cross-exchange total: token, token_id (0 when the symbol has no CoinMarketCap id), total_liq_usd, long_liq_usd, short_liq_usd, by_exchange{name: {total/long/short_liq_usd}}. by_exchange is sparse — a feed with nothing for that coin has no key; read it as 0 when that feed's exchanges[] total is not null |
others | object | — | Everything top_n cut off, same fields plus coin_count, so coins[] + others adds back to each exchange's total |
total | object | USD / ratio | total_liq_usd, long_liq_usd, short_liq_usd, long_pct, short_pct |
covered_hours | float | h | Hours of the window that actually have buckets (< hours right after a collector restart) |
buckets | int | — | Number of 5-minute buckets aggregated |
window_hours / window_start / window_end | int / string | h / ISO 8601 UTC | The window as the server resolved it |
updated_at | string | ISO 8601 UTC | Latest bucket used |
long_liq_usd = long positions liquidated (price fell); short_liq_usd = shorts liquidated (price rose).
| Status | Body | When |
|---|---|---|
| 400 | {"error": "hours must be between 1 and 168"} / {"error": "top_n must be between 1 and 50"} | Out-of-range parameter |
200 with the same shape and every amount null, buckets: 0 — never a table of zeros. Check total.total_liq_usd before using the numbers./liquidation/get_coin; a normalised long-history signal is /liquidation/get_alpha./liquidation/get_coin uses for windows["24"]./long_short_ratio/get_table Every collected coin × every long/short-ratio source, as of now. Ten sources: Binance, OKX and Gate.io each publish three kinds — all accounts, top-trader accounts, top-trader positions — and Bybit publishes accounts only. Rows are ordered by Binance open-interest notional. Only coins that resolve to a CoinMarketCap crypto are listed; the API-key response is the full table (full: true), the anonymous studio twin only the rows of its 30-coin whitelist.
None.
data = requests.get(f"{BASE_URL}/long_short_ratio/get_table", headers=headers, timeout=30).json()["data"]keys = [s["key"] for s in data["sources"] if not s["stale"]]btc = next(c for c in data["coins"] if c["token"] == "BTC")print({k: btc[k] for k in keys if btc[k] is not None})# Live capture 2026-09-22 via the anonymous studio twin (/studio/charts/long_short_ratio/table) —# same inner shape; the API-key response wraps it in "data" and has full: true with every row.# {"coins": [{"binance_account": 0.8818, "binance_top_account": 1.0149, "binance_top_position": 2.2666,# "bybit_account": 1.0375, "gate_account": 0.7294, "gate_top_account": 0.6944,# "gate_top_position": 1.6436, "okx_account": 0.9084, "okx_top_account": 0.8655,# "okx_top_position": 1.0222, "token": "BTC", "token_id": 1}, ...],# "sources": [{"exchange": "binance", "key": "binance_account", "last_at": "2026-09-22T05:50:00+00:00",# "stale": false, "type": "account"}, ...,# {"exchange": "bybit", "key": "bybit_account", "last_at": "2026-09-22T05:50:00+00:00",# "stale": false, "type": "account"}],# "summary": {"binance_long_majority": 436, "binance_tokens": 509},# "tokens_shown": 30, "tokens_total": 611, "full": false, "updated_at": "2026-09-22T05:50:00+00:00"}Collection start (first stored bucket, measured on BTC 2026-09-22)
| Source key | Collecting since |
|---|---|
binance_account | 2021-05-11 |
binance_top_account / binance_top_position | 2026-08-22 |
okx_account / okx_top_account / okx_top_position | 2025-02-18 |
gate_account / gate_top_account / gate_top_position | 2026-08-12 |
bybit_account | 2026-08-12 |
Every source is now older than the 7 days this dataset serves, so none of them limits a query — the dates matter only if you are told a source "has no history".
{"data": {"coins", "sources", "summary", "tokens_shown", "tokens_total", "full", "updated_at"}}.
| Field | Type | Unit | Description |
|---|---|---|---|
coins[] | object[] | — | One row per coin: token, token_id, plus one value per source key |
coins[].<source key> | float / null | ratio | Long accounts (or positions) ÷ short. null = that exchange has no such feed for the coin. Long share = r / (1 + r) — the API does not precompute it |
sources[] | object[] | — | The ten feeds, in column order. Read this, never a hard-coded key list |
sources[].key | string | — | <exchange>_<type>, e.g. binance_top_position — the key used in coins[] |
sources[].exchange / .type | string | — | binance / okx / gate / bybit; account / top_account / top_position |
sources[].last_at | string | ISO 8601 UTC | Newest sample from that feed |
sources[].stale | bool | — | That feed's newest sample is over 1 hour old (measured against now). Top-level updated_at is the newest source and says nothing about any single one — judge a source by its own last_at / stale |
summary.binance_tokens / .binance_long_majority | int | — | Coins with a Binance account ratio / of those, how many are above 1. Computed over the whole table, not the rows shown |
tokens_shown / tokens_total | int | — | Rows returned / rows in the table. Equal on an API key |
full | bool | — | true on an API key; false on the anonymous studio twin |
updated_at | string | ISO 8601 UTC | Newest bucket across sources |
"Top trader" is a different population at each exchange — do not compare the levels across exchanges.
| Exchange | Who counts as a top trader (official wording) |
|---|---|
| Binance | "the top 20% users with the highest margin balance" |
| OKX | "the top 5% of traders with the largest open position value" |
| Gate.io | Never published — the docs only name the fields |
So binance_top_account above okx_top_account says nothing about which venue's big traders are more long. Compare each source against its own history instead.
| Status | Body | When |
|---|---|---|
| 503 | {"error": "long short ratio data unavailable"} | No fresh snapshot — retry later; never read as an empty market |
/long_short_ratio/get_coin (7 days) — there is no long-history endpoint for this dataset./long_short_ratio/get_coin One coin, all ten sources: the latest 5-minute value of each, a 7-day hourly series per source, and the Binance perp close on the same frame.
symbol is the normalised coin nameparams = {"symbol": "BTC"}data = requests.get(f"{BASE_URL}/long_short_ratio/get_coin", headers=headers, params=params, timeout=30).json()["data"]latest = data["latest"]["binance_top_position"] # null when Binance does not list the coinif latest is not None: r = latest["value"] print("top-trader long share:", round(r / (1 + r), 4))# Live capture 2026-09-22 (abridged with ...; anonymous studio twin, same inner shape):# {"latest": {"binance_account": {"ts": "2026-09-22T05:50:00+00:00", "value": 0.8818},# "binance_top_account": {"ts": "2026-09-22T05:50:00+00:00", "value": 1.0149}, ... 10 keys},# "series": {"bucket_seconds": 3600, "days": 7, "price_symbol": "BTCUSDT", "price_multiplier": 1,# "provisional_from": 1790053200,# "timestamp": [..., 1790049600, 1790053200],# "binance_account": [..., 0.8699, 0.8818], "price": [..., 85424.7, 85495.8], ... one array per source},# "sources": [{"exchange": "binance", "key": "binance_account", "last_at": "2026-09-22T05:50:00+00:00",# "listed": true, "stale": false, "type": "account"}, ... 10 rows],# "symbol": "BTC", "token_id": 1, "updated_at": "2026-09-22T05:50:00+00:00"}{"data": {"latest", "series", "sources", "symbol", "token_id", "updated_at"}}.
| Field | Type | Unit | Description |
|---|---|---|---|
latest.<source key> | object / null | — | {value, ts} — that source's newest 5-minute sample; null when the source does not list the coin |
series.bucket_seconds / .days | int | s / d | 3600 / 7 |
series.timestamp | int[] | epoch s | 168 slots, oldest → newest, one per hour |
series.<source key> | float[] / null | ratio | Last sample of each hour; null for an hour with no sample. The whole field is a single null (not an array) for a source that does not list the coin |
series.price | float[] / null | USD | Binance perp close on the same frame. A single null (with price_symbol / price_multiplier also null) when the coin has no Binance perp |
series.price_symbol / .price_multiplier | string / int | — | Which perp the price came from and its contract multiplier (1000PEPEUSDT → 1000; price ÷ price_multiplier = price per coin) |
series.provisional_from | int / null | epoch s | First slot that can still change (sources finalise up to ~10 min late); null when no source has data |
sources[] | object[] | — | The full roster, same fields as the table plus listed |
sources[].listed | bool | — | false = that exchange has no such feed for this coin; its latest and series entries are null |
symbol / token_id / updated_at | — | — | As in the table |
| Status | Body | When |
|---|---|---|
| 400 | {"error": "symbol is required"} | symbol missing, blank, over 32 chars, or nothing left after the quote suffix is stripped |
| 404 | {"error": "<SYMBOL> is not a collected symbol"} | No source collects the coin — an answer, not a transient |
| 503 | {"error": "long short ratio data unavailable"} | A listed source could not be read. null only ever means "that venue does not list it" |
/long_short_ratio/get_table applies here too.start_date / end_date./studio/charts/...) serve the same payload from the same builder without a key, which is where these examples were taken. They are not a substitute for the API-key endpoints: the tables are cut to 30 coins (full: false), and a coin outside the studio whitelist answers 403 {"error_code": "ERR001", ..., "anon_whitelist": [...]} instead of data. The API-key endpoints documented here have no whitelist and no row cut./oi_imbalance/get_table Every collected coin × five exchanges, in USD notional. Basis: USDT-margined perpetuals only, USD notional, one side. An exchange that reports both sides is halved (exchanges[].side_factor, Gate.io = 0.5). Because every value is already USD notional, multiplied contracts (1000PEPE and friends) add across exchanges with no rescaling.
None.
data = requests.get(f"{BASE_URL}/oi_imbalance/get_table", headers=headers, timeout=30).json()["data"]crowded = sorted((c for c in data["coins"] if c["oi_mcap"] is not None), key=lambda c: -c["oi_mcap"])[:10]print(data["total"]["oi"], [(c["token"], round(c["oi_mcap"], 4)) for c in crowded])# Live capture 2026-09-22 (abridged with ...; anonymous studio twin, same inner shape):# {"coins": [{"token": "BTC", "token_id": 1, "oi_total": 18645450917.48, "chg_1h": -0.001775,# "chg_4h": -0.001046, "chg_24h": 0.128725, "market_cap": 1629947967503.241, "oi_mcap": 0.011439,# "by_exchange": {"binance": {"oi": 9417422808.02, "chg_1h": 2e-05, "chg_4h": 0.010203, "chg_24h": 0.067527},# "bingx": {"oi": 1328003926.8, ...},# "bybit": {"oi": 2569097877.96, "chg_1h": -0.008636, "chg_4h": -0.030159, "chg_24h": null},# "gate": {...}, "okx": {"oi": 2575361192.92, ..., "chg_24h": null}}}, ...],# "exchanges": [{"key": "binance", "oi": 24712717530.01, "side_factor": 1.0, "since": null, "full_7d": true,# "last_at": "2026-09-22T05:25:00+00:00", "stale": false}, ... 5 rows],# "total": {"oi": 47428938620.05, "chg_1h": -0.008919, "chg_4h": -0.010508, "chg_24h": 0.073881,# "n_exchanges": 5, "n_full_7d": 3},# "summary": {"oi_mcap_leader": "SAGA", "oi_mcap_leader_value": 1.718336},# "tokens_shown": 30, "tokens_total": 622, "full": false, "updated_at": "2026-09-22T05:30:00+00:00"}Collection start (first stored bucket, measured on BTC 2026-09-22)
| Exchange | Collecting since |
|---|---|
binance | 2021-12-01 |
bingx | 2025-04-15 |
gate | 2026-08-12 |
okx | 2026-09-21 |
bybit | 2026-09-21 |
OKX and Bybit are why n_full_7d is 3 of 5 and why their chg_24h was still null on 2026-09-22 — read exchanges[].since / full_7d rather than these dates, which age out.
{"data": {"coins", "exchanges", "total", "summary", "tokens_shown", "tokens_total", "full", "updated_at"}}.
| Field | Type | Unit | Description |
|---|---|---|---|
coins[].token / .token_id | string / int | — | Coin |
coins[].oi_total | float | USD | Summed across the five exchanges |
coins[].chg_1h / .chg_4h / .chg_24h | float / null | fraction | Decimal change (0.0675 = +6.75 %). Each window counts only the exchanges that have a baseline at that window's start, numerator and denominator over the same set; null when none does |
coins[].market_cap | float / null | USD | CoinMarketCap market cap; null when there is no usable one |
coins[].oi_mcap | float / null | ratio | oi_total ÷ market_cap; null when market_cap is |
coins[].by_exchange | object | — | {exchange: {oi, chg_1h, chg_4h, chg_24h}}, one key per exchange; null when the coin is not listed there. A per-window null means that exchange had no baseline that far back — a feed younger than the window |
exchanges[] | object[] | — | binance, okx, bingx, bybit, gate — whole-market oi, side_factor, since, full_7d, last_at, stale |
exchanges[].since / .full_7d | string / bool | date | The feed's first day when it has under 7 days of history (full_7d: false), else null / true. Informational on this table (it has no 7-day window); on /oi_imbalance/get_coin such a feed has no 7 d baseline and is left out of series.total |
total | object | — | Whole-market oi, chg_1h/4h/24h, n_exchanges, n_full_7d |
summary.oi_mcap_leader / _value | string / float | — | Highest OI ÷ market cap among the top 100 coins by OI |
tokens_shown / tokens_total / full / updated_at | — | — | As in the long/short-ratio table |
Not the same number as the OI 失衡 indicator. /oi_imbalance/get_overview_data (and the oi_imbalance alpha behind screener conditions and alerts) is a three-exchange aggregate — Binance + OKX + BingX. This table is five exchanges on the basis above. The two oi_total values differ, so a threshold tuned on one does not carry over to the other.
| Status | Body | When |
|---|---|---|
| 503 | {"error": "open interest data unavailable"} | The job has no fresh result (missing or over an hour old) — never a table of zeros |
chg_24h: null on OKX / Bybit in the capture above is the young-feed rule, not a gap in the market: those two started on 2026-09-21, so they had no 24 h baseline yet./oi_imbalance/get_coin; backtest-length history for one coin on one exchange is /oi_imbalance/get_history./oi_imbalance/get_coin One coin's open interest per exchange, on the same basis as the table: current value and share, four change windows with the exchanges each counted, and a 7-day hourly total line.
symbol, exactly as in /long_short_ratio/get_coin.
data = requests.get(f"{BASE_URL}/oi_imbalance/get_coin", headers=headers, params={"symbol": "BTC"}, timeout=30).json()["data"]day = data["windows"]["24h"]print(data["oi_total"], day["chg"], "counted:", day["exchanges"])# Live capture 2026-09-22 (abridged with ...; anonymous studio twin, same inner shape):# {"exchanges": [{"key": "binance", "oi": 9454606424.48, "share": 0.5055, "chg_1h": 0.00037, "chg_4h": 0.014471,# "chg_24h": 0.064607, "chg_7d": 0.17205, "side_factor": 1.0, "listed": true, "since": null,# "full_7d": true, "last_at": "2026-09-22T05:50:00+00:00", "stale": false},# {"key": "okx", ..., "since": "2026-09-21", "full_7d": false}, ... 5 rows],# "windows": {"1h": {"chg": -0.000462, "chg_usd": -8636171.48, "exchanges": ["binance", "okx", "bingx", "bybit", "gate"]},# "4h": {...},# "24h": {"chg": 0.12231, "chg_usd": 1474912315.85, "exchanges": ["binance", "bingx", "gate"]},# "7d": {"chg": 0.212184, "chg_usd": 2368974857.56, "exchanges": ["binance", "bingx", "gate"]}},# "series": {"bucket_seconds": 3600, "days": 7, "timestamp": [1789452000, 1789455600, ...],# "total": [11171863169.89, 11167043101.84, ...], "total_exchanges": ["binance", "bingx", "gate"],# "price": [...], "price_symbol": "BTCUSDT", "price_multiplier": 1, "provisional_from": 1790053200},# "oi_total": 18704068031.08, "market_cap": 1629947967503.241, "oi_mcap": 0.011475, "oi_mcap_rank": 580,# "tokens_total": 622, "symbol": "BTC", "token_id": 1, "updated_at": "2026-09-22T05:55:00+00:00"}{"data": {"exchanges", "windows", "series", "oi_total", "market_cap", "oi_mcap", "oi_mcap_rank", "tokens_total", "symbol", "token_id", "updated_at"}}.
| Field | Type | Unit | Description |
|---|---|---|---|
exchanges[] | object[] | — | The full five-exchange roster: key, oi (USD), share (of oi_total), chg_1h/4h/24h/7d, side_factor, listed, since, full_7d, last_at, stale |
exchanges[].listed | bool | — | false = the coin is not listed there; its values are null |
oi_total / market_cap / oi_mcap | float | USD / ratio | As in the table |
oi_mcap_rank / tokens_total | int / null | — | Rank by oi_mcap in the table job's last round; null when that job has no fresh result |
windows.<1h|4h|24h|7d>.chg / .chg_usd | float / null | fraction / USD | Change of the counted exchanges' total |
windows.<w>.exchanges | string[] | — | Which exchanges were counted in that window — a young feed is absent, so 24 h / 7 d can count fewer exchanges than 1 h |
series.timestamp | int[] | epoch s | 168 hourly slots, oldest → newest |
series.total | float[] / null | USD | Total OI per slot — only the series.total_exchanges (the full_7d feeds) are in this line, so it is not comparable in level to oi_total. A slot is null when any of those exchanges has no sample that hour; the whole field is null when no exchange is full_7d for the coin |
series.total_exchanges | string[] | — | Which exchanges the line adds up |
series.price / .price_symbol / .price_multiplier / .provisional_from | — | — | As in /long_short_ratio/get_coin |
400 / 404 / 503 exactly as /long_short_ratio/get_coin, with {"error": "open interest data unavailable"} on 503.
windows["1h"]["exchanges"] having five entries while windows["24h"] has three is the young-feed rule, not missing data — read that list before comparing windows./oi_imbalance/get_table applies to this oi_total too./oi_imbalance/get_history (one exchange, coins rather than USD — a different basis from oi_total)./oi_imbalance/get_history One coin's open interest on one exchange, as a time series you can backtest on — the same basis as the Studio dashboard 未平倉量 card. alpha is one-sided open interest in coins, not USD. Multiplied contracts are converted back to coins (1000PEPE returns a PEPE count). Each bucket is the last reading of its period — open interest is a stock, never summed.
/oi_imbalance/get_coin1w is a 400 (unit not supported); 1m is read as 1min, so it is a 400 for being below 5minPer-request window: at most 365 days; a longer range is silently clamped (start_date moved to end_date − 365 days, no error), as in /kline.
params = {"symbol": "BTC", "period": "1d", "start_date": "2022-01-01", "end_date": "2022-01-03"}data = requests.get(f"{BASE_URL}/oi_imbalance/get_history", headers=headers, params=params, timeout=120).json()["data"]# Live capture 2026-10-02:# {"data": {"alpha": [72913.725, 73310.482, 79515.424], "close": [47704.35, 47280.0, 46445.81],# "exchanges": ["binance"], "timestamp": [1640995200.0, 1641081600.0, 1641168000.0]}}params = {"symbol": "SOL", "period": "4h", "oi_exchange": "bybit", "start_date": "2026-09-30", "end_date": "2026-09-30"}# {"data": {"alpha": [3443506.2, 3344470.1, 3269534.6, 3108222.6, 3082040.9, 3042368.1],# "close": [119.08, 118.41, 119.47, 119.25, 117.17, 118.05], "exchanges": ["bybit"],# "timestamp": [1790726400.0, 1790740800.0, 1790755200.0, 1790769600.0, 1790784000.0, 1790798400.0]}}params = {"symbol": "1000PEPE", "period": "1d", "start_date": "2026-09-01", "end_date": "2026-09-02"}# alpha is PEPE coins; close is per 1000 PEPE, so USD OI = alpha × close / 1000# {"data": {"alpha": [19073240707000.0, 17615934147000.0], "close": [0.0034752, 0.0034306],# "exchanges": ["binance"], "timestamp": [1788220800.0, 1788307200.0]}}{"data": {"timestamp", "alpha", "close", "exchanges"}}, parallel arrays, oldest → newest.
| Field | Type | Unit | Description |
|---|---|---|---|
timestamp | float[] | Unix seconds (UTC) | Bucket start |
alpha | float[] | coins | One-sided open interest on oi_exchange, last reading of the bucket |
close | float[] | USDT | Binance USDT-M perpetual price — per contract unit, so per 1000 coins for 1000PEPE |
exchanges | string[] | — | The exchange actually read, e.g. ["binance"] |
alpha × close is not USD open interest on a multiplied contract. close there is the price per contract unit (per 1000 coins for 1000PEPE) while alpha is in single coins — divide close by the multiplier first. For non-multiplied contracts such as BTC, alpha × close ≈ USD open interest.
Gate.io: always send start_date ≥ 2026-03-28 — the default window (end_date − 365 days) starts before Gate's history and is a 400.
Not the same number as /oi_imbalance/get_table / get_coin (five exchanges summed, USD) and not the OI 失衡 indicator (/oi_imbalance/get_overview_data).
| Status | Body | When |
|---|---|---|
| 400 | {"error": "symbol is required"} / {"error": "period is required"} | Missing (a 400 here, not the 403 of the indicator endpoints) |
| 400 | {"error": "period must be at least 5min, in min / h / d units"} | period below 5min (including 1m, read as 1min) or in a unit other than min / h / d (1w) |
| 400 | {"error": "invalid date format, expected YYYY-MM-DD"} | Malformed start_date / end_date |
| 400 | {"error": "start_date must not be after end_date"} | start_date > end_date |
| 400 | {"error": "oi_exchange must be one of binance, bybit, gate"} | oi_exchange outside the list |
| 400 | {"error": "no <exchange> open interest for <TOKEN> at start_date; this exchange's history may start later — try a later start_date"} | The window starts before that exchange's history (see Data from). Without start_date, oi_exchange=gate always hits this until its history passes 365 days (≈ 2027-03) — for Gate always send start_date ≥ 2026-03-28 |
| 404 | {"error": "<TOKEN> is not a collected symbol on <exchange>"} | That exchange does not list the coin, the coin has no Binance perpetual, or it is delisted — an answer, not a transient |
| 503 | {"error": "<exchange> open interest data unavailable for <TOKEN>"} | Data could not be read right now — retry |
200 with empty arrays means no bucket in that window (e.g. the coin listed after it) — do not cache it as a permanent "no data".end_date is today./taker_intensity/get_cvd_table Taker (market-order) buy and sell turnover per coin, in USD, across three exchanges: Binance from the 5-minute kline's taker-buy quote volume (sell = the bar's total minus it), OKX from its USD taker volume, Gate.io from taker contracts × the same row's multiplier and mark price. Perpetuals only — no spot — and aggregated from 5-minute bars, not from trade-by-trade prints. Each exchange's own reported turnover is used; volume is never multiplied by a price borrowed from another venue.
None.
data = requests.get(f"{BASE_URL}/taker_intensity/get_cvd_table", headers=headers, timeout=30).json()["data"]buying = sorted((c for c in data["coins"] if c["net_24h"] is not None), key=lambda c: -c["net_24h"])[:10]print(data["total"]["net_24h"], [(c["token"], c["net_24h"]) for c in buying])# Live capture 2026-09-22 (abridged with ...; anonymous studio twin, same inner shape):# {"coins": [{"token": "BTC", "token_id": 1, "buy_24h": 24607245298.03, "sell_24h": 23128502231.73,# "net_1h": -212647361.27, "net_4h": -207128163.51, "net_24h": 1478743066.31,# "by_exchange": {"binance": {"buy_24h": 12663681424.94, "sell_24h": 12135756153.44,# "net_1h": -191133129.94, "net_4h": -217337267.5, "net_24h": 527925271.5},# "gate": {...}, "okx": {...}}}, ...],# "exchanges": [{"key": "binance", "buy_24h": 34978603608.55, "sell_24h": 35112588381.38,# "net_24h": -133984772.74, "last_at": "2026-09-22T05:25:00+00:00", "stale": false}, ... 3 rows],# "total": {"buy_24h": 63543431942.93, "sell_24h": 62491177680.21, "net_24h": 1052254262.8},# "tokens_shown": 30, "tokens_total": 591, "full": false, "updated_at": "2026-09-22T05:25:00+00:00"}Collection start (first stored bucket, measured on BTC 2026-09-22)
| Exchange | Source field | Collecting since |
|---|---|---|
binance | 5-minute kline (taker-buy quote volume) | 2020-01-01 |
gate | contract_stats | 2026-08-12 |
okx | taker_volume_usd | 2026-09-21 |
OKX is additionally capped by the venue keeping only 5 days, so it stays full_7d: false until a week after that date. This table carries no since / full_7d (it has no 7-day window) — read them per coin from /taker_intensity/get_cvd_coin's exchanges[], not from these dates.
{"data": {"coins", "exchanges", "total", "tokens_shown", "tokens_total", "full", "updated_at"}}.
| Field | Type | Unit | Description |
|---|---|---|---|
coins[].token / .token_id | string / int | — | Coin |
coins[].buy_24h / .sell_24h | float / null | USD | Taker buy / sell turnover over the rolling 24 h, summed over the coin's non-stale exchanges; null when all of them are stale |
coins[].net_1h / .net_4h / .net_24h | float / null | USD | buy − sell over each rolling window (same null rule) |
coins[].by_exchange | object | — | {exchange: {buy_24h, sell_24h, net_1h, net_4h, net_24h}}, one key per exchange; null when the coin is not listed there or that exchange's data for it is stale |
exchanges[] | object[] | — | binance, okx, gate — whole-market buy_24h, sell_24h, net_24h, last_at, stale |
exchanges[].stale | bool | — | That feed's last bar is over an hour old: its windows come back null and it is left out of the totals rather than contributing a sum that silently covers less than the window |
total | object | USD | Whole-market buy_24h, sell_24h, net_24h over the fresh exchanges |
tokens_shown / tokens_total / full / updated_at | — | — | As in the other raw tables |
| Status | Body | When |
|---|---|---|
| 503 | {"error": "cvd data unavailable"} | The job has no fresh result — never zeros |
taker_intensity alpha (/taker_intensity/get_alpha), which is a normalised z-score-like signal with years of history. This is raw USD turnover, now.net_24h is not a calendar day./taker_intensity/get_cvd_coin One coin's taker buy / sell / net per exchange (same basis as the table) plus a 7-day hourly net and its running cumulative — the CVD line itself.
symbol, exactly as in /long_short_ratio/get_coin.
data = requests.get(f"{BASE_URL}/taker_intensity/get_cvd_coin", headers=headers, params={"symbol": "BTC"}, timeout=30).json()["data"]print(data["windows"]["24h"]["net"], "line covers:", data["series"]["exchanges"], "last cvd:", data["series"]["cvd"][-1])# Live capture 2026-09-22 (abridged with ...; anonymous studio twin, same inner shape):# {"exchanges": [{"key": "binance", "listed": true, "since": null, "full_7d": true, "stale": false,# "last_at": "2026-09-22T05:50:00+00:00",# "windows": {"1h": {"buy": 334079345.8, "sell": 432484304.99, "net": -98404959.2},# "4h": {...}, "24h": {"buy": 12764594401.23, "sell": 12156150828.71, "net": 608443572.52},# "7d": {"buy": 48395824125.78, "sell": 48033568140.24, "net": 362255985.54}}},# {"key": "okx", "full_7d": false, "since": "2026-09-21", ...}, {"key": "gate", ...}],# "windows": {"1h": {"buy": 661443769.03, "sell": 760343818.66, "net": -98900049.65}, "4h": {...},# "24h": {"buy": 24795988390.84, "sell": 23206873390.07, "net": 1589115000.77},# "7d": {"buy": 69832361511.62, "sell": 68794205279.31, "net": 1038156232.31}},# "series": {"bucket_seconds": 3600, "days": 7, "timestamp": [1789452000, 1789455600, ...],# "net": [-53629060.26, -75636445.35, ...], "cvd": [0.0, -75636445.35, ...],# "exchanges": ["binance", "gate"], "price": [...], "price_symbol": "BTCUSDT",# "price_multiplier": 1, "provisional_from": 1790053200},# "symbol": "BTC", "token_id": 1, "updated_at": "2026-09-22T05:50:00+00:00"}{"data": {"exchanges", "windows", "series", "symbol", "token_id", "updated_at"}}.
| Field | Type | Unit | Description |
|---|---|---|---|
windows.<1h|4h|24h|7d> | object | USD | {buy, sell, net} summed over the fresh exchanges |
exchanges[] | object[] | — | The full roster: key, listed, windows (same four, per exchange), since, full_7d, last_at, stale |
exchanges[].full_7d | bool | — | false = under 7 days of history for this coin there: its 7 d window is null and it is excluded from the 7 d total and from the series. OKX keeps only 5 days, so it is false until a week after the feed's start |
series.timestamp | int[] | epoch s | 168 hourly slots, oldest → newest |
series.net | float[] | USD | Net taker flow per clock hour, summed over series.exchanges; null for an hour with no data. When series.exchanges is empty every slot is null and cvd stays flat at 0 — the line carries no information then |
series.cvd | float[] | USD | Running total of net; cvd[0] = 0 — the line is a shape, not an absolute level |
series.exchanges | string[] | — | Which exchanges the line adds up |
series.price / .price_symbol / .price_multiplier / .provisional_from | — | — | As in /long_short_ratio/get_coin |
400 / 404 / 503 exactly as /long_short_ratio/get_coin, with {"error": "cvd data unavailable"} on 503.
series.exchanges being shorter than exchanges[] is the full_7d rule — compare the series against itself, not against windows["24h"], which counts more venues.cvd[0] = 0 by construction: only the slope and the turning points carry information./cme_cot/get_latest The latest weekly CFTC row for each of the four CME crypto futures, plus standard + micro summed in coins per asset. Same shape as one row of /cme_cot/get_history, without price.
None.
data = requests.get(f"{BASE_URL}/cme_cot/get_latest", headers=headers, timeout=60).json()["data"]btc = next(c for c in data["contracts"] if c["key"] == "btc")# Live capture 2026-10-07 (abridged):# {"key": "btc", "name": "Bitcoin Futures (CME)", "cftc_code": "133741", "coin": "BTC", "coin_per_contract": 5,# "latest": {"date": "2026-09-29", "open_interest": 19596, "open_interest_change": -2719,# "tff": {"leveraged_funds": {"long": 4980, "short": 11836, "spread": 538, "net": -6856,# "long_change": 235, "short_change": -862, "spread_change": -2187, "net_change": 1097},# "asset_manager": {"long": 5069, "short": 1483, "spread": 297, "net": 3586, ...}, ...},# "legacy": {"non_commercial": {...}, "commercial": {...}, "nonreportable": {...}}}}# data["source_updated"] == "Fri, 02 Oct 2026 19:30:08 GMT", data["stale"] == False{"data": {"contracts": [...], "combined": [...], "report", "units", "source", "source_updated", "fetched_at", "stale"}}
| Field | Description |
|---|---|
contracts[] | One per contract: key (btc, micro_btc, eth, micro_eth), name, cftc_code, coin, coin_per_contract (5 / 0.1 / 50 / 0.1), latest (a row, see get_history; null if the contract has no rows) |
combined[] | btc_combined, eth_combined: name, coin, components, units, micro_since, note, latest (a combined row, in coins) |
report | futures_only |
units | Unit of contracts[].latest positions: contracts (× coin_per_contract for coins) |
source | CFTC attribution line — show it with any figure you publish |
source_updated | When CFTC last updated the dataset |
fetched_at | When Blave fetched it (UTC) |
stale | true = CFTC was unreachable and the last stored copy is served |
| Status | Body | When |
|---|---|---|
| 503 | {"error": "CFTC data unavailable. Please retry shortly."} | CFTC unreachable and no stored copy |
/cme_cot/get_history One contract's weekly positioning by trader category. Rows are dated by the report date — the day the positions are as of, usually a Tuesday (a Monday when Tuesday is a US holiday). The data became public later: normally that week's Friday 15:30 ET; a federal holiday Wednesday–Friday moves the release to the next business day, and a government shutdown delays it by weeks (the 2018-12-24 … 2019-02-26 reports came out 2019-02-01 … 03-05; the 2025-09-30 … 2026-01-20 reports 2025-11-19 … 2026-01-23 — CFTC Releases 7864-19 and 9138-25). A backtest must not act on a row before its release.
*_combined = standard + micro summed in coins2018-01-01) for full historydata = requests.get(f"{BASE_URL}/cme_cot/get_history", headers=headers, params={"contract": "btc_combined", "start_date": "2026-09-01"}, timeout=60).json()["data"]lev_net = {r["date"]: r["tff"]["leveraged_funds"]["net"] for r in data["rows"]} # BTC# Live capture 2026-10-07 (abridged): 5 rows 2026-09-01 … 2026-09-29# {"contract": {"key": "btc_combined", "name": "Bitcoin + Micro Bitcoin Futures (CME), in BTC", "coin": "BTC",# "components": ["btc", "micro_btc"], "micro_since": "2021-05-04", "units": "coins (...)", "note": "..."},# "rows": [..., {"date": "2026-09-29", "included": ["btc", "micro_btc"], "price": 83663.66,# "open_interest": 100612.0, "open_interest_change": -14522.7,# "tff": {"leveraged_funds": {"long": 25889.6, "short": 61305.6, "spread": 2742.4, "net": -35416.0,# "long_change": 680.4, "short_change": -4283.9,# "spread_change": -11214.8, "net_change": 4964.3},# "asset_manager": {"long": 25570.8, "short": 7421.7, "net": 18149.1, ...},# "dealer": {"net": 13483.9, ...}, "other_reportables": {...}, "nonreportable": {...}},# "legacy": {"non_commercial": {"net": 11754.9, ...}, "commercial": {"net": -13695.5, ...},# "nonreportable": {...}}}],# "price_source": "Binance spot BTCUSDT, UTC daily close on the report date (Tuesday)",# "report": "futures_only", "source": "Source: U.S. Commodity Futures Trading Commission (CFTC), ...",# "source_updated": "Fri, 02 Oct 2026 19:30:08 GMT", "fetched_at": "2026-10-07T09:16:35Z", "stale": false}{"data": {"contract": {...}, "rows": [...], "price_source", "report", "units", "source", "source_updated", "fetched_at", "stale"}}, rows oldest → newest.
contract: key, name, coin, and cftc_code + coin_per_contract (single contract) or components + micro_since + note (combined).
Each row:
| Field | Type | Description |
|---|---|---|
date | string | Report date — usually a Tuesday, a Monday when Tuesday is a US holiday |
open_interest / open_interest_change | number | Total open interest and its week-over-week change |
tff | object | Groups dealer, asset_manager, leveraged_funds, other_reportables, nonreportable |
legacy | object | null | Groups non_commercial, commercial, nonreportable; null if CFTC has no Legacy row for that week |
price | float | null | Binance spot BTCUSDT / ETHUSDT UTC daily close on the report date; null when unavailable |
included | string[] | Combined contracts only: which contracts this row sums (["btc"] before micro_since) |
Each group: long, short, spread (not for nonreportable / commercial), net (= long − short), and long_change, short_change, spread_change, net_change. Units: contracts for a single contract, coins for a combined one. The *_change fields are CFTC's own week-over-week figures, not row-to-row differences — CFTC skips weeks (e.g. government shutdowns), so never diff rows yourself.
| Status | Body | When |
|---|---|---|
| 400 | {"error": "contract must be one of btc, micro_btc, eth, micro_eth, btc_combined, eth_combined"} | Unknown contract |
| 400 | {"error": "Invalid start_date, expected YYYY-MM-DD"} (or end_date) / {"error": "start_date must not be after end_date"} | Bad date / reversed range |
| 503 | {"error": "CFTC data unavailable. Please retry shortly."} | CFTC unreachable and no stored copy |
*_combined has a break at micro_since: the week micro joins, the totals step up and that week's *_change includes micro's whole first position. Start a combined backtest after micro_since, or use the single btc / eth contract.source next to any figure you show. Not endorsed by the CFTC.