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

Field
Type
Required
Description
coin
string
Yes
Symbol to subscribe to (e.g., "BTC", "ETH")

Response Fields

L4BookUpdate

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

Field
Type
Description
snapshot
L4BookSnapshot
Full order book snapshot (sent on subscribe and reconnect)
diff
L4BookDiff
Incremental diff (sent per block after the initial snapshot)

L4BookSnapshot

Field
Type
Description
coin
string
Symbol (e.g., "BTC", "ETH")
time
uint64
Block timestamp in milliseconds
height
uint64
Block height
bids
L4Order[]
All resting bid orders
asks
L4Order[]
All resting ask orders

L4BookDiff

Field
Type
Description
time
uint64
Block timestamp in milliseconds
height
uint64
Block height
data
string
JSON-encoded object containing order_statuses and book_diffs, matching the existing node data format

L4Order

Field
Type
Description
user
string
Ethereum address of the order owner
coin
string
Trading pair identifier (e.g., "ETH", "BTC")
side
string
"A" (Ask/Sell) or "B" (Bid/Buy)
limit_px
string
Limit price as a decimal string
sz
string
Order size as a decimal string
oid
uint64
Unique order ID
timestamp
uint64
When the order entered the book (milliseconds)
trigger_condition
string
Trigger condition status: "N/A", "Triggered", etc.
is_trigger
bool
Whether the order is a trigger/stop order
trigger_px
string
Trigger price as a decimal string
is_position_tpsl
bool
Whether the order is a position take-profit/stop-loss
reduce_only
bool
Whether the order is reduce-only
order_type
string
Order type: "Limit", "Market", etc.
tif
string (optional)
Time-in-force: "Gtc" (Good til Cancelled), "Ioc" (Immediate or Cancel), "Alo" (Add Liquidity Only)
cloid
string (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
// StreamL4Book — OrderBookStreaming service
const request = {
coin: 'ETH'
};

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

Feature
Granularity
StreamL4Book
Individual orders
StreamL2Book
Aggregated by price level
BOOK_UPDATES
Individual order-level diffs
Feature
Includes current state
StreamL4Book
Yes — initial snapshot
StreamL2Book
Yes — every message
BOOK_UPDATES
No — forward-only
Feature
Needs REST bootstrap
StreamL4Book
No
StreamL2Book
No
BOOK_UPDATES
Yes
Feature
Client state management
StreamL4Book
Apply diffs to snapshot
StreamL2Book
None
BOOK_UPDATES
Build from scratch
Feature
Per-order details
StreamL4Book
User, oid, triggers, timestamps, tif
StreamL2Book
Total size and count only
BOOK_UPDATES
User, oid, size
Feature
Bandwidth
StreamL4Book
Higher (full order details)
StreamL2Book
Medium (capped by n_levels)
BOOK_UPDATES
Low (diffs only)
Feature
Best for
StreamL4Book
HFT, quant desks, MEV
StreamL2Book
Most customers
BOOK_UPDATES
Customers 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