# L4 Order Book Dataset

## 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`](/content/docs/hyperliquid/grpc-api/StreamL4Book/index.html)  
**API Availability:** gRPC Streaming API only  
**Update Model:** Full snapshot on subscribe, then incremental diffs per block, with authoritative replacement snapshots possible at any time

## 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 a JSON-encoded `data` string containing `order_statuses` (full order status objects matching the Orders stream) and `book_diffs` (incremental changes using `raw_book_diff` format matching the Book Updates stream)  
3. **Apply diffs** to your local copy of the snapshot to maintain current state  
4. **Replacement snapshots:** The stream can send another `L4BookSnapshot` after the initial one, for example when an ALO priority fee insertion changes queue order or when stream state is rebuilt. Treat every snapshot as authoritative: discard both sides of the local book, rebuild from `bids` and `asks` in the order emitted, and continue applying later diffs from that snapshot's `height`

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 and replacements)
The initial `L4BookSnapshot` contains the full order book. Later snapshots use the same shape and fully replace the local book:
```json
{
  "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:
```json
{
  "diff": {
    "time": 1764867601000,
    "height": 817863404,
    "data": "{\"order_statuses\": [...], \"book_diffs\": [...]}"
  }
}
```

## Request Parameters
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| coin | string | Yes | Symbol 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:
- **Perpetuals**: Human-readable names — "BTC", "ETH"
- **Spot tokens**: `@{index}` format — "@1", "@107"
- **Outcome markets (HIP-4)**: `#N` format

## Response Fields
### L4BookUpdate
Each message is a `L4BookUpdate` containing either a snapshot or a diff:
| Field | Type | Description |
| --- | --- | --- |
| snapshot | L4BookSnapshot | Full order book snapshot |
| diff | L4BookDiff | Incremental diff |

### 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 |

### 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 |
| 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", "Ioc", "Alo" |
| cloid | string (optional) | Client order ID |

## Proto Definition
`StreamL4Book` is defined in `orderbook.proto`:
```protobuf
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)**
```json
{
  "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"
      }
    ]
  }
}
```
**L4 Diff (incremental per-block update)**
```json
{
  "diff": {
    "time": 1764867601000,
    "height": 817863404,
    "data": "{\"order_statuses\":[...],\"book_diffs\":[...]}"
  }
}
```

The `data` field is a JSON-encoded string. When parsed, it contains:

**`order_statuses`** — Full order status events, one per order changed this block.

**`book_diffs`** — Incremental order book changes.

## API Usage
**gRPC Streaming**
```javascript
// Perp order book
const request = {
  coin: 'ETH'
};
// Spot order book (@ index format)
const spotRequest = {
  coin: '@142'
};
```

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

## Important Notes
- **Treat every snapshot as authoritative**: Snapshots arrive on subscribe and reconnect, and a replacement snapshot can also arrive after normal incremental updates. On active markets, replacement snapshots can arrive multiple times per minute.
- **Queue priority arrives via snapshots**: The L4 diffs do not carry queue-order changes through replacement snapshots whose `bids` and `asks` are emitted in canonical queue order.
- **Allow large messages**: Replacement snapshots can be much larger than an incremental diff.
- **`DATA_LOSS` reconnection**: Implement auto-reconnect logic on `DATA_LOSS` — a fresh snapshot is delivered on each new connection.
- **Apply diffs to local state**: Between snapshots, apply each `L4BookDiff` to maintain the current book.
- **Typed alternative available**: If you only need per-order add/update/remove movement, [StreamL4BookUpdates](/content/docs/hyperliquid/datasets/l4-book-updates/index.html) delivers the same order-level changes as typed protobuf diffs.
- **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.

## Related Streams
- **[StreamL2Book](/content/docs/hyperliquid/datasets/l2-book/index.html)** - Aggregated price levels
- **[StreamL4BookUpdates](/content/docs/hyperliquid/datasets/l4-book-updates/index.html)** - Typed per-order add/update/remove diffs
- **[Book Updates](/content/docs/hyperliquid/datasets/book-updates/index.html)** - Forward-only incremental diffs 
- **[Orders](/content/docs/hyperliquid/datasets/orders/index.html)** - Order lifecycle events (open, filled, canceled, etc.)
- **[Trades](/content/docs/hyperliquid/datasets/trades/index.html)** - Executed trade data with maker/taker information
