Dealer Hedge Flow API
The Dealer Hedge Flow API returns how options dealers are positioned in Deribit BTC options and what their hedging would do if the price moved: for every price level, how many US dollars of BTC dealers would buy or sell to stay delta-hedged on the way there, and whether that flow amplifies or dampens the move. It also returns net gamma exposure (GEX), the zero gamma level and a few legacy options statistics. A new snapshot is computed every hour.
How dealer positions are rebuilt, the formulas and the assumptions: Dealer Hedge Flow Methodology.
The Dealer Hedge Flow is a descriptive model of dealer positioning, not a price target or a trading signal.
Endpoints
| Method | Path | Description |
|---|---|---|
GET | /v1/options/gex | Daily series: one row per day (the 00:00 UTC snapshot) |
GET | /v1/options/gex/hourly | Every hourly snapshot (Pro) |
GET | /v1/options/gex/profile | Hedge flow by price for one snapshot (default: the latest) |
GET | /v1/options/gex/heatmap | Time × price matrix of impact for a heatmap |
Base URL: https://api.blocklens.co. All responses are JSON in the envelope {"success": true, "data": …}: for the
series data is a list of rows (with count, access and message next to it), for /profile and /heatmap it is
an object that contains access. Errors use {"success": false, "message": {…}, "timestamp": "…"}
(see Errors).
Authentication
All requests require an API key:
Authorization: Bearer YOUR_API_KEY
See Authentication for API keys and Rate Limits & Tiers for which plans include API access and the request limits.
Signs and units
- All amounts are in USD. GEX values (
net_gex,gex[],strikes[].call_gex/put_gex) are USD per 1% move; hedge flow and impact are USD for the whole move from the current price to the level. hedge_flow> 0 — dealers buy BTC on the way to the level; < 0 — they sell.impact=hedge_flow× sign(level − spot): > 0 — amplify (the flow pushes the move further), < 0 — dampen (it leans against the move).net_gex> 0 — dealers are net long gamma (dampening regime); < 0 — net short gamma (amplifying regime).spotis the BTC index price of the snapshot; levels lie on an absolute $500 grid within ±30% of it.zero_gammais searched within ±50% ofspot, so it can lie outside the level grid;nullwhen the GEX curve keeps one sign there.
Tiers and history
The tier rules are enforced by the API itself, not only by the Lab interface:
| Free | Pro, Enterprise | |
|---|---|---|
/v1/options/gex (daily) | the last 30 days | full history since 2026-03-16 |
/v1/options/gex/hourly | — (403) | yes |
/v1/options/gex/profile | the latest snapshot only, without strikes | any snapshot, with strikes |
/v1/options/gex/heatmap | resolution=1d, the last 30 days | 1h, 6h, 1d, full history |
Every response carries an access block:
"access": {"tier": "free", "grade": 0, "full_history": false, "history_from": "2026-09-24",
"resolutions": ["1d"], "profile_history": false, "strikes": false, "hourly": false,
"required_grade": 1, "clipped": false}
history_from— the first day the caller may see (nullfor the full history).resolutions,profile_history,strikes,hourly— what the caller's tier allows.clipped—truewhen the daily series or the heatmap was asked for days beforehistory_fromand they were cut off. These two endpoints never return 403 for that reason: they return the allowed part.- A past snapshot from
/profile(anything but the latest),/hourly, and a6h/1hheatmap return 403 on Free (see Errors).
Snapshots and time
- One snapshot of the Deribit BTC options board per hour, a few seconds after the full hour. History starts on 2026-03-16; 2026-06-08 … 2026-07-07 is missing (collection outage), and single hours are skipped when the board was incomplete. Data are refreshed every hour at about :20 UTC.
- Times are UTC, ISO 8601. Snapshot times carry microseconds when the snapshot has them
(
"2026-10-24T09:00:02.418731Z"): pass ats/times[]value back to/profile?ts=unchanged and it selects exactly that snapshot. Atswithout fractional seconds matches any snapshot within that second. - A day (the daily series,
/profile?date=, the1dheatmap) is the 00:00 UTC snapshot of that day — the first snapshot of the day if 00:00 is missing. It lies away from the 08:00 UTC daily expiry, so the row of a day does not change once it appears.
GET /v1/options/gex
Daily series, newest first.
| Parameter | Default | Description |
|---|---|---|
from_date | first allowed day | YYYY-MM-DD (UTC); earlier than the tier window → cut off, access.clipped = true |
to_date | latest day | YYYY-MM-DD (UTC, inclusive) |
limit | 100 | Number of days (1–10,000), newest first |
fields | all | Comma-separated field names (date is always kept) |
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://api.blocklens.co/v1/options/gex?from_date=2026-10-01&fields=btc_price,net_gex,zero_gamma,flow_up5,flow_dn5"
{
"success": true,
"data": [
{"date": "2026-10-23", "snapshot_ts": "2026-10-23T00:00:02Z", "btc_price": 80712.4,
"legacy_total_gex": 30112000.0, "legacy_call_gex": 41870000.0, "legacy_put_gex": -11758000.0,
"top_support_strike": 80000.0, "top_support_gex": 9120000.0,
"top_resist_strike": 76000.0, "top_resist_gex": -3410000.0, "legacy_flip_point": 80551.2,
"pc_ratio_oi": 0.62, "pc_ratio_vol_24h": 0.81, "max_pain": 82000.0, "max_pain_expiry": "24OCT26",
"hedge_snapshot_ts": "2026-10-23T00:00:02Z", "spot": 80712.4, "net_gex": 35700000.0, "zero_gamma": 59300.0,
"flow_up5": -219000000.0, "flow_dn5": 288000000.0, "flow_up10": -402000000.0, "flow_dn10": 515000000.0}
],
"count": 1,
"access": {"tier": "pro", "grade": 1, "full_history": true, "history_from": null, "resolutions": ["1h", "6h", "1d"],
"profile_history": true, "strikes": true, "hourly": true, "required_grade": 1, "clipped": false},
"message": "Options GEX and dealer hedge flow, daily (Deribit BTC)"
}
| Field | Meaning |
|---|---|
date | UTC day |
hedge_snapshot_ts, spot | The snapshot of the day used for the hedge-flow fields and its BTC index price |
net_gex | Net dealer GEX at spot, Black-Scholes, USD per 1% move — the published net GEX |
zero_gamma | The sign change of the recomputed GEX curve nearest to spot (±50%); null if none |
flow_up5, flow_dn5, flow_up10, flow_dn10 | Hedge flow in USD if the price moved +5% / −5% / +10% / −10% from spot, exact at spot × 1.05 / 0.95 / 1.10 / 0.90 |
snapshot_ts, btc_price | The snapshot of the legacy fields and its BTC price |
top_support_strike, top_support_gex | The strike with the largest positive GEX (Deribit gamma; strikes with |GEX| below $1,000 are left out) |
top_resist_strike, top_resist_gex | The strike with the most negative GEX (same rules) |
pc_ratio_oi, pc_ratio_vol_24h | Put/call ratio by open interest and by 24h volume |
max_pain, max_pain_expiry | Max pain strike of the nearest expiry, and that expiry |
legacy_total_gex, legacy_call_gex, legacy_put_gex | GEX on Deribit's published gamma (rounded to 1e-5 — biased against Black-Scholes); use net_gex |
legacy_flip_point | Sign change of strike GEX between the two strikes around the price — not a gamma flip; use zero_gamma |
The daily net_gex, zero_gamma, flow_* and top_*_strike columns are also catalog metrics (options_*, category
options) available through /v1/metrics and the MCP tool get_metric.
GET /v1/options/gex/hourly
Every hourly snapshot, newest first (Pro). Same fields as the daily series, keyed by timestamp (the snapshot time)
instead of date; the legacy and the hedge-flow values of the same snapshot share one row.
| Parameter | Default | Description |
|---|---|---|
from_date, to_date | — | YYYY-MM-DD (UTC, to_date inclusive) |
limit | 168 | Number of snapshots (1–10,000); the default is one week |
fields | all | Comma-separated field names (timestamp is always kept) |
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://api.blocklens.co/v1/options/gex/hourly?limit=24&fields=spot,net_gex,zero_gamma"
GET /v1/options/gex/profile
Hedge flow by price for one snapshot.
| Parameter | Default | Description |
|---|---|---|
ts | latest | Snapshot time (ISO 8601, UTC if no offset): the latest snapshot at or before it. Not with date |
date | — | YYYY-MM-DD (UTC): the 00:00 UTC snapshot of that day (the first of the day). Not with ts |
Free callers get the latest snapshot only: omit ts / date (a ts / date that resolves to the latest snapshot
is also accepted).
curl -H "Authorization: Bearer YOUR_API_KEY" https://api.blocklens.co/v1/options/gex/profile
{
"success": true,
"data": {
"ts": "2026-10-24T09:00:02Z", "spot": 80712.4, "step": 500.0,
"levels": [80000.0, 80500.0, 81000.0, 81500.0],
"hedge_flow": [21400000.0, 4900000.0, -6800000.0, -27300000.0],
"impact": [-21400000.0, -4900000.0, -6800000.0, -27300000.0],
"gex": [36900000.0, 35900000.0, 35200000.0, 34100000.0],
"net_gex": 35700000.0, "zero_gamma": 59300.0, "flips": [59300.0],
"flow": {"up5": -219000000.0, "dn5": 288000000.0, "up10": -402000000.0, "dn10": 515000000.0},
"max_amplify_level": null, "max_dampen_level": 74000.0, "method_version": 1,
"legacy": {"flip_point": 80551.2, "top_support_strike": 80000.0, "top_resist_strike": 76000.0,
"total_gex": 30112000.0},
"strikes": [{"strike": 80000.0, "call_gex": 6200000.0, "put_gex": 2920000.0}],
"access": {"tier": "pro", "grade": 1, "full_history": true, "history_from": null, "resolutions": ["1h", "6h", "1d"],
"profile_history": true, "strikes": true, "hourly": true, "required_grade": 1, "clipped": false}
}
}
The example is shortened: a real profile has about a hundred levels.
| Field | Meaning |
|---|---|
ts, spot | Snapshot time and BTC index price |
step, levels | Grid step ($500) and the price levels, ascending, within ±30% of spot |
hedge_flow[i] | USD dealers trade if the price moves from spot to levels[i] (> 0 buy, < 0 sell) |
impact[i] | hedge_flow[i] signed by the direction of the move (> 0 amplify, < 0 dampen) |
gex[i] | Net dealer GEX recomputed as if the price were at levels[i], USD per 1% |
net_gex | GEX at spot |
zero_gamma, flips | The sign change of the GEX curve nearest to spot and all sign changes, ascending, within ±50% of spot (null / [] if none) |
flow | Hedge flow exactly at spot × 1.05 / 0.95 / 1.10 / 0.90 (up5, dn5, up10, dn10) |
max_amplify_level, max_dampen_level | The $500 band with the largest amplifying / dampening marginal flow (null if none) |
method_version | Version of the calculation method |
legacy | Legacy values of the same snapshot (Deribit gamma): flip_point, top_support_strike, top_resist_strike, total_gex |
strikes | Net GEX by strike, calls and puts separately, summed over expiries (Pro; null on Free) |
hedge_flow is cumulative along the price path: to read a band between two levels take the difference, never the sum
of several levels.
GET /v1/options/gex/heatmap
| Parameter | Default | Description |
|---|---|---|
resolution | 1d | 1d, 6h or 1h (Pro): one snapshot per bucket — the first one (1d = the 00:00 UTC snapshot) |
from | 1d: the whole history; 6h: the last 180 days; 1h: the last 30 days | ISO date or date-time (UTC). Earlier than the tier window → cut off, access.clipped = true |
to | now | ISO date (inclusive) or date-time (exclusive) |
price_min, price_max | all levels | Trim the price range, USD (finite, ≥ 0, price_min < price_max) |
from / to snap outward to whole buckets of resolution.
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://api.blocklens.co/v1/options/gex/heatmap?resolution=6h&from=2026-09-01"
{
"success": true,
"data": {
"resolution": "1d", "times": ["2026-10-22T00:00:01Z", "2026-10-23T00:00:02Z"], "step": 500.0,
"levels": [80000.0, 80500.0, 81000.0],
"matrix": [[-18200000, null, -5100000], [-21400000, -4900000, -6800000]],
"overlays": {"price": [80310.0, 80712.4], "zero_gamma": [null, 59300.0]},
"scale": {"p98": 310000000, "max": 612000000},
"access": {"tier": "pro", "grade": 1, "full_history": true, "history_from": null, "resolutions": ["1h", "6h", "1d"],
"profile_history": true, "strikes": true, "hourly": true, "required_grade": 1, "clipped": false}
}
}
matrix[t][l]— the impact in whole USD atlevels[l]for the snapshottimes[t](> 0 amplify, < 0 dampen).nulloutside that snapshot's own ±30% range or in a hole of its grid.timesare the real snapshot times, ascending; the spacing is irregular around data gaps (no empty rows).levels— one common $500 grid covering every returned snapshot.overlays.price—spotof each row;overlays.zero_gamma— its zero gamma level (nullwhere there is none). The zero gamma level can lie outsidelevels: clip the line when drawing it.scale— the 98th percentile and the maximum of |impact|; cap a colour scale atp98.
Limits and payload size
resolution=1hcovers at most 90 days per request (400 otherwise — use6hor1dfor longer ranges).- A heatmap request may cover at most 2,000,000 cells (snapshots × levels); larger requests return 400 — use a
coarser resolution, a shorter period or
price_min/price_max. - The full hourly history is about 10 MB of uncompressed JSON. Responses are gzip-compressed on the wire. For a first
view use
1dor6h, or a short1hwindow. - Request limits per API key: Rate Limits & Tiers.
Updates and caching
- A new snapshot is computed every hour on our side and published at about :20 UTC; until then the previous hour is the latest.
- Responses are cached on the server and refreshed when new data arrive.
- The same URL returns different data for different tiers, so responses are sent with
Cache-Control: private, max-age=600andVary: Authorization— they are never stored by shared caches.
Errors
Errors come in the envelope {"success": false, "message": {…}, "timestamp": "…"}; the table shows message.
| Status | When | message |
|---|---|---|
| 400 | A bad date or time, to_date before from_date, both ts and date, unknown resolution, price_min / price_max not finite, negative or price_min >= price_max, a range that does not overlap the levels, more than 90 days at 1h, a heatmap above 2,000,000 cells | {"error": "Invalid parameter", "message": "resolution must be one of 1h, 6h, 1d"} |
| 401 | Missing or invalid API key | |
| 403 | Free: a past snapshot from /profile, /hourly, a 6h / 1h heatmap | {"error": "Insufficient tier", "message": "Profiles of past snapshots requires Pro", "required_grade": 1, "current_tier": "free", "current_grade": 0, "history_from": "2026-09-24", "upgrade_url": "https://blocklens.co/pricing"} |
| 404 | No snapshot for the requested day or time, or no data in the requested range | {"error": "Not found", "message": "no profile on 2026-06-20"} |
| 429 | Rate limit exceeded | See Rate Limits & Tiers |