Exchange Wire Formats

Bitget Futures wire format

How Bitget USDT-M, USDC-M and Coin-M Futures messages become rows in our Parquet files. Each data type below shows a real message next to the rows we publish for it, with the source and the rule for every column. Hover a line or a column to see how they connect.

Checked against our pipeline

These messages were captured from Bitget USDT-M, USDC-M and Coin-M Futures on 2026-10-05. Our test suite replays each one through the production collector parser and postprocessor, and fails if the published rows differ from the rows on this page. Files written before a change to the pipeline can differ; see Known Gaps & Corrections.

The collector subscribes to the books, trade and ticker channels for every tradable contract of the USDT-FUTURES, USDC-FUTURES (for example BTCPERP) and COIN-FUTURES product types, and to the liquidation topic once per product type. The examples use BTCUSDT. There are no REST polls: open interest and mark prices come from the ticker channel.

  • Public WebSocket V2 (order book, trades, ticker): wss://ws.bitget.com/v2/ws/public
  • Public WebSocket V3 (liquidations): wss://ws.bitget.com/v3/ws/public

Exchange API reference: www.bitget.com. Conventions shared by every exchange are on the wire formats overview.

Trades

One row per trade from the trade channel.

  • WebSocket trade

Trade snapshot on subscribe

Right after subscribing, Bitget resends recent trades, newest first, as one snapshot message. They are published like any other trade, sorted oldest first; trades already published in an earlier hour, or earlier in the same hour, are dropped.

Abridged: The snapshot carried the 50 most recent trades; the newest three are shown.

WebSocket message · tradereceived 2026-10-05 19:11:22.132028 UTC
{
"action": "snapshot",
"arg": {
"instType": "USDT-FUTURES",
"channel": "trade",
"instId": "BTCUSDT"
},
"data": [
{
"ts": "1791227481512",
"price": "85599.9",
"size": "0.2581",
"side": "buy",
"tradeId": "1491081618619383808"
},
{
"ts": "1791227480460",
"price": "85599.9",
"size": "0.209",
"side": "buy",
"tradeId": "1491081614206976018"
},
{
"ts": "1791227480460",
"price": "85599.9",
"size": "0.0001",
"side": "buy",
"tradeId": "1491081614206976016"
}
],
"ts": 1791227482003
}

Published rows · 3

received_time1791227482132028000—Our collector's clock when the message arrived, in nanoseconds since the Unix epoch. Not sent by Bitget.
event_time1791227480460data[].tsCopied from the trade's fill time data[].ts, not the envelope ts. Milliseconds.
symbolBTCUSDTarg.instIdCopied.
trade_id1491081614206976016data[].tradeIdCopied, stored as an integer.
price85599.9data[].priceCopied as the exact decimal string.
quantity0.0001data[].sizeCopied as the exact decimal string. Base asset units.
trade_time1791227480460data[].tsCopied. Milliseconds. Same value as event_time.
is_buyer_makerfalsedata[].sidetrue when the taker side side is sell, false when it is buy.
order_typeMARKET—Always MARKET. Bitget does not send an order type; this is a placeholder.

Trade update

Later messages carry new trades only. One message can hold several trades, newest first; each becomes its own row.

WebSocket message · tradereceived 2026-10-05 19:11:27.315542 UTC
{
"action": "update",
"arg": {
"instType": "USDT-FUTURES",
"channel": "trade",
"instId": "BTCUSDT"
},
"data": [
{
"ts": "1791227487186",
"price": "85599.8",
"size": "0.0027",
"side": "sell",
"tradeId": "1491081642417864704"
}
],
"ts": 1791227487186
}

Published row

received_time1791227487315542000—Our collector's clock when the message arrived, in nanoseconds since the Unix epoch. Not sent by Bitget.
event_time1791227487186data[].tsCopied from the trade's fill time data[].ts, not the envelope ts. Milliseconds.
symbolBTCUSDTarg.instIdCopied.
trade_id1491081642417864704data[].tradeIdCopied, stored as an integer.
price85599.8data[].priceCopied as the exact decimal string.
quantity0.0027data[].sizeCopied as the exact decimal string. Base asset units.
trade_time1791227487186data[].tsCopied. Milliseconds. Same value as event_time.
is_buyer_makertruedata[].sidetrue when the taker side side is sell, false when it is buy.
order_typeMARKET—Always MARKET. Bitget does not send an order type; this is a placeholder.

Notes

  • Bitget's side is the taker's side. Bitget sends no order type, so order_type is always MARKET; use is_buyer_maker for the aggressor side.
  • Trade IDs increase over time but are not consecutive. Do not use gaps in trade_id to detect missed trades.

Column types and descriptions: Trades schema.

Order Book

One row per price level from the books channel: a snapshot on subscribe, then incremental updates.

  • WebSocket books

Book snapshot

The first books message after subscribing (and after every reconnect) is a snapshot of the book. Each level becomes one snapshot row.

Abridged: Bitget sent 500 bid and 500 ask levels in this snapshot; the best three of each are shown.

WebSocket message · booksreceived 2026-10-05 19:11:22.394450 UTC
{
"action": "snapshot",
"arg": {
"instType": "USDT-FUTURES",
"channel": "books",
"instId": "BTCUSDT"
},
"data": [
{
"asks": [
["85599.9", "0.5811"],
["85600", "0.1907"],
["85601.9", "0.0002"]
],
"bids": [
["85599.8", "3.4111"],
["85599.7", "0.0598"],
["85599.2", "0.2628"]
],
"ts": "1791227482002",
"seq": 1062970931190,
"pseq": 0
}
],
"ts": 1791227482021
}

Published rows · 6

received_time1791227482394450000—Our collector's clock when the message arrived, in nanoseconds since the Unix epoch. Not sent by Bitget.
event_time1791227482021tsCopied from the envelope ts, Bitget's push time. Milliseconds.
transaction_time1791227482002data[].tsCopied from data[].ts, the matching-engine time. Milliseconds.
symbolBTCUSDTarg.instIdCopied.
event_typesnapshotactionsnapshot when action is snapshot.
first_update_idnull—Null. Bitget sends one sequence number per push, not a range.
final_update_id1062970931190data[].seqCopied.
prev_final_update_idnull—Null for snapshots: a snapshot starts a new seq chain. Bitget sends pseq 0 on snapshots.
last_update_idnull—Null. Bitget sends no separate last update ID.
sidebiddata[].bidsdata[].asksbid for levels in bids, ask for levels in asks. One row per level.
price85599.8data[].bids[][0]data[].asks[][0]Copied as the exact decimal string.
quantity3.4111data[].bids[][1]data[].asks[][1]Copied as the exact decimal string: the total size at that price. Base asset units.
order_countnull—Null. Bitget's books channel does not report order counts.

Book update

The first update after the snapshot above. Its pseq equals the snapshot's seq, so the sequence chain is unbroken.

Abridged: Bitget sent 8 bid and 17 ask levels in this update; the first 2 bid and the first 3 ask levels are shown.

WebSocket message · booksreceived 2026-10-05 19:11:22.394832 UTC
{
"action": "update",
"arg": {
"instType": "USDT-FUTURES",
"channel": "books",
"instId": "BTCUSDT"
},
"data": [
{
"asks": [
["85602.2", "0"],
["85603.7", "0.0001"],
["85603.8", "0.0808"]
],
"bids": [
["85599.8", "3.8911"],
["85599.7", "0.0597"]
],
"ts": "1791227482100",
"seq": 1062970936888,
"pseq": 1062970931190
}
],
"ts": 1791227482103
}

Published rows · 5

received_time1791227482394832000—Our collector's clock when the message arrived, in nanoseconds since the Unix epoch. Not sent by Bitget.
event_time1791227482103tsCopied from the envelope ts, Bitget's push time. Milliseconds.
transaction_time1791227482100data[].tsCopied from data[].ts, the matching-engine time. Milliseconds.
symbolBTCUSDTarg.instIdCopied.
event_typeupdateactionupdate when action is update.
first_update_idnull—Null. Bitget sends one sequence number per push, not a range.
final_update_id1062970936888data[].seqCopied.
prev_final_update_id1062970931190data[].pseqCopied. The seq of the previous push on this subscription; a mismatch with the previous message's final_update_id is a gap. All rows of one message share it, so check once per message, not per row.
last_update_idnull—Null. Bitget sends no separate last update ID.
sidebiddata[].bidsdata[].asksbid for levels in bids, ask for levels in asks. One row per level.
price85599.8data[].bids[][0]data[].asks[][0]Copied as the exact decimal string.
quantity3.8911data[].bids[][1]data[].asks[][1]Copied as the exact decimal string: the new total size at that price. Base asset units. 0 removes the level.
order_countnull—Null. Bitget's books channel does not report order counts.

Notes

  • transaction_time holds the matching-engine time from the October 2026 pipeline update; it is null in files written before it. event_time has always been the push time.
  • Each update's prev_final_update_id (pseq) equals the previous message's final_update_id (seq). A mismatch means a lost message; resume from the next snapshot.
  • A message with no levels at all is published as one row with side noop, price 0 and quantity 0, so the seq chain stays complete. A noop update changes no level. A noop snapshot means the book is empty: clear your book.
  • Files can start with a checkpoint snapshot of the book carried over from the previous hour: its received_time is the hour start, transaction_time is null, and final_update_id and last_update_id both hold the seq of the last message applied. The next update's prev_final_update_id links to it.

Column types and descriptions: Order Book schema.

Ticker

One row per ticker push.

  • WebSocket ticker
WebSocket message · tickerreceived 2026-10-05 19:11:22.136978 UTC
{
"action": "snapshot",
"arg": {
"instType": "USDT-FUTURES",
"channel": "ticker",
"instId": "BTCUSDT"
},
"data": [
{
"instId": "BTCUSDT",
"lastPr": "85599.9",
"bidPr": "85599.8",
"askPr": "85599.9",
"bidSz": "4.0378",
"askSz": "0.4618",
"open24h": "85345.7",
"high24h": "86966.9",
"low24h": "84929.5",
"change24h": "0.00298",
"fundingRate": "0.000063",
"nextFundingTime": "1791244800000",
"markPrice": "85599.9",
"indexPrice": "85636.34",
"holdingAmount": "31506.4859999999786",
"baseVolume": "41733.57",
"quoteVolume": "3588373746.3737",
"openUtc": "86473.2",
"symbolType": "1",
"symbol": "BTCUSDT",
"ts": "1791227481990"
}
],
"ts": 1791227481991
}

Published row

received_time1791227482136978000—Our collector's clock when the message arrived, in nanoseconds since the Unix epoch. Not sent by Bitget.
event_time1791227481991tsCopied from the envelope ts, Bitget's push time. Milliseconds.
symbolBTCUSDTdata[].instIdCopied.
price_changenull—Null. Bitget does not send the absolute 24h price change.
price_change_percent0.298data[].change24hchange24h multiplied by 100. Bitget sends a fraction (0.01 is 1 %); the column is in percent.
weighted_average_pricenull—Null. Bitget does not send a weighted average price.
last_price85599.9data[].lastPrCopied.
last_quantitynull—Null. Bitget's ticker does not send the last trade size.
open_price85345.7data[].open24hCopied. The price 24 hours ago (rolling window), not the UTC-day open.
high_price86966.9data[].high24hCopied. Rolling 24 hours.
low_price84929.5data[].low24hCopied. Rolling 24 hours.
base_asset_volume41733.57data[].baseVolumeCopied. 24h volume in base asset units.
quote_asset_volume3588373746.3737data[].quoteVolumeCopied. 24h volume in quote asset units.
statistics_open_timenull—Null. Bitget does not send the window bounds.
statistics_close_timenull—Null. Bitget does not send the window bounds.
first_trade_idnull—Null. Bitget does not send trade ID ranges.
last_trade_idnull—Null. Bitget does not send trade ID ranges.
total_tradesnull—Null. Bitget does not send a trade count.

Notes

  • price_change_percent is in percent from the October 2026 pipeline update. Files written before it hold Bitget's fraction unchanged (0.01 for 1 %); multiply those values by 100.
  • The ticker's best bid and ask (bidPr, askPr, bidSz, askSz) and openUtc are not published. Mark price, index price and funding go to mark_price; open interest goes to open_interest.

Column types and descriptions: Ticker schema.

Mark Price

One row per futures ticker push, from the ticker's mark price, index price and funding fields. The collector subscribes to no separate mark price channel.

  • WebSocket ticker

The same ticker message as on the ticker page. Every futures ticker push also becomes one mark price row.

WebSocket message · tickerreceived 2026-10-05 19:11:22.136978 UTC
{
"action": "snapshot",
"arg": {
"instType": "USDT-FUTURES",
"channel": "ticker",
"instId": "BTCUSDT"
},
"data": [
{
"instId": "BTCUSDT",
"lastPr": "85599.9",
"bidPr": "85599.8",
"askPr": "85599.9",
"bidSz": "4.0378",
"askSz": "0.4618",
"open24h": "85345.7",
"high24h": "86966.9",
"low24h": "84929.5",
"change24h": "0.00298",
"fundingRate": "0.000063",
"nextFundingTime": "1791244800000",
"markPrice": "85599.9",
"indexPrice": "85636.34",
"holdingAmount": "31506.4859999999786",
"baseVolume": "41733.57",
"quoteVolume": "3588373746.3737",
"openUtc": "86473.2",
"symbolType": "1",
"symbol": "BTCUSDT",
"ts": "1791227481990"
}
],
"ts": 1791227481991
}

Published row

received_time1791227482136978000—Our collector's clock when the message arrived, in nanoseconds since the Unix epoch. Not sent by Bitget.
event_time1791227481991tsCopied from the envelope ts, Bitget's push time. Milliseconds.
symbolBTCUSDTdata[].instIdCopied.
mark_price85599.9data[].markPriceCopied.
index_price85636.34data[].indexPriceCopied.
estimated_settle_pricenull—Copied from deliveryPrice when the push has it. Bitget documents it for delivery contracts, pushed from one hour before delivery. Null here: this perpetual ticker has no deliveryPrice field.
funding_rate0.000063data[].fundingRateCopied. A fraction per funding period: 0.000063 is 0.0063 %.
next_funding_time1791244800000data[].nextFundingTimeCopied. Next funding settlement time, milliseconds.

Column types and descriptions: Mark Price schema.

Open Interest

One row per ticker push, from the ticker's holdingAmount. There is no REST poll.

  • WebSocket ticker

The same ticker message again. Every futures ticker push also becomes one open interest row.

WebSocket message · tickerreceived 2026-10-05 19:11:22.136978 UTC
{
"action": "snapshot",
"arg": {
"instType": "USDT-FUTURES",
"channel": "ticker",
"instId": "BTCUSDT"
},
"data": [
{
"instId": "BTCUSDT",
"lastPr": "85599.9",
"bidPr": "85599.8",
"askPr": "85599.9",
"bidSz": "4.0378",
"askSz": "0.4618",
"open24h": "85345.7",
"high24h": "86966.9",
"low24h": "84929.5",
"change24h": "0.00298",
"fundingRate": "0.000063",
"nextFundingTime": "1791244800000",
"markPrice": "85599.9",
"indexPrice": "85636.34",
"holdingAmount": "31506.4859999999786",
"baseVolume": "41733.57",
"quoteVolume": "3588373746.3737",
"openUtc": "86473.2",
"symbolType": "1",
"symbol": "BTCUSDT",
"ts": "1791227481990"
}
],
"ts": 1791227481991
}

Published row

received_time1791227482136978000—Our collector's clock when the message arrived, in nanoseconds since the Unix epoch. Not sent by Bitget.
symbolBTCUSDTdata[].instIdCopied.
sum_open_interest31506.4859999999786data[].holdingAmountCopied exactly as sent, including Bitget's float noise (…9999786). Base asset units.
sum_open_interest_value2696952050.95139817data[].holdingAmountdata[].markPriceholdingAmount × markPrice, computed in exact decimal and rounded to 8 decimal places. Quote currency (USDT for USDT-margined contracts, USDC for USDC-margined contracts, USD for coin-margined contracts). Null if either field is missing.
timestamp1791227481990data[].tsCopied from data[].ts, Bitget's data time. Milliseconds.

Notes

  • Rows repeat at the ticker's rate even when open interest has not changed.
  • sum_open_interest_value was empty before the 2026-09 data-integrity release.

Column types and descriptions: Open Interest schema.

Liquidations

One row per entry of the V3 liquidation topic, subscribed once per product type (usdt-futures, usdc-futures, coin-futures).

  • WebSocket liquidation

No BTCUSDT liquidation arrived while we captured, so this example is for ZECUSDT. The sell side means a short position was liquidated.

WebSocket message · liquidationreceived 2026-10-05 19:13:37.850963 UTC
{
"action": "update",
"arg": {
"instType": "usdt-futures",
"topic": "liquidation"
},
"data": [
{
"symbol": "ZECUSDT",
"side": "sell",
"price": "1348.598068598069",
"amount": "775.443889443889",
"ts": "1791227617704"
}
],
"ts": 1791227617724
}

Published row

received_time1791227617850963000—Our collector's clock when the message arrived, in nanoseconds since the Unix epoch. Not sent by Bitget.
event_time1791227617704data[].tsCopied from the liquidation time data[].ts. Milliseconds.
symbolZECUSDTdata[].symbolCopied.
sideBUYdata[].sideSide of the liquidation order: buy (a long position was liquidated) becomes SELL, sell (a short position was liquidated) becomes BUY.
order_typeMarket—Always Market. A placeholder: Bitget sends no order type.
time_in_forceIOC—Always IOC. A placeholder: Bitget sends no time in force.
quantity0.575data[].amountdata[].priceamount ÷ price, computed in exact decimal and rounded to 6 decimal places. Base asset units. Bitget sends amount in quote currency.
price1348.598068598069data[].priceCopied. Bitget's liquidation price.
average_price1348.598068598069data[].priceCopy of price. Bitget sends no average fill price.
order_statusFILLED—Always FILLED. A placeholder: Bitget sends no order status.
last_filled_quantity0.575data[].amountdata[].priceSame value as quantity.
filled_quantity0.575data[].amountdata[].priceSame value as quantity.
trade_time1791227617704data[].tsCopied. Milliseconds. Same value as event_time.

Notes

  • Bitget pushes liquidations once per second and sends at most one record per symbol and position side per second: the largest. Rows are an exchange-sampled subset, not every liquidation, so counts and totals are a lower bound.
  • An entry without a positive price and amount is not published, because it has no valid base quantity. Before the October 2026 pipeline update, such an entry was published with the quote amount as its quantity.

Column types and descriptions: Liquidations schema.