GEX levels
Composable GEX key levels. All-expiry HVL/walls plus 0DTE-specific levels in a single call.
curl --request GET \
--url https://api.example.com/gex/levels \
--header 'X-API-Key: <api-key>'import requests
url = "https://api.example.com/gex/levels"
headers = {"X-API-Key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-API-Key': '<api-key>'}};
fetch('https://api.example.com/gex/levels', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/gex/levels",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/gex/levels"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-API-Key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.example.com/gex/levels")
.header("X-API-Key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/gex/levels")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-API-Key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"data": {
"all_expiry": {
"hvl": 123,
"call_resistance": 123,
"call_wall_2": 123,
"call_wall_3": 123,
"put_support": 123,
"put_wall_2": 123,
"put_wall_3": 123
},
"odte": {
"hvl": 123,
"call_resistance": 123,
"put_support": 123
},
"positioning": "flow",
"ranked": {
"all_expiry_top_10": [],
"odte_top_10": []
},
"max_pain": {
"strike": 123,
"value": 123
},
"expected_move": {
"upper_1sd": 123,
"lower_1sd": 123,
"upper_2sd": 123,
"lower_2sd": 123
},
"gamma_flip_zones": [
{}
],
"spot": {
"spot_price": 123,
"perps_price": 123
},
"candles": [
{
"datetime": "<string>",
"open": 123,
"high": 123,
"low": 123,
"close": 123,
"volume": 123
}
]
},
"meta": {
"version": "2.0",
"timestamp": "<string>",
"request_id": "<string>",
"symbol": "<string>",
"spot_price": 123,
"computed_at": "<string>",
"freshness_seconds": 123,
"source": [
"<string>"
],
"exchanges_filtered": [
"<string>"
],
"rate_limit": {},
"extra": {}
},
"success": true
}{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid API key"
},
"meta": {
"version": "2.0",
"timestamp": "2026-04-29T12:00:00Z"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": {}
},
"meta": {
"version": "2.0",
"timestamp": "<string>",
"request_id": "<string>",
"symbol": "<string>",
"spot_price": 123,
"computed_at": "<string>",
"freshness_seconds": 123,
"source": [
"<string>"
],
"exchanges_filtered": [
"<string>"
],
"rate_limit": {},
"extra": {}
},
"success": false
}{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid request parameters",
"details": {
"errors": []
}
},
"meta": {
"version": "2.0",
"timestamp": "2026-04-29T12:00:00Z"
}
}{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Try again later."
},
"meta": {
"version": "2.0",
"timestamp": "2026-04-29T12:00:00Z"
}
}?include= to opt into max-pain, expected move, ranked top-10, gamma
flip zones, spot, candles.
Default positioning=flow. Pass ?positioning=std for textbook
call/put OI signing. See Positioning.
See also
What is GEX?
Flow vs std
Strike profile
Multi-symbol bundle
Authorizations
Your BackQuant API key (same key as v1)
Headers
Query Parameters
Trading symbol: BTCUSDT, ETHUSDT, SOLUSDT, or HYPEUSDT.
BTCUSDT, ETHUSDT, SOLUSDT, HYPEUSDT Comma-separated venue filter, e.g. deribit,bybit. Restricts the response to those venues' contribution, recomputed from the per-venue breakdown - it is a re-aggregation, not a post-hoc scaling. Unknown names are ignored; an all-invalid filter returns every venue rather than nothing. Venues: deribit, bybit, okx, binance, derive, thalex, delta_india, delta, bullish, paradex. A venue with no contracts on the surface contributes zero - use GET /v2/status to tell that apart from a venue that is switched off.
Comma-separated optional sections: candles,expected_move,max_pain,ranked,spot,zones
Dealer positioning model. flow (default) is BackQuant's measured dealer model, available for BTC/ETH; it falls back to std when it cannot be produced for a symbol. std is the textbook convention (call:+OI / put:-OI). The response reports which model actually ran in meta.extra.positioning.
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
Show child attributes
Show child attributes
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.
Show child attributes
Show child attributes
curl --request GET \
--url https://api.example.com/gex/levels \
--header 'X-API-Key: <api-key>'import requests
url = "https://api.example.com/gex/levels"
headers = {"X-API-Key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-API-Key': '<api-key>'}};
fetch('https://api.example.com/gex/levels', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/gex/levels",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/gex/levels"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-API-Key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.example.com/gex/levels")
.header("X-API-Key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/gex/levels")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-API-Key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"data": {
"all_expiry": {
"hvl": 123,
"call_resistance": 123,
"call_wall_2": 123,
"call_wall_3": 123,
"put_support": 123,
"put_wall_2": 123,
"put_wall_3": 123
},
"odte": {
"hvl": 123,
"call_resistance": 123,
"put_support": 123
},
"positioning": "flow",
"ranked": {
"all_expiry_top_10": [],
"odte_top_10": []
},
"max_pain": {
"strike": 123,
"value": 123
},
"expected_move": {
"upper_1sd": 123,
"lower_1sd": 123,
"upper_2sd": 123,
"lower_2sd": 123
},
"gamma_flip_zones": [
{}
],
"spot": {
"spot_price": 123,
"perps_price": 123
},
"candles": [
{
"datetime": "<string>",
"open": 123,
"high": 123,
"low": 123,
"close": 123,
"volume": 123
}
]
},
"meta": {
"version": "2.0",
"timestamp": "<string>",
"request_id": "<string>",
"symbol": "<string>",
"spot_price": 123,
"computed_at": "<string>",
"freshness_seconds": 123,
"source": [
"<string>"
],
"exchanges_filtered": [
"<string>"
],
"rate_limit": {},
"extra": {}
},
"success": true
}{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid API key"
},
"meta": {
"version": "2.0",
"timestamp": "2026-04-29T12:00:00Z"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": {}
},
"meta": {
"version": "2.0",
"timestamp": "<string>",
"request_id": "<string>",
"symbol": "<string>",
"spot_price": 123,
"computed_at": "<string>",
"freshness_seconds": 123,
"source": [
"<string>"
],
"exchanges_filtered": [
"<string>"
],
"rate_limit": {},
"extra": {}
},
"success": false
}{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid request parameters",
"details": {
"errors": []
}
},
"meta": {
"version": "2.0",
"timestamp": "2026-04-29T12:00:00Z"
}
}{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Try again later."
},
"meta": {
"version": "2.0",
"timestamp": "2026-04-29T12:00:00Z"
}
}