Orderbook Channel

Real-time orderbook updates for perpetual markets.

Channel: orderbook
Authentication: Not required

Subscribe

{
  "method": "subscribe",
  "params": {
    "channel": "orderbook",
    "market_ids": [1, 2]
  }
}
ParameterTypeRequiredDescription
market_idsnumber[]NoFilter by market IDs. Empty = all markets
🚧

The snapshot can arrive before the subscribe acknowledgement

One snapshot is sent per market, and it is written to the socket before the "type": "subscribed" reply. A client that ignores messages until it sees the ack will drop its own snapshot and start with an incomplete book.

Message Format

Snapshot

Sent immediately after subscribing — one message per market, containing the full book.

{
  "method": "snapshot",
  "channel": "orderbook",
  "type": "snapshot",
  "market_id": "1",
  "data": {
    "market_id": 1,
    "bids": [
      { "price": "63218.5", "quantity": "1.317053", "order_count": 1 },
      { "price": "63215.2", "quantity": "0.004744", "order_count": 1 }
    ],
    "asks": [
      { "price": "63220", "quantity": "1.317053", "order_count": 1 },
      { "price": "63222.6", "quantity": "0.004744", "order_count": 1 }
    ]
  },
  "level_count": 4,
  "block_number": 19328296,
  "log_index": 0,
  "worker_timestamp": "1786934053513837410"
}

Update

Sent when the book changes. Contains only the modified price levels.

{
  "channel": "orderbook",
  "type": "update",
  "market_id": "1",
  "data": {
    "market_id": 1,
    "bids": [
      { "price": "62913.8", "quantity": "6.006075", "order_count": 1 }
    ],
    "asks": [
      { "price": "63257.5", "quantity": "0.750763", "order_count": 1 },
      { "price": "63257.6", "quantity": "0", "order_count": 0 }
    ]
  },
  "checksum": 3608920187,
  "block_number": 19328296,
  "log_index": 614,
  "tx_hash": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
  "worker_timestamp": "1786934053513837410"
}

Level Deletion

A removed price level is sent with quantity: "0" and order_count: 0 — as in the 63257.6 ask above. Delete that level from your local book rather than storing a zero.

Data Fields

Snapshot Message Fields

FieldTypeDescription
methodstringAlways "snapshot"
channelstringAlways "orderbook"
typestringAlways "snapshot"
market_idstringMarket ID
dataobjectContains market_id, bids, and asks arrays
level_countnumberTotal number of price levels in this snapshot
block_numbernumberBlock the book state is taken at
log_indexnumberLog index within that block
worker_timestampstringServer time in nanoseconds

Update Message Fields

FieldTypeDescription
channelstringAlways "orderbook"
typestringAlways "update"
market_idstringMarket ID
dataobjectContains market_id, bids, and asks arrays
checksumnumberCRC32 checksum of the full book after this update
block_numbernumberBlockchain block number
log_indexnumberLog index within the block
tx_hashstringTransaction hash
worker_timestampstringServer time in nanoseconds

There is no timestamp or block_timestamp field on this channel.

Level Object

Identical in snapshots and updates:

FieldTypeDescription
pricestringPrice level, decimal (e.g. "63250.4")
quantitystringTotal quantity at this price, decimal. "0" indicates deletion
order_countnumberNumber of orders resting at this price level

Levels do not carry their own block_number / log_index; the block metadata on the message applies to every level in it.

Ordering

  • Bids: Sorted descending by price (highest first)
  • Asks: Sorted ascending by price (lowest first)

CRC32 Checksum

The checksum lets you verify that your local book still matches the server's. It is computed over the entire book after the update, not over the levels in the message.

❗️

The checksum is computed on wei-scaled integers

The wire format is decimal, but the checksum input is not: every price and quantity is multiplied by 1018 and rendered as an integer with no decimal point before hashing. Feeding the decimal strings straight in never matches.

Algorithm

  1. Sort bids descending by price, asks ascending by price
  2. Interleave: bids[0], asks[0], bids[1], asks[1], … — if one side is shorter, its slots are simply skipped
  3. For each level emit price then quantity, each converted to wei (18 decimals, integer)
  4. Join every value with : and compute CRC32-IEEE over the ASCII bytes

Python Implementation

import binascii
from decimal import Decimal

WEI = Decimal(10) ** 18

def to_wei(value: str) -> str:
    return str(int(Decimal(value) * WEI))

def compute_checksum(bids, asks):
    """bids/asks: full local book, already sorted, with decimal 'price'/'quantity' strings."""
    parts = []
    for i in range(max(len(bids), len(asks))):
        if i < len(bids):
            parts.append(to_wei(bids[i]["price"]))
            parts.append(to_wei(bids[i]["quantity"]))
        if i < len(asks):
            parts.append(to_wei(asks[i]["price"]))
            parts.append(to_wei(asks[i]["quantity"]))

    return binascii.crc32(":".join(parts).encode()) & 0xffffffff

Checksum Mismatch

If your computed checksum doesn't match the received one:

  1. Your local book has drifted — do not keep trading on it
  2. Unsubscribe and resubscribe to get a fresh snapshot
  3. Check that you delete quantity: "0" levels instead of keeping them

Examples

Subscribe to all markets

{
  "method": "subscribe",
  "params": {
    "channel": "orderbook"
  }
}

Subscribe to specific markets

{
  "method": "subscribe",
  "params": {
    "channel": "orderbook",
    "market_ids": [1, 2]
  }
}

Unsubscribe

{
  "method": "unsubscribe",
  "params": {
    "channel": "orderbook"
  }
}

Testing with wscat

# Connect (mainnet)
wscat -c wss://ws.rise.trade/ws

# Subscribe to market 1 (BTC/USDC)
{"method":"subscribe","params":{"channel":"orderbook","market_ids":[1]}}

# Unsubscribe
{"method":"unsubscribe","params":{"channel":"orderbook"}}

Notes

Price Format

Prices and quantities are decimal strings, not wei. Only the oracle channel quotes in wei.

Re-subscribing

Re-subscribing to orderbook merges the new market IDs into your existing subscription and sends a snapshot only for the markets you did not already have. Re-subscribing to a market you already follow returns no new snapshot.

Public Channel

This channel does not require authentication.