Skip to main content

L4 Order Book Dataset

Updated on
Feb 25, 2026

Overviewโ€‹

The StreamL4Book stream delivers the full order book at individual order granularity โ€” every resting order with user address, order ID, size, trigger info, and timestamps. On subscribe, the stream sends a complete snapshot of all resting orders, then incremental diffs per block.

gRPC Service: OrderBookStreaming
gRPC Method: StreamL4Book
API Availability: gRPC Streaming API only Update Model: Initial full snapshot, then incremental diffs per block

How It Worksโ€‹

  1. On subscribe: The stream sends a full L4BookSnapshot containing every resting bid and ask with complete order details
  2. Per block thereafter: The stream sends L4BookDiff messages with JSON-encoded incremental updates containing order_statuses and book_diffs
  3. Apply diffs to your local copy of the snapshot to maintain current state

This is a significantly simpler way to create and maintain a local L4 order book view because the initial snapshot is built-in โ€” no REST bootstrap or race-condition stitching is needed. On reconnect, a fresh snapshot is automatically delivered.

Data Structureโ€‹

Snapshot (first message)โ€‹

The initial L4BookSnapshot contains the full order book:

{
"snapshot": {
"coin": "ETH",
"time": 1764867600518,
"height": 817863403,
"bids": [
{
"user": "0x1c1c270b573d55b68b3d14722b5d5d401511bed0",
"coin": "ETH",
"side": "B",
"limit_px": "3167.4",
"sz": "1.5785",
"oid": 258166296856,
"timestamp": 1764867590000,
"trigger_condition": "N/A",
"is_trigger": false,
"trigger_px": "0",
"is_position_tpsl": false,
"reduce_only": false,
"order_type": "Limit",
"tif": "Gtc"
}
],
"asks": [
{
"user": "0xe9acfdc9322f6f924f007016c082e6891a3c653c",
"coin": "ETH",
"side": "A",
"limit_px": "3168.0",
"sz": "2.0000",
"oid": 258166160909,
"timestamp": 1764867580000,
"trigger_condition": "N/A",
"is_trigger": false,
"trigger_px": "0",
"is_position_tpsl": false,
"reduce_only": false,
"order_type": "Limit",
"tif": "Gtc"
}
]
}
}

Diff (subsequent messages)โ€‹

After the snapshot, each block produces an L4BookDiff with JSON-encoded incremental changes:

{
"diff": {
"time": 1764867601000,
"height": 817863404,
"data": "{\"order_statuses\": [...], \"book_diffs\": [...]}"
}
}

Request Parametersโ€‹

FieldTypeRequiredDescription
coinstringYesSymbol to subscribe to โ€” perps use names (e.g., "BTC", "ETH"), spot uses @index format (e.g., "@142")

Coin Namingโ€‹

The coin parameter follows Hyperliquid's naming convention, which unambiguously distinguishes perpetuals from spot:

  • Perpetuals: Human-readable names โ€” "BTC", "ETH", "HYPE", "SOL"
  • Spot tokens: @{index} format โ€” "@1", "@107", "@142", "@166"
  • Exception: "PURR/USDC" is the only spot coin with a readable name

There is no overlap between formats. "BTC" always refers to the BTC perpetual; spot BTC is "@142". To discover @index mappings for spot tokens, query the meta or spotMeta info endpoints.

Response Fieldsโ€‹

L4BookUpdateโ€‹

Each message is a L4BookUpdate containing either a snapshot or a diff:

FieldTypeDescription
snapshotL4BookSnapshotFull order book snapshot (sent on subscribe and reconnect)
diffL4BookDiffIncremental diff (sent per block after the initial snapshot)

L4BookSnapshotโ€‹

FieldTypeDescription
coinstringSymbol (e.g., "BTC", "ETH")
timeuint64Block timestamp in milliseconds
heightuint64Block height
bidsL4Order[]All resting bid orders
asksL4Order[]All resting ask orders

L4BookDiffโ€‹

FieldTypeDescription
timeuint64Block timestamp in milliseconds
heightuint64Block height
datastringJSON-encoded object containing order_statuses and book_diffs, matching the existing node data format

L4Orderโ€‹

FieldTypeDescription
userstringEthereum address of the order owner
coinstringTrading pair identifier (e.g., "ETH", "BTC")
sidestring"A" (Ask/Sell) or "B" (Bid/Buy)
limit_pxstringLimit price as a decimal string
szstringOrder size as a decimal string
oiduint64Unique order ID
timestampuint64When the order entered the book (milliseconds)
trigger_conditionstringTrigger condition status: "N/A", "Triggered", etc.
is_triggerboolWhether the order is a trigger/stop order
trigger_pxstringTrigger price as a decimal string
is_position_tpslboolWhether the order is a position take-profit/stop-loss
reduce_onlyboolWhether the order is reduce-only
order_typestringOrder type: "Limit", "Market", etc.
tifstring (optional)Time-in-force: "Gtc" (Good til Cancelled), "Ioc" (Immediate or Cancel), "Alo" (Add Liquidity Only)
cloidstring (optional)Client order ID (custom identifier set by user)

Proto Definitionโ€‹

StreamL4Book is defined in orderbook.proto:

service OrderBookStreaming {
rpc StreamL4Book (L4BookRequest) returns (stream L4BookUpdate);
}

message L4BookRequest {
string coin = 1;
}

message L4BookUpdate {
oneof update {
L4BookSnapshot snapshot = 1;
L4BookDiff diff = 2;
}
}

message L4BookSnapshot {
string coin = 1;
uint64 time = 2;
uint64 height = 3;
repeated L4Order bids = 4;
repeated L4Order asks = 5;
}

message L4BookDiff {
uint64 time = 1;
uint64 height = 2;
string data = 3;
}

message L4Order {
string user = 1;
string coin = 2;
string side = 3;
string limit_px = 4;
string sz = 5;
uint64 oid = 6;
uint64 timestamp = 7;
string trigger_condition = 8;
bool is_trigger = 9;
string trigger_px = 10;
bool is_position_tpsl = 11;
bool reduce_only = 12;
string order_type = 13;
optional string tif = 14;
optional string cloid = 15;
}

Example Updatesโ€‹

L4 Snapshot (initial full state)
{
"snapshot": {
"coin": "ETH",
"time": 1764867600518,
"height": 817863403,
"bids": [
{
"user": "0x1c1c270b573d55b68b3d14722b5d5d401511bed0",
"coin": "ETH",
"side": "B",
"limit_px": "3167.4",
"sz": "1.5785",
"oid": 258166296856,
"timestamp": 1764867590000,
"trigger_condition": "N/A",
"is_trigger": false,
"trigger_px": "0",
"is_position_tpsl": false,
"reduce_only": false,
"order_type": "Limit",
"tif": "Gtc"
},
{
"user": "0x999a4b5f268a8fbf33736feff360d462ad248dbf",
"coin": "ETH",
"side": "B",
"limit_px": "3167.0",
"sz": "5.0000",
"oid": 258166123456,
"timestamp": 1764867585000,
"trigger_condition": "N/A",
"is_trigger": false,
"trigger_px": "0",
"is_position_tpsl": false,
"reduce_only": false,
"order_type": "Limit",
"tif": "Gtc",
"cloid": "0x20251204000000000000000000381433"
}
],
"asks": [
{
"user": "0xe9acfdc9322f6f924f007016c082e6891a3c653c",
"coin": "ETH",
"side": "A",
"limit_px": "3168.0",
"sz": "2.0000",
"oid": 258166160909,
"timestamp": 1764867580000,
"trigger_condition": "N/A",
"is_trigger": false,
"trigger_px": "0",
"is_position_tpsl": false,
"reduce_only": false,
"order_type": "Limit",
"tif": "Alo"
}
]
}
}
L4 Diff (incremental per-block update)
{
"diff": {
"time": 1764867601000,
"height": 817863404,
"data": "{\"order_statuses\":[{\"oid\":258166296856,\"status\":\"filled\"}],\"book_diffs\":[{\"coin\":\"ETH\",\"side\":\"B\",\"px\":\"3167.4\",\"sz\":\"0.0\",\"oid\":258166296856}]}"
}
}

The data field is a JSON string containing:

  • order_statuses: Order lifecycle changes (filled, canceled, etc.)
  • book_diffs: Incremental book modifications to apply to your local snapshot
Trigger/Stop-Loss Order
{
"user": "0x7a475736bf02d67bf51b00414ab766ef4da9214d",
"coin": "BTC",
"side": "A",
"limit_px": "90000.0",
"sz": "0.5000",
"oid": 258166400000,
"timestamp": 1764867595000,
"trigger_condition": "Triggered",
"is_trigger": true,
"trigger_px": "91000.0",
"is_position_tpsl": true,
"reduce_only": true,
"order_type": "Limit",
"tif": "Gtc"
}

API Usageโ€‹

gRPC Streaming
// Perp order book
const request = {
coin: 'ETH'
};

// Spot order book (@ index format)
const spotRequest = {
coin: '@142'
};

gRPC Only

StreamL4Book is only available via the gRPC Streaming API (OrderBookStreaming service). It is not available through JSON-RPC or WebSocket.

Comparison: L4 Book vs L2 Book vs Book Updates Datasetโ€‹

FeatureStreamL4BookStreamL2BookBOOK_UPDATES
GranularityIndividual ordersAggregated by price levelIndividual order-level diffs
Includes current stateYes โ€” initial snapshotYes โ€” every messageNo โ€” forward-only
Needs REST bootstrapNoNoYes
Client state managementApply diffs to snapshotNoneBuild from scratch
Per-order detailsUser, oid, triggers, timestamps, tifTotal size and count onlyUser, oid, size
BandwidthHigher (full order details)Medium (capped by n_levels)Low (diffs only)
Best forHFT, quant desks, MEVMost customersCustomers who only need book updates

Important Notesโ€‹


  • Snapshot on subscribe and reconnect: The stream always starts with a full snapshot, so reconnects are handled automatically
  • DATA_LOSS reconnection: The stream may emit gRPC DATA_LOSS status errors during transient issues. Implement auto-reconnect logic on DATA_LOSS โ€” a fresh snapshot is delivered on each new connection, so no manual state recovery is needed.
  • Apply diffs to local state: After the initial snapshot, apply each L4BookDiff to maintain the current book. The JSON format matches the existing node data format used by BOOK_UPDATES.
  • zstd compression strongly recommended: L4 messages can be large due to full order details. Enable zstd compression on your gRPC channel to significantly reduce bandwidth.

  • StreamL2Book - Aggregated price levels โ€” simpler, lower bandwidth, no client-side state management
  • Book Updates - Forward-only incremental diffs via StreamData (legacy approach)
  • Orders - Order lifecycle events (open, filled, canceled, etc.)
  • Trades - Executed trade data with maker/taker information
Share this doc