Orderbook Channel

The orderbook channel provides data about the top 100 levels of the orderbook on either side; the top 100 bids and asks.

Initial snapshot

Upon subscribing, you will receive one snapshot of the orderbook. This message is of type partial with a data field containing:

  • action: partial
  • bids
  • asks
  • checksum: see below
  • time: Timestamp in UNIX time; format seconds.microsends; matching engine time

The bids and asks are formatted like so: [[best price, size at price], [next next best price, size at price], ...]

Example snapshot (partial) message (bids and asks truncated for readability):

{
    "channel": "orderbook",
    "market": "BTC-PERP",
    "type": "partial",
    "data": {
        "time": 1657922998.855916,
        "checksum": 3867334211,
        "bids": [
            [
                20926.0,
                15.3968
            ],
            [
                20925.0,
                1.8693
            ]
        ],
        "asks": [
            [
                20927.0,
                3.6708
            ],
            [
                20928.0,
                1.4143
            ]
        ],
        "action": "partial"
    }
}

Updates

After receiving your snapshot, you will be streamed messages of type update that have data fields containing:

  • action: update
  • bids
  • asks
  • checksum: see below
  • time: Timestamp in UNIX time; format seconds.microsends
    The bids and asks fields contain updates to the orderbook.

If the bid size at price 5220.5 changed to 20.2, the bids field would be: [[5220.5, 20.2]]
If all asks at price 5223.5 got canceled, the asks field would contain: [[5233.5, 0]] In this case, the asks row at this price should be removed entirely from the orderbook.

Example update message (bids and asks truncated for readability):

{
    "channel": "orderbook",
    "market": "BTC-PERP",
    "type": "update",
    "data": {
        "time": 1657922998.8830926,
        "checksum": 3019748526,
        "bids": [
            [
                20920.0,
                7.4663
            ],
            [
                20885.0,
                28.7092
            ]
        ],
        "asks": [
            [
                20993.0,
                36.1774
            ]
        ],
        "action": "update"
    }
}

Checksum

Every orderbook message contains an unsigned 32-bit integer checksum of the orderbook. You can run the same checksum on your client orderbook state and compare it to checksum field. If they are the same, your client's state is in sync with the current state of the orderbook. If not, you have likely lost or mishandled a packet and should re-subscribe to receive the initial snapshot again. The checksum operates on a string that represents the first 100 orders on the orderbook on either side. The format of the string is:

<best_bid_price>:<best_bid_size>:<best_ask_price>:<best_ask_size>:<second_best_bid_price>:<second_best_bid_size>:...

For example, if the orderbook was comprised of the following two bids and asks:

bids: [[5000.5, 10], [4995.0, 5]]
asks: [[5001.0, 6], [5002.0, 7]]

then the checksum string would be: '5000.5:10:5001.0:6:4995.0:5:5002.0:7'

If there are more orders on one side of the book than the other, then simply omit the information about orders that don't exist:

bids: [[5000.5, 10.0], [4995.0, 5.0]]
asks: [[5001.0, 7.5e-5]]

would produce the checksum string: '5000.5:10.0:5001.0:7.5e-05:4995.0:5.0'

Rules for handling float formatting for the checksum:

  • Values smaller than 1e-04 (0.0001) should be formatted using scientific notation, and should contain a zero before the exponent. For example, a message containing 7.5e-5 or 0.000075 should be formatted like so for computing the checksum: '7.5e-05'.
  • Values larger than 1e-04 should always contain a decimal and at least one digit after the decimal. For instance, a value of 1.0 must be formatted as '1.0', not '1'.

The final checksum is the crc32 hashed value of this string.

Here's an example of calculating the checksum in Python:

checksum = data['checksum']
orderbook = current_orderbook_dictionary
checksum_data = [
    ':'.join([f'{float(order[0])}:{float(order[1])}' for order in (bid, offer) if order])
    for (bid, offer) in zip_longest(orderbook['bids'][:100], orderbook['asks'][:100])
]

computed_result = int(zlib.crc32(':'.join(checksum_data).encode()))

if computed_result != checksum:
    # Checksum does not match. 
    # Re-subscribe to orderbook channel and start from fresh snapshot