Please note BitMEX does not support old browsers.
We recommend upgrading to the latest version of Opera, Firefox, or Chrome.
AllBTCUSDT100000.0+17.67%BTCUSD83927.5+1.10%BTC/USDT83954.5+1.15%BTCEUR76969.0-0.01%BTCETH43.323-1.37%BTCUSD_​BBX59922.0+0.73%BTCUSDTH2584457.0+0.97%BTCUSDTM2588518.0+0.85%BTCH2584703.0+1.17%BTCM2588648.5+1.04%BTCJ2585606.5-0.05%BTCZ2596997.0+1.90%BTCU2592609.0-0.13%ETHUSDT1937.57+2.33%ETHBTC0.02297+0.39%ETHUSD1937.60+2.28%ETH/USDT4606.00+2.36%ETH/BTC0.0800000+0.00%ETHUSDH251948.05+2.53%ETHUSDM252047.15+2.42%ETHH250.02316+1.18%ETHM250.02431+2.06%BMEXUSDT25.055+0.00%BMEX/USDT0.3129+3.95%AAVEUSDT176.42+5.93%AAVEUSD176.30+7.06%ACTUSDT0.32614+0.00%ADAUSDT0.7445-3.00%ADAUSD0.7208+3.12%ADAH250.00000863+2.13%ADAM250.00000896+0.67%AEVOUSDT0.3993+20.09%AI16ZUSDT0.2041-30.65%AIBTCUSDT0.6348-0.02%APE/USDT0.555+9.47%APEUSDT0.5688+13.51%APTUSDT6.107+0.00%APTUSD5.379+4.37%APUUSDT0.0002196+8.93%ATOM/USDT--.-+0.00%AVAXUSDT18.836+2.45%AVAXUSD18.838+2.05%AXS/USDT3.745+0.03%AXSUSD3.45+7.48%BANANAUSDT17.3897-1.90%MEMEMEXTUSDT68.02+3.23%BBX/USDT--.-+0.00%BCHUSDT338.05+0.84%BCHUSD337.45+1.05%BERAUSDT--.-+0.00%BIGTIMEUSDT0.04957+13.15%BIOUSDT0.7183+0.00%BLURUSDT0.1080+4.96%BLURUSD0.1075+4.57%BNBUSDT624.59+3.47%BNBUSD624.68+3.66%BOMEUSDT0.006857+9.36%100BONKUSDT0.0011151+6.89%BONK/USDT--.-+0.00%BRETTUSDT0.20735+0.00%BROCCOLIUSDT--.-+0.00%CATUSDT0.000008137+8.55%CHILLGUYUSDT--.-+0.00%CYBERUSDT1.3315+8.46%DOGEUSDT0.17384+2.97%DOGEUSD0.17383+2.87%DOGSUSDT0.000144+1.41%DOTUSDT4.413+4.06%DOTUSD4.423+3.41%DUCKUSDT0.003049-5.95%DYDXUSD0.6457+4.79%DYMUSDT0.3422+8.36%ENAUSDT0.9876+249.96%EOSUSD0.5024+5.32%FARTCOINUSDT0.3150-9.14%FILUSDT3.1011+2.67%FILUSD3.0638+7.60%FLOKIUSDT0.00006219+4.87%FTR/USDT0.015000+0.00%P_​FTXZ2630.66-0.29%GEMS/USDT--.-+0.00%GMEUSDT0.001618+3.59%GMTUSD0.0500+5.04%GOATUSDT--.-+0.00%GOAT/USDT--.-+0.00%GPSUSDT--.-+0.00%HIVEUSDT0.2559-6.84%HSKUSDTZ251.2000+0.00%HYPEUSDT14.880-15.37%INJUSDT9.2934-6.67%IPUSDT--.-+0.00%JUSDT0.2291-26.12%JAILSTOOLUSDT--.-+0.00%JUPUSDT0.5459-17.11%KAITOUSDT--.-+0.00%KLAYUSDT0.12315+0.00%LDOUSD0.9744+6.20%LDOUSDT0.9847-18.67%LINKUSDT14.162+5.59%LINK/USDT14.918-97.31%LINKUSD14.137+5.11%LTCUSDT93.16+3.72%LTCUSD93.01+2.94%LUNAUSDT0.2216+7.10%MANTAUSDT0.2625+7.10%MEUSDT9.0000+0.00%MELANIAUSDT--.-+0.00%MEMEUSDT0.002488+8.27%MERLUSD0.1335+19.62%MEWUSDT0.001953+5.85%1000000MOGUSDT2.4000+0.00%MOVEUSDT1.0700+0.00%MUBARAKUSDT--.-+0.00%MYROUSDT0.01874+0.32%NEARUSDT2.637+4.15%NEARUSD2.644+5.17%NOTUSDT0.002382-0.83%ONDOUSDT0.87767+7.31%OPUSD0.8996+8.59%OPUSDT0.9097-14.61%ORDIUSD9.576+4.67%PENGUUSDT0.00697+2.50%PEPEUSD0.000007319+11.93%PEPEUSDT0.000007339+11.64%PIUSDT--.-+0.00%PIXELUSDT0.1788+33.73%PNUTUSDT0.50860-49.14%POLUSDT0.2166+2.75%POL/USDT0.3707-0.99%POPCATUSDT0.8000+40.33%P_​POWELLK2643.65-0.46%PYTHUSDT0.1463-18.40%RAYUSDT1.747-25.37%REDUSDT--.-+0.00%REDUSDTZ250.9900-0.72%SUSDT0.5012+0.68%S/USDT0.4391+6.86%SAGAUSDT0.3932-9.07%SEIUSDT0.2011+0.65%SHELLUSDT--.-+0.00%SHIBUSDT0.000012957-1.38%SHIBUSD0.000012952-1.84%SOLUSDT128.65-3.39%SOLUSD128.92+1.34%SOL/USDT129.00-5.44%SOLVUSDT0.04304+2.23%STLS/USDT0.10607+0.07%STRKUSDT0.1785-1.71%SUIUSDT2.3426+5.09%SUIUSD2.339+4.65%TIAUSDT3.3244-6.64%TNSRUSDT0.4456-6.13%TONUSD3.4863+2.22%TONUSDT5.4167-8.90%TRUMP/USDT0.715-98.57%TRUMPOFFICIALUSDT12.646-6.34%TRXUSDT0.22031+3.06%TRXUSD0.22040+3.51%TRX/USDT0.09020+0.00%TSTUSDT--.-+0.00%UNI/USDT7.545+0.00%USDTUSDC1.0019+0.15%USUALUSDT1.0700+0.00%VELOUSDT0.242500+0.00%VINEUSDT0.1645+0.00%VVVUSDT--.-+0.00%WUSDT0.3146+45.51%WEN/USDT--.-+0.00%WIFUSDT0.5129-14.72%WLDUSDT0.904+5.36%WLDUSD0.887+4.48%WLFIUSDTZ260.089-4.30%WOOUSDT0.2149+35.41%XAIUSDT0.25260+31.84%XAUTUSD3006.2+0.57%XRDUSDT0.00688-6.65%XRPUSDT2.4033+0.33%XRPUSD2.3487+1.99%XRP/USDT2.3658+1.93%XRPH250.00002810+0.54%XRPM250.00002940+1.52%ZKUSDT0.1939+69.34%ZROUSDT2.5715+8.92%Funding: 06:23:58 @ -0.3285%Time: 9:36:01 pm UTC

WebSocket API

BitMEX offers a complete pub/sub API with table diffing over WebSocket. You may subscribe to real-time changes on any available table.

Reference Connectors

For working code and examples, please see our WebSocket Connectors on GitHub.

Connecting

Connect your websocket client to the primary websocket endpoint wss://ws.testnet.bitmex.com/realtime for trading related topics (see below).

Alternate endpoints depending on topic:

  • For platform topics, wss://ws.testnet.bitmex.com/realtimePlatform

You can get a basic idea of how to use our websocket API by sending "help".

All Commands

A basic command is sent in the following format:

{"op": "<command>", "args": ["arg1", "arg2", "arg3"]}

The args array is optional on some commands. If you are only sending a single argument, the array is not necessary.

Note that placing and canceling orders is not supported via the Websocket. Please use the REST API for this. When using HTTP Keep-Alive, request/response round-trip time will be identical to Websocket.

Subscriptions

BitMEX allows subscribing to real-time data. This access is not rate-limited once connected and is the best way to get the most up-to-date data to your programs.

To subscribe to topics, send them as a comma-separated list in your connection string. For example:

wss://ws.testnet.bitmex.com/realtime?subscribe=instrument,orderBookL2_25:XBTUSD

If you are already connected and wish to subscribe to a new topic, send a message with the following format:

{"op": "subscribe", "args": [<SubscriptionTopic>]}

You may subscribe to multiple topics at a time by sending an array of subscription topics.

The following subscription topics are available on the primary endpoint without authentication:

"funding",             // Updates of swap funding rates. Sent every funding interval (usually 8hrs)
"instrument",          // Instrument updates including turnover and bid/ask (Special filters: CONTRACTS, INDICES, DERIVATIVES, SPOT)
"insurance",           // Daily Insurance Fund updates
"liquidation",         // Liquidation orders as they're entered into the book
"orderBookL2_25",      // Top 25 levels of level 2 order book
"orderBookL2",         // Full level 2 order book
"orderBook10",         // Top 10 levels using traditional full book push
"quote",               // Top level of the book
"quoteBin1m",          // 1-minute quote bins
"quoteBin5m",          // 5-minute quote bins
"quoteBin1h",          // 1-hour quote bins
"quoteBin1d",          // 1-day quote bins
"settlement",          // Settlements
"trade",               // Live trades
"tradeBin1m",          // 1-minute trade bins
"tradeBin5m",          // 5-minute trade bins
"tradeBin1h",          // 1-hour trade bins
"tradeBin1d",          // 1-day trade bins

The following subscription topics require authentication and are also available on the primary endpoint:

"affiliate",   // Affiliate status, such as total referred users & payout %
"execution",   // Individual executions; can be multiple per order
"order",       // Live updates on your orders
"margin",      // Updates on your current account balance and margin requirements
"position",    // Updates on your positions
"transact"     // Deposit/Withdrawal updates
"wallet"       // Bitcoin address balance data, including total deposits & withdrawals

The following subscriptions are only available on the /realtimePlatform endpoint:

"announcement",        // Site announcements
"chat",                // Trollbox chat
"connected",           // Statistics of connected users/bots
"publicNotifications", // System-wide notifications (used for short-lived messages)
"privateNotifications", // Individual notifications - currently not used (requires auth)

If you wish to get real-time order book data, we recommend you use the orderBookL2_25 subscription. orderBook10 pushes the top 10 levels on every tick, but transmits much more data. orderBookL2 pushes the full L2 order book, but the payload can get very large. orderbookL2_25 provides a subset of the full L2 orderbook, but is throttled. In the future, orderBook10 may be throttled, so use orderBookL2 in any latency-sensitive application. The id on an orderBookL2_25 or orderBookL2 entry is always unique for any given price level and it should be used to apply update and delete actions.

When applicable, topics may be filtered to a given instrument by appending a colon and instrument name. For example, trade:XBTUSD will subscribe you to messages only for the XBTUSD instrument.

Some traffic:

> {"op": "subscribe", "args": ["orderBookL2_25:XBTUSD"]}
  < {"success":true,"subscribe":"orderBookL2_25:XBTUSD","request":{"op":"subscribe","args":["orderBookL2_25:XBTUSD"]}}
  < {
      "table":"orderBookL2_25",
      "keys":["symbol","id","side"],
      "types":{"id":"long","price":"float","side":"symbol","size":"long","symbol":"symbol","timestamp":"timestamp"}
      "action":"partial",
      "data":[
        {"symbol":"XBTUSD","id":17999992000,"side":"Sell","size":100,"price":80,"timestamp":"2022-02-09T11:23:06.802Z"},
        {"symbol":"XBTUSD","id":17999993000,"side":"Sell","size":20,"price":70,"timestamp":"2022-02-09T11:23:06.802Z"},
        {"symbol":"XBTUSD","id":17999994000,"side":"Sell","size":10,"price":60,"timestamp":"2022-02-09T11:23:06.802Z"},
        {"symbol":"XBTUSD","id":17999995000,"side":"Buy","size":10,"price":50,"timestamp":"2022-02-09T11:23:06.802Z"},
        {"symbol":"XBTUSD","id":17999996000,"side":"Buy","size":20,"price":40,"timestamp":"2022-02-09T11:23:06.802Z"},
        {"symbol":"XBTUSD","id":17999997000,"side":"Buy","size":100,"price":30,"timestamp":"2022-02-09T11:23:06.802Z"}
      ]
    }
  < {
      "table":"orderBookL2_25",
      "action":"update",
      "data":[
        {"symbol":"XBTUSD","id":17999995000,"side":"Buy","size":5}
      ]
    }
  < {
      "table":"orderBookL2_25",
      "action":"delete",
      "data":[
        {"symbol":"XBTUSD","id":17999995000,"side":"Buy"}
      ]
    }
  < {
      "table":"orderBookL2_25",
      "action":"insert",
      "data":[
        {"symbol":"XBTUSD","id":17999995500,"side":"Buy","size":10,"price":45},
      ]
    }

Upon subscription, you will receive an image of the existing data, so you can get started. This comes through as a partial action.

You may receive other messages before the partial comes through. In that case, drop any messages received until you have received the partial.

Some notes on this response:

  • After the subscription acknowledgement, you’ll receive a message with "action": "partial". This is an image of the table, after which you can apply deltas.
    • If you receive any messages before the partial, ignore them.
  • The partial also contains some table information, like keys and types. Depending on your application, this data may be useful.
    • Columns listed in keys always come back on an insert, delete, or update. Use them to look up which items to modify in your storage.

For an example of this in action, see our official NodeJS Delta Parser.

You may unsubscribe using the 'unsubscribe' operation. The formatting is identical to 'subscribe'.

Authentication

A number of data streams are publicly available (see below). If you wish to subscribe to user-locked streams, you must authenticate first. Note that invalid authentication will close the connection.

API Keys

BitMEX API usage requires an API Key.

Permanent API Keys can be locked to IP address ranges and revoked at will without compromising your main credentials. They also do not require renewal.

To use API Key auth, you must generate an API Key.

To use an API Key with websockets, you can either:

  • Sign the initial upgrade request in the same manner you would sign other REST calls (api-* headers), or
  • Connect to websocket with api-* headers in the query parameters (e.g. /realtime?api-key=***&api-signature=***&api-expires=12345)

In both cases, use a signature as if you were signing GET /realtime. See this Python implementation for an example and working code.

If you have questions about authenticating with an API Key, please see the API Key Authentication Documentation.

Heartbeats

Some WebSocket libraries are better than others at detecting connection drops. If your websocket library supports hybi-13, or ping/pong, you may send a ping at any time and the server will return with a pong.

Due to changes in browser power-saving modes, we no longer support expectant pings via the WebSocket API.

If you are concerned about your connection silently dropping, we recommend implementing the following flow:

  • After receiving each message, set a timer a duration of 5 seconds.
  • If any message is received before that timer fires, restart the timer.
  • When the timer fires (no messages received in 5 seconds), send a raw ping frame (if supported) or the literal string 'ping'.
  • Expect a raw pong frame or the literal string 'pong' in response. If this is not received within 5 seconds, throw an error or reconnect.

Dead Man’s Switch (Auto Cancel)

BitMEX offers “Dead Man’s Switch” functionality to help prevent unexpected losses from network malfunctions. If you are putting up significant risk on BitMEX, it can be nerve-wracking to think of what might happen if you or your datacenter loses connectivity.

Via REST at /order/cancelAllAfter or via WebSocket via the example below, one can set a millisecond timeout. This will start a timer. If cancelAllAfter is not called again before time runs out, all of your existing orders on all symbols will be canceled.

To cancel this operation and keep your orders open, pass a timeout of 0.

Advanced users of BitMEX should use this operation. A common use pattern is to set a timeout of 60000, and call it every 15 seconds. This gives you sufficient wiggle room to keep your orders open in case of a network hiccup, while still offering significant protection in case of a larger outage. Of course, the parameters are up to you.

We recommend not setting a timeout of less than 5 seconds to avoid being rate limited or having your orders unexpectedly canceled in case of network congestion.

For example:

// Places a dead man's switch at 60 seconds.
> {"op": "cancelAllAfter", "args": 60000}
  < {"now":"2015-09-02T14:18:43.536Z","cancelTime":"2015-09-02T14:19:43.536Z",
     "request":{"op":"cancelAllAfter","args":60000}}
// Cancels the switch.
> {"op": "cancelAllAfter", "args": 0}
  < {"now":"2015-09-02T14:19:11.617Z","cancelTime":0,"request":{"op":"cancelAllAfter","args":0}}

Rate Limits

The following actions are ratelimited:

  • Subscription: Consumes one token from your request limiter.
  • Connection: 720 per hour, on a separate limiter.
  • Dead Man’s Switch (cancelAllAfter): Consumes one token from your request limiter.

If you exceed your ratelimit on a subscription or cancelAllAfter call, you will see a message like:

{"status":429,"error":"Rate limit exceeded, retry in 1 seconds.","meta":{"retryAfter":1},"request":{"op":"subscribe","args":"orderBookL2_25"}}

If you are ratelimited from connecting, the message is slightly different (example includes headers):

HTTP/1.1 429 Too Many Requests
Cache-Control: no-store, no-cache, must-revalidate, max-age=0
Pragma: no-cache
X-RateLimit-Limit: 720
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1506983924
Retry-After: 29
Content-Type: application/json
Content-Length: 55
Date: Mon, 02 Oct 2017 21:43:49 GMT
Connection: keep-alive

{"error":"Rate limit exceeded, retry in 29 seconds."}

In rare occasions where our servers are too busy, they could become temporarily unavailable to process incoming requests.

They will then respond with an error:

{"status":503,"error":"Max Pending subscription limit reached, please try again later.","request":{"op":"subscribe","args":"orderBookL2"}}

Users are recommended to retry a couple of times within a short interval in this situation e.g. 1s

Response Format

Websocket responses may be of the following three types:

Success: (Emitted upon a successful subscription to a topic)

{"subscribe": subscriptionName, "success": true}

Error: (Emitted upon a malformed request or an attempt to request a locked resource)

{"error": errorMessage}

Data: (Emitted when data is available or requested)

This definition follows the typing conventions used in Flowtype and TypeScript. Fields suffixed with ? are not always present. See the comments for more details.

{
  // Table name / Subscription topic.
  // Could be "trade", "order", "instrument", etc.
  "table": string,

  // The type of the message. Types:
  // 'partial'; This is a table image, replace your data entirely.
  // 'update': Update a single row.
  // 'insert': Insert a new row.
  // 'delete': Delete a row.
  "action": 'partial' | 'update' | 'insert' | 'delete',

  // An array of table rows is emitted here. They are identical in structure to data returned from the REST API.
  "data": Object[],

  //
  // The below fields define the table and are only sent on a `partial`
  //

  // Attribute names that are guaranteed to be unique per object.
  // If more than one is provided, the key is composite.
  // Use these key names to uniquely identify rows. Key columns are guaranteed
  // to be present on all data received.
  "keys"?: string[],

  // This lists the shape of the table. The possible types:
  // "symbol" - In most languages this is equal to "string"
  // "guid"
  // "timestamp"
  // "timespan"
  // "float"
  // "long"
  // "integer"
  // "boolean"
  "types"?: {[key: string]: string},

  // When multiple subscriptions are active to the same table, use the `filter` to correlate which datagram
  // belongs to which subscription, as the `table` property will not contain the subscription's symbol.
  "filter"?: {account?: number, symbol?: string},
}

Reference Implementation

We have a reference implementation of the websocket as part of our reference Market Maker.

Of interest is the __on_message function, which handles updating tables in memory.

Data Example

Outgoing messages are prefixed with >. Incoming messages are prefixed with <.

Using the python tool wsdump:

~/g/f/w/bin (master|✔) $ python wsdump.py \
  wss://ws.testnet.bitmex.com/realtime/websocket?accessToken=xnyXWIQL0sbrLC91ISDlFhuLUGQJNq05A...
Press Ctrl+C to quit

  < {"info":"Welcome to the BitMEX Realtime API.","version":"1.1.0",
     "timestamp":"2015-01-18T10:14:06.802Z","docs":"https://testnet.bitmex.com/app/wsAPI","heartbeatEnabled":false}

> "help"

  < {"info":"See https://testnet.bitmex.com/app/wsAPI and https://testnet.bitmex.com/explorer for more documentation.",...}

> {"op": "subscribe", "args": ["trade:XBTUSD","instrument:XBTUSD"]}

  < {"success":true,"subscribe":"trade:XBTUSD",
     "request":{"op":"subscribe","args":["trade:XBTUSD","instrument:XBTUSD"]}}
  < {"success":true,"subscribe":"instrument:XBTUSD",
     "request":{"op":"subscribe","args":["trade:XBTUSD","instrument:XBTUSD"]}}

  < {"table":"trade","action": "partial", ...}
  < {"table":"instrument","action": "partial", ...}

  < {"table":"instrument","action":"update","data":[{"symbol":"XBTUSD","fairPrice":380.52,
     "markPrice":380.52,"indicativeSettlePrice":380.52,"timestamp":"2016-01-15T22:33:15.000Z"}]}
  < {"table":"instrument","action":"update","data":[{"symbol":"XBTUSD","openValue":673520400,
     "timestamp":"2016-01-15T22:33:15.000Z"}]}

Data Samples

These include a few messages you might not see often in your testing; they are replicated here so you know how to handle them.

Liquidation

This assumes a 1-contract XBTUSD position with a liquidation price of 1140.1. At the time of this snap, the mark price jumped down to 1136.88.

# First, the position will update to a 'posState' of 'Liquidation'.
# Notice that the mark price is below the liquidation price. On a long, that means liquidation.
< {"table":"position",
   "action":"update",
   "data":[{
    "account":2,"symbol":"XBTUSD","currency":"XBt",
    "currentTimestamp":"2017-04-04T22:07:42.442Z", "currentQty":1,"markPrice":1136.88,"markValue":-87960,
    "riskValue":87960,"homeNotional":0.0008796,"posState":"Liquidation","maintMargin":263,
    "unrealisedGrossPnl":-677,"unrealisedPnl":-677,"unrealisedPnlPcnt":-0.0078,"unrealisedRoePcnt":-0.7756,
    "simpleQty":0.001,"liquidationPrice":1140.1, "timestamp":"2017-04-04T22:07:45.442Z"
   }]}

# Then, the liquidation execution is inserted. Notice that 'text' is 'Liquidation'.
< {"table":"execution",
   "action":"insert",
   "data":[{
    "execID":"0193e879-cb6f-2891-d099-2c4eb40fee21",
    "orderID":"00000000-0000-0000-0000-000000000000","clOrdID":"","clOrdLinkID":"","account":2,"symbol":"XBTUSD",
    "side":"Sell","lastQty":1,"lastPx":1134.37,"underlyingLastPx":null,"lastMkt":"XBME",
    "lastLiquidityInd":"RemovedLiquidity", "simpleOrderQty":null,"orderQty":1,"price":1134.37,"displayQty":null,
    "stopPx":null,"pegOffsetValue":null,"pegPriceType":"","currency":"USD","settlCurrency":"XBt",
    "execType":"Trade","ordType":"Limit","timeInForce":"ImmediateOrCancel","execInst":"",
    "contingencyType":"","exDestination":"XBME","ordStatus":"Filled","triggered":"","workingIndicator":false,
    "ordRejReason":"","simpleLeavesQty":0,"leavesQty":0,"simpleCumQty":0.001,"cumQty":1,"avgPx":1134.37,
    "commission":0.00075,"tradePublishIndicator":"DoNotPublishTrade","multiLegReportingType":"SingleSecurity",
    "text":"Liquidation","trdMatchID":"7f4ab7f6-0006-3234-76f4-ae1385aad00f","execCost":88155,"execComm":66,
    "homeNotional":-0.00088155,"foreignNotional":1,"transactTime":"2017-04-04T22:07:46.035Z",
    "timestamp":"2017-04-04T22:07:46.035Z"
   }]}

# Then, the position enters 'Liquidated' state. Notice the 'currentQty' is still 1.
< {"table":"position",
   "action":"update",
   "data":[{
    "account":2,"symbol":"XBTUSD","currency":"XBt","currentQty":1,
    "markPrice":1136.88,"posState":"Liquidated","simpleQty":0.001,"liquidationPrice":1140.1,"bankruptPrice":1134.37,
    "timestamp":"2017-04-04T22:07:46.019Z"
   }]}

# Quickly thereafter, the position resets.
< {"table":"position",
   "action":"update",
   "data":[{
    "account":2,"symbol":"XBTUSD","currency":"XBt",
    "deleveragePercentile":null,"rebalancedPnl":1003,"prevRealisedPnl":-1003,"execSellQty":1,
    "execSellCost":88155,"execQty":0,"execCost":872,"execComm":131,"currentTimestamp":"2017-04-04T22:07:46.140Z",
    "currentQty":0,"currentCost":872,"currentComm":131,"realisedCost":872,"unrealisedCost":0,"grossExecCost":0,
    "isOpen":false,"markPrice":null,"markValue":0,"riskValue":0,"homeNotional":0,"foreignNotional":0,"posState":"",
    "posCost":0,"posCost2":0,"posInit":0,"posComm":0,"posMargin":0,"posMaint":0,"maintMargin":0,
    "realisedGrossPnl":-872,"realisedPnl":-1003,"unrealisedGrossPnl":0,"unrealisedPnl":0,
    "unrealisedPnlPcnt":0,"unrealisedRoePcnt":0,"simpleQty":0,"simpleCost":0,"simpleValue":0,
    "avgEntryPrice":null,"breakEvenPrice":null,"marginCallPrice":null,"liquidationPrice":null,"bankruptPrice":null,
    "timestamp":"2017-04-04T22:07:46.140Z"
   }]}

Deleverage

The following shows the deleverage of a 2000-contract XBTUSD position.

# First, the position updates to a 'posState' of 'Deleverage'.
< {"table":"position",
   "action":"update",
   "data":[{
    "account":2,"symbol":"XBTUSD","currency":"XBt","currentQty":2000,
    "markPrice":1160.72,"posState":"Deleverage","simpleQty":1.746,"liquidationPrice":1140.1,
    "timestamp":"2017-04-04T22:16:38.460Z"
   }]}

# Then, a 'Deleverage' execution is inserted. Notice the 'text'.
< {"table":"execution",
   "action":"insert",
   "data":[{
    "execID":"20ad1ff4-c110-a4f2-dd31-f94eaa0701fd",
    "orderID":"00000000-0000-0000-0000-000000000000","clOrdID":"","clOrdLinkID":"","account":2,"symbol":"XBTUSD",
    "side":"Sell","lastQty":2000,"lastPx":1160.72,"underlyingLastPx":null,"lastMkt":"XBME",
    "lastLiquidityInd":"AddedLiquidity","simpleOrderQty":null,"orderQty":2000,"price":1160.72,"displayQty":null,
    "stopPx":null,"pegOffsetValue":null,"pegPriceType":"","currency":"USD","settlCurrency":"XBt","execType":"Trade",
    "ordType":"Limit","timeInForce":"GoodTillCancel","execInst":"","contingencyType":"","exDestination":"XBME",
    "ordStatus":"Filled","triggered":"","workingIndicator":false,"ordRejReason":"",
    "simpleLeavesQty":0,"leavesQty":0,"simpleCumQty":1.746,"cumQty":2000,"avgPx":1160.72,"commission":-0.00025,
    "tradePublishIndicator":"PublishTrade","multiLegReportingType":"SingleSecurity","text":"Deleverage",
    "trdMatchID":"1e849b8a-7e88-3c67-a93f-cc654d40e8ba","execCost":172306000,"execComm":-43077,
    "homeNotional":-1.72306,"foreignNotional":2000,"transactTime":"2017-04-04T22:16:38.472Z",
    "timestamp":"2017-04-04T22:16:38.472Z"
   }]}

# Quickly thereafter, the position resets.
< {"table":"position",
   "action":"update",
   "data":[{
    "account":2,"symbol":"XBTUSD","currency":"XBt",
    "deleveragePercentile":null,"rebalancedPnl":-2171150,"prevRealisedPnl":2172153,"execSellQty":2001,
    "execSellCost":172394155,"execQty":0,"execCost":-2259128,"execComm":87978,
    "currentTimestamp":"2017-04-04T22:16:38.547Z","currentQty":0,"currentCost":-2259128,
    "currentComm":87978,"realisedCost":-2259128,"unrealisedCost":0,"grossExecCost":0,"isOpen":false,
    "markPrice":null,"markValue":0,"riskValue":0,"homeNotional":0,"foreignNotional":0,"posState":"","posCost":0,
    "posCost2":0,"posInit":0,"posComm":0,"posMargin":0,"posMaint":0,"maintMargin":0,"realisedGrossPnl":2259128,
    "realisedPnl":2171150,"unrealisedGrossPnl":0,"unrealisedPnl":0,"unrealisedPnlPcnt":0,"unrealisedRoePcnt":0,
    "simpleQty":0,"simpleCost":0,"simpleValue":0,"simplePnl":0,"simplePnlPcnt":0,
    "avgEntryPrice":null,"breakEvenPrice":null,"marginCallPrice":null,"liquidationPrice":null,"bankruptPrice":null,
    "timestamp":"2017-04-04T22:16:38.547Z"
   }]}

Instrument

The instrument data feed has some unique filters. In addition to the full instrument subscription that will get all insturments AND indices, and the specific instrument or index subscription such as instrument:XBTUSD which will just get updates on the XBTUSD contract. There are also the following filters:

  • CONTRACTS: All instruments, but no indicies
  • INDICES: All indices, but no tradeable instruments
  • DERIVATIVES: Only derivative instruments, and no indicies
  • SPOT: Only spot instruments, and no indices

In most sitiuations you should not need the full instrument feed, and we recommend purely subscribing to the instruments you need, but these should be used as helpers if all instruments are needed.

OrderBookL2

This orderbook is keyed by a unique ID, not price, so that all levels are unique across all symbols. This may be unintuitive at first but ensures that each level across the entire system is uniquely keyed.

Previously there was a scheme to extract the price from the ID as the price was not included in all updates. We are changing this and price would now be present. The ID will no longer be translatable to a price. This will be fully deprecated by May 31st 2023, please refer to announcements for more up to date information.

Here is a sample of an orderbook update:

{"table":"orderBookL2","action":"update","data":[{"symbol":"XBTUSD","id":8798952400,"side":"Sell","size":8003, "price":20.2}]}

Multiplexing

This is intended for advanced users only.

The BitMEX Websocket supports a very simple multiplexing scheme. Use this in place of many individual connections.

The most common use case is to keep a stream open for market data, and multiple streams for individual subaccounts.

Multiplexing has a different endpoint. Use /realtimemd (that’s “realtime-mux-demux”) for multiplexing capabilities.

The protocol is very simple:

Packet Format:

[<type>,<id>,<topic>,<payload>]

Definitions:

  • type: See “Packet Types” below.
  • id: Client-selected unique ID for this stream. This can be arbitrary; consider using a unique identifier like userID.
  • topic: Client-selected non-unique purpose for this stream. This is required but can be any string you wish.
    • Note: All returned messages will include the id and topic. Unsubscribing is done via id.
  • payload: For MESSAGE types, the payload is exactly equal to any message one would send via a non-multiplexed stream.

Packet Types:

  • MESSAGE: 0
    • When a stream is opened, use this type to send a message on a given topic.
  • SUBSCRIBE: 1
    • Use to open a stream. Both id and topic may contain any data but must be unique.
  • UNSUBSCRIBE: 2
    • Use to close a stream. id must match the one used for the subscription.
Example

Outgoing messages are prefixed with >. Incoming messages are prefixed with <.

# Create stream with an id of `hudsyg1q5dda4`, topic of `user_1`
> [1, "hudsyg1q5dda4", "user_1"]
# A welcome message greets you.
< [0, "hudsyg1q5dda4", "user_1",{"info":"Welcome to the BitMEX Realtime API.",...}]

# The stream is created! The stream acts exactly like any other WS connection, just framed with type and id.

# Authenticate inside that stream - see `authentication` above
> [0, "hudsyg1q5dda4", "user_1", {"op": "authKeyExpires", "args": ["pV1CPhfZWUlZM93v..."]}]
< [0, "hudsyg1q5dda4", "user_1", {"success":true}]

# Subscribe to a private table.
> [0, "hudsyg1q5dda4", "user_1", {"subscribe": "position"}]
# One message confirms the subscription,
< [0, "hudsyg1q5dda4", "user_1", {"success":true,"subscribe":"position","request":{"subscribe":"position"}}]
# And another sends the first partial.
< [0, "hudsyg1q5dda4", "user_1", {"table":"position","action":"partial","keys":["account","symbol", ...]}]

# Data will flow from here on out.

# To close a stream:
> [2, "hudsyg1q5dda4", "user_1"]
# A confirmation echo is sent from the server.
< [2, "hudsyg1q5dda4", "user_1"]

BitMEX is a P2P crypto-products trading platform.

BitMEX and the mobile apps issued under BMEX are wholly owned and operated by HDR Global Trading Limited, a Republic of Seychelles incorporated entity or its relevant authorised affiliates.

Trading in cryptocurrency derivatives involves significant risks. Please consider whether using BitMEX is appropriate for you.

Please read our Terms of Service, Risk Disclosure Statement and Privacy Notice.

US Persons are prohibited from accessing the services of the BitMEX trading platform.

Cryptocurrency charts by TradingView.