> ## Documentation Index
> Fetch the complete documentation index at: https://goldrush.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Build with the L2 Order Book

> The Hyperliquid L2 order book over WebSocket - build top-of-book quote feeds, depth-weighted mid prices, slippage and market-impact estimators, and liquidity heatmaps from self-contained L2 snapshots, no diff replay or snapshot bootstrap required.

The `l2Book` channel on `wss://hypercore.goldrushdata.com/ws?key=<GOLDRUSH_API_KEY>` is wire-equal to the public Hyperliquid feed but with `coin` made optional and the per-IP subscription cap removed. This recipe shows how to turn that stream into common trading and analytics building blocks. For the raw subscription shape see the [`l2Book` reference](https://goldrush.dev/docs/api-reference/hyperliquid-websocket/l2-book); for the connection model see the [WebSocket API overview](https://goldrush.dev/docs/goldrush-hyperliquid/websocket-api/overview.md).

## What you get

* **Complete snapshots, not diffs.** Every `l2Book` message contains the current `time`, `coin`, and a full `[bids, asks]` tuple in best-first order, with `px` / `sz` / `n` per level. Consume each message in isolation - no sequence numbers to track, no diff replay buffer, no REST snapshot to bootstrap.
* **Self-healing on packet loss.** Drop a message, reconnect mid-session, or restart your process - the next message arrives with the full book state, so your in-memory view is correct on the very next tick.
* **Upstream-compatible aggregation knobs.** `nSigFigs` accepts `2`, `3`, `4`, `5`, or `null` (full precision). `mantissa` accepts `1`, `2`, or `5`, and is only valid when `nSigFigs` is `5`.
* **Wildcard coverage.** Omit `coin` to stream every asset's book over a single subscription, instead of fanning out one subscription per asset. The wildcard defaults to perps only (`marketTypes: ["perp"]`); pass `["spot"]`, `["outcome"]`, a mix, or `["*"]` to opt into spot, outcome, and future market types.

## Pair address format

Hyperliquid markets use a **deployer-prefix naming scheme**. The exact string differs by surface, so pass the value each API expects - matching is case- and format-sensitive.

| Where it's used | Format | Examples |
| - | - | - |
| WebSocket `coin` (`l2Book`, `l2BookDiff`, `l4Book`) - canonical perps | `<symbol>` | `BTC`, `ETH`, `HYPE` |
| WebSocket `coin` - HIP-3 builder markets | `<deployer>:<symbol>` | `xyz:GOLD`, `flx:OIL` |
| Streaming `pair_addresses` (`ohlcvCandlesForPair`) | `<deployer>:<symbol>-<quote>`, or `<symbol>-<quote>` for canonical pairs | `xyz:GOLD-USDC`, `flx:OIL-USDH`, `BTC-USDC` |
| Streaming `token_addresses` (`ohlcvCandlesForToken`) | `<symbol>` (no prefix) | `GOLD`, `OIL`, `BTC` |

* `deployer` - wallet address of the HIP-3 builder that deployed the market. Omitted for canonical Hyperliquid markets.
* `symbol` - market ticker (e.g. `GOLD`, `OIL`).
* `quote` - the margin / quote currency, usually `USDC` (some HIP-3 markets use `USDH`).

> [!NOTE]
>
> HIP-4 outcome markets use a separate `#<encoding>` scheme (e.g. `#1230`), not the deployer-prefix - see [HIP-4 Markets](https://goldrush.dev/docs/goldrush-hyperliquid/streaming/hip4-markets.md).

**Discovering markets:** a dedicated market-list endpoint (the `perpDexs` Info API type) is on the roadmap. Until it ships, call [`metaAndAssetCtxs`](https://goldrush.dev/docs/api-reference/hyperliquid-info/meta-and-asset-ctxs) - the `name` field on each `universe` entry is the canonical pair address.

## Subscribe and hold book state

The pattern below keeps a `Map<coin, snapshot>` in memory. Each incoming message replaces the entry for its `coin`, so the map is always current and never needs reconciliation.

```typescript TypeScript theme={null}
import WebSocket from "ws";

type Level = { px: string; sz: string; n: number };
type Snapshot = { time: number; bids: Level[]; asks: Level[] };

const books = new Map<string, Snapshot>();

const ws = new WebSocket(
  `wss://hypercore.goldrushdata.com/ws?key=${process.env.GOLDRUSH_API_KEY}`,
);

ws.on("open", () => {
  // Omit `coin` to stream every asset on one subscription.
  ws.send(JSON.stringify({
    method: "subscribe",
    subscription: { type: "l2Book", coin: "BTC" },
  }));
});

ws.on("message", (raw) => {
  const msg = JSON.parse(raw.toString());
  if (msg.channel !== "l2Book") return;

  const { coin, time, levels: [bids, asks] } = msg.data;
  books.set(coin, { time, bids, asks });

  console.log(coin, time, "bid:", bids[0]?.px, "ask:", asks[0]?.px);
});
```

```python Python theme={null}
import asyncio, json, os
import websockets

books: dict[str, dict] = {}

async def main():
    uri = f"wss://hypercore.goldrushdata.com/ws?key={os.environ['GOLDRUSH_API_KEY']}"
    async with websockets.connect(uri) as ws:
        await ws.send(json.dumps({
            "method": "subscribe",
            "subscription": {"type": "l2Book", "coin": "BTC"},
        }))
        async for raw in ws:
            msg = json.loads(raw)
            if msg.get("channel") != "l2Book":
                continue
            data = msg["data"]
            coin, time = data["coin"], data["time"]
            bids, asks = data["levels"]
            books[coin] = {"time": time, "bids": bids, "asks": asks}
            print(coin, time, "bid:", bids[0]["px"], "ask:", asks[0]["px"])

asyncio.run(main())
```

## Patterns

### Top-of-book tracker

Read `bids[0]` and `asks[0]` directly from each message. The spread is `Number(asks[0].px) - Number(bids[0].px)`. No state required - every message is self-contained, so a single-line transformation gives you a live ticker.

### Depth-weighted mid quote

Sum `px * sz` across the first `K` levels on each side, then average. This produces a fair-value mid that's robust to thin top-of-book liquidity, and is useful as a hedging or pricing reference.

```typescript TypeScript theme={null}
function depthWeightedMid(snap: Snapshot, k = 5): number {
  const side = (levels: Level[]) => {
    let num = 0, den = 0;
    for (const { px, sz } of levels.slice(0, k)) {
      const p = Number(px), s = Number(sz);
      num += p * s;
      den += s;
    }
    return den > 0 ? num / den : NaN;
  };
  return (side(snap.bids) + side(snap.asks)) / 2;
}
```

### Slippage / impact estimator

Walk levels on the relevant side until cumulative `sz` covers the requested notional. Return the size-weighted average fill price - the difference vs the top-of-book is your expected slippage.

```typescript TypeScript theme={null}
function estimateFill(levels: Level[], targetSize: number): number {
  let remaining = targetSize, notional = 0;
  for (const { px, sz } of levels) {
    const take = Math.min(remaining, Number(sz));
    notional += take * Number(px);
    remaining -= take;
    if (remaining <= 0) break;
  }
  return remaining > 0 ? NaN : notional / targetSize;
}

// Buying 10 BTC against current asks:
const avgFill = estimateFill(books.get("BTC")!.asks, 10);
```

### Liquidity heatmap

On each message, append `[time, coin, side, px, sz]` rows to your time-series store (Clickhouse, TimescaleDB, Parquet). Because every message is a complete snapshot of the top levels, the heatmap rebuilds correctly from any contiguous slice of history - you don't need a separate "initial book" record to seed the visualisation.

## Handling reconnects

Reconnect logic is a one-liner: open a new socket and resend the same `subscribe` payload. The first message after subscribe is a full book snapshot, so your `books` map is correct on the next tick - there's nothing to replay, nothing to buffer, and no sequence numbers to reconcile against a separately-fetched REST snapshot.

```typescript TypeScript theme={null}
function connect() {
  const ws = new WebSocket(
    `wss://hypercore.goldrushdata.com/ws?key=${process.env.GOLDRUSH_API_KEY}`,
  );
  ws.on("open", () => ws.send(JSON.stringify({
    method: "subscribe",
    subscription: { type: "l2Book", coin: "BTC" },
  })));
  ws.on("close", () => setTimeout(connect, 1000));
  return ws;
}
```

## Related

* [`l2Book` API reference](https://goldrush.dev/docs/api-reference/hyperliquid-websocket/l2-book) - full subscription and message schema.
* [WebSocket API overview](https://goldrush.dev/docs/goldrush-hyperliquid/websocket-api/overview.md) - endpoint URL, auth, and limits.
* [`clearinghouseState`](https://goldrush.dev/docs/api-reference/hyperliquid-info/clearinghouse-state) - pair the live book with per-account position and margin state.
* [HIP-3 markets OHLCV recipe](https://goldrush.dev/docs/goldrush-hyperliquid/streaming/hip3-markets.md) - candles instead of raw book state.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.