Skip to main content
GET
Filtered options chain
Filtered chain with two-layer projection (?fields= top-level, ?include= per-contract) and a payload cap (?max_contracts). Cached 30s per filter combination.

Where each number comes from

A chain row mixes cross-venue and single-venue fields on purpose. Reading a single-venue field as a market-wide total is the most common way to misread this endpoint. The activity fields cover a rolling 24 hours and arrive under ?include=volume. volume is contracts, notional_volume is premium paid in USD, and trade_count is prints. All three mean the same thing on every symbol; only the venue scope differs. Under ?as_of=, these three are recomputed from the tape for the window ending at that snapshot (meta.extra.activity_rebuilt confirms it). bid and ask are not recoverable that way and stay 0 on chains persisted before 2026-09-01 - meta.extra.quotes_note says so.
On the activity fields, null is not 0. A 0 means measured and nothing traded; a null means not measured. SOL reports trade_count: null, because no venue publishes a per-contract trade count for it, and BTC/ETH read null in the brief window where the cross-venue measurement is unavailable.
Full reasoning, including why SOL and HYPE are not blended, is in Venues.

See also

Which fields are cross-venue

Consolidated best bid/offer

Greeks beyond delta

Refresh cadences

Authorizations

X-API-Key
string
header
required

Your BackQuant API key (same key as v1)

Headers

X-API-Key
string | null

Query Parameters

symbol
enum<string>
default:BTCUSDT

Trading symbol: BTCUSDT, ETHUSDT, SOLUSDT, or HYPEUSDT.

Available options:
BTCUSDT,
ETHUSDT,
SOLUSDT,
HYPEUSDT
expiries
string | null

CSV of expiry tokens (e.g. 28MAR25,25APR25)

dte_min
integer | null

Inclusive lower bound on days-to-expiry.

Required range: 0 <= x <= 720
dte_max
integer | null

Inclusive upper bound on days-to-expiry.

Required range: 0 <= x <= 720
oi_min
number | null

Minimum open interest per contract.

Required range: x >= 0
oi_max
number | null

Maximum open interest per contract.

Required range: x >= 0
delta_min
number | null

Minimum |delta| (0..1).

Required range: 0 <= x <= 1
delta_max
number | null

Maximum |delta| (0..1).

Required range: 0 <= x <= 1
strike_min
number | null

Minimum strike price (absolute).

Required range: x >= 0
strike_max
number | null

Maximum strike price (absolute).

Required range: x >= 0
moneyness_min
number | null

Strike/spot lower bound (e.g. 0.9 for ATM-10%).

Required range: 0 <= x <= 10
moneyness_max
number | null

Strike/spot upper bound (e.g. 1.1 for ATM+10%).

Required range: 0 <= x <= 10
option_type
enum<string>
default:both

Filter to call, put, or both contract types.

Available options:
call,
put,
both
max_contracts
integer
default:2000

Cap on the number of contracts returned (default 2000, hard ceiling 5000). When more contracts match the filters, the response is truncated to the closest-to-spot subset and truncated=true is set with total_matching_count so the client knows to narrow the filter.

Required range: 1 <= x <= 5000
fields
string | null

Top-level projection: aggregates,available_expiries,contracts

include
string | null

Per-contract projection: bid_ask,gex,greeks,iv,oi,volume. Default is all sections.

as_of
string | null

ISO-8601 instant to answer as of, e.g. 2026-08-20T14:30:00Z. Omit for the current value. Resolves to the nearest chain snapshot AT OR BEFORE the requested time (never after, which would be look-ahead bias); the snapshot actually used and the lag are reported in meta.extra.as_of. Under positioning=flow the dealer flow map is rebuilt from the tape as it stood at that instant, so a given timestamp always returns the same numbers. Bounded by your plan's history window.

Response

Successful Response

data
ChainData · object
required
meta
V2Meta · object
required

The meta block returned alongside every v2 response.

Every field after version/timestamp is optional because endpoints attach different combinations - e.g. /v2/status skips symbol, the chain endpoint sets extra.filter_hash, etc. Listing them here means SDKs get a typed accessor for each instead of a generic meta: dict.

success
boolean
default:true