- This file is a work in progress, guidelines are being developed right now!If you want to use python or PHP language you must execute npm run export-exchanges (to ensure exchanges.js will be updated) and npm run transpile to update python and PHP exchange modules.
You can test websocket events with two sample scripts:
- examples/js/websocket-orderbook-subscription.js tests orderbook subscription/unsubscription with one ore multiple symbols: subscribe to symbol, wait 5 seconds, subscribe second symbol, ..., then unsubscribe symbol, wait 5 seconds, unsubscribe seconds symbol, ...
node examples/js/websocket-orderbook-subscription.js bitstamp None None 5 BTC/EUR- test bitstamp orderbook subscription/unsubscription on BTC/EUR symbol
node examples/js//websocket-orderbook-subscription.js bitstamp None None 5 BTC/EUR XRP/EUR- test bitstamp orderbook subscription/unsubscription on BTC/EUR and XRP/EUR symbols
- examples/js/websocket-playground.js tests websocket events: orderbook, trade, ... usage:
node examples/js/websocket-playground.js therock ob ETH/BTC- get orderbook updates of therock exchange and ETH/BTC market
node examples/js/websocket-playground.js binance ob ETH/USDT limit:5- get orderbook updates, limited to 5 bids/5 asks, of binance exchange and ETH/USDT market
- examples/js/websocket-orderbook.js subscription on one or more markets.
node examples/js/websocket-orderbook.js- print orderbook updates on bitfinex2(BTC/USDT, XRP/USDT) & binance(BTC/USDT)
node examples/js/websocket-orderbook.js config.json- print orderbook updates on subscribed markets in config.json file
{ // default config in exchange creation "exchangeDefaults": { "verbose": false }, // default config on symbol subscription "symbolDefaults": { "limit": 5 }, // config for printing market tablet "marketTable": { // markets in same row "marketsByRow": 3, // max bids/asks to print "maxLimit": 10, // characters (columns) reserved for each market "marketColumnWidth": 50, }, // dict with exchanges ids "exchanges" : { "bitfinex2" : { "symbols": { "BTC/USDT": { // config for this symbol subscription }, "XRP/USDT": { } }, "options": { // config for this exchange creation } }, "binance": { "symbols": { 'BTC/USDT':{} }, "options": { } } } }
You can find both examples in python and PHP languages:
- examples/php/websocket-playground.php
- examples/py/websocket-playground.py
And specific examples for exchanges:
- examples/py/websocket-poloniex-orderbook.py test websocket orderbook events in poloniex.
| id | name | ver | doc | WsVer | Ws doc | Ws Protocol | Ws Features | countries | |
|---|---|---|---|---|---|---|---|---|---|
![]() |
binance | Binance | * | API | API | raw | ob ti tr oh | Japan | |
![]() |
bitfinex2 | Bitfinex v2 | 2 | API | raw | ob | British Virgin Islands | ||
![]() |
bitmex | BitMEX | 1 | API | API | raw | ob | Seychelles | |
![]() |
bitstamp | Bitstamp | 2 | API | pusher | ob | UK | ||
![]() |
bittrex | Bittrex | 1.1 | API | signalr | ob | US | ||
![]() |
cex | CEX.IO | * | API | API | raw | ob | UK, EU, Cyprus, Russia | |
![]() |
cobinhood | COBINHOOD | 1 | API | raw | ob ti tr oh | Taiwan | ||
![]() |
coincheck | coincheck | * | API | API | raw | ob | Japan, Indonesia | |
![]() |
coinbaseprime | Coinbase Prime | * | API | raw | ob | US | ||
![]() |
coinbasepro | Coinbase Pro | * | API | raw | ob | US | ||
![]() |
gateio | Gate.io | 2 | API | API | raw | ob | China | |
![]() |
gemini | Gemini | 1 | API | raw | ob | US | ||
![]() |
hadax | HADAX | 1 | API | raw | ob | China | ||
![]() |
hitbtc2 | HitBTC v2 | 2 | API | API | raw | ob | Hong Kong | |
![]() |
huobipro | Huobi Pro | 1 | API | API | raw | ob | China | |
![]() |
kraken | Kraken | 0 | API | raw | ob | US | ||
![]() |
lbank | LBank | 1 | API | raw | ob | China | ||
![]() |
liquid | Liquid | 2 | API | pusher | ob | Japan, China, Taiwan | ||
![]() |
okex | OKEX | 1 | API | API | raw | ob | China, US | |
![]() |
poloniex | Poloniex | * | API | raw | ob | US | ||
![]() |
theocean | The Ocean | 0 | API | socketio | ob | US | ||
![]() |
therock | TheRockTrading | 1 | API | pusher | ob | Malta | ||
![]() |
upbit | Upbit | 1 | API | raw | ob ti tr | South Korea | ||
![]() |
zb | ZB | 1 | API | API | raw | ob | China |
Ws protocol
- raw: supported in this ccxt branch
- pusher: testing
Ws Features:
- ob: orderbook
- ti: tickers
- tr: trades
- oh: ohlcv
Only two types of websocket connections are supported:
- Connections that expects you send a subscribing command to receive data updates,
- connections that receive updates just after connected.
...
'wsconf': {
'conx-tpls': {
'default': {
'type': 'ws',
'baseurl': 'wss://api.zb.com:9999/websocket',
},
},
'methodmap': {
'_asyncTimeoutRemoveNonce': '_asyncTimeoutRemoveNonce',
},
'events': {
'ob': {
'conx-tpl': 'default',
'conx-param': {
'url': '{baseurl}',
'id': '{id}',
},
},
},
},
...- conx-tpls: dictionary with exchange websocket connections. Most exchanges only have one connection. You can use any id for this connection, but 'default' is used for now. For each connection you mus define:
- type: 'ws'|'ws-s' for connections that expect a subscribing command or connections with updates after connected, respectively.
- baseurl: the baseurl for exchange websocket.
- methodmap: this is a hack to convert a method from 'camel' format to 'snake' format, used in php & python transpiled code. Is is usefull when you need to invoke a class method with a string.
- events: dictionary with events or update types received from exchange:
- 'ob' for orderbook updates,
- 'ticker' for ticker,
- 'trade' for trades,
- ...
For each event you must define the connection that provide it:
- conx-tpl: id of the websocket connection defined in 'conx-tpls'.
- conx-param: additional config for websocket:
- url: url to connecto to
- id: internl id for the connection
In each generator you can use variables between braces {}:
- {baseurl}: replace with baseurl value in 'conx-tpls' definitions,
- {id}: replace with key id in 'conx-tpls' dictionary.
You must define some exchange methods in .js file:
- _websocketSubscribe(contextId, event, symbol, nonce, params): required, called from Exchange.js when user invoke an event subscription. contextId is the websocket internal id used to access context data. event must be 'ob'|'ticket'|'trade'|'ohlcv', symbol is the symbol, and nonce and internal and unique id . If this exchange does not support this event you must throw a NotSupported exception. If exchange websocket type is 'ws', you must send the subscription command for this exchange and save the nonce id and use it when you receive a subscription response from exchange. params recives a dictionary with optional params for each exchange subscription. If the subscription succeeds then you must invoke emit method with nonce parameter:
this.emit(nonce, true). If the subscription fails you must invoke emit method with the error (optional):this.emit(nonce, false, new ExchangeException('...')). - _websocketUnsubscribe(contextId event, symbol, nonce, params): required, same as bellow but for unsubscription process.
- _websocketOnMessage(contextId, data): required, this method is called when a message is received from websocket. data is the raw data received and contextId is the websocket internal id that receives the message used for access context data.
- _websocketOnClose(contextId): optional, this is called when websocket is closed. contextId is the websocket internal id.
- _websocketOnError(contetId, error): opetional, and it is called when an error takes place in the websocket connection.
- _websocketOnOpen(conextId, websocketConexConfig): optional, this is called from Exchange.js when websocket is opened and connected. contextId is the opened websocket internal id and websocketConexConfig the initialization config of this websocket. You can use this method in 'ws-s' websockets to set 'subscribed' status:
...
for (let symbol in streams) {
this._contextSetSubscribed ('ob', symbol, true);
this._contextSetSubscribing('ob', symbol, false);
}
...Cex orderbook subscription command.
let [currencyBase, currencyQuote] = symbol.split ('/');
this.asyncSendJson ({
'e': 'order-book-subscribe',
'data': {
'pair': [currencyBase, currencyQuote],
'subscribe': true,
'depth': 0,
},
'oid': nonce,
});Methods to access context data for each websocket:
- _contextSetSubscribed (conxid, event, symbol, subscribed): returns subscribed status for event/symbol
- _contextIsSubscribed (conxid, event, symbol): set subscribed status for event/symbol
- _contextSetSubscribing (conxid, event, symbol, subscribing): returns subscribing status for event/symbol
- _contextIsSubscribing (conxid, event, symbol): set subscribing status for event/symbol
- _contextGetSymbolData(conxid, event, symbol): get symbol user defined dictionary
- _contextSetSymbolData(conxid, event, symbol, data): set symbol user defined dictionary
- _contextSet (conxid, key, data): set data to user defined dictionary (to store any user defined data)
- _contextGet (conxid, key): get from user defined dictionary
- _contextGetEvents(conxid): get events dictionary ('ob', 'tickers', ...)
- _contextGetSymbols(conxid, event): get symbols from event
- _contextResetEvent(conxid, event): reset event dictionary
- _contextResetSymbol(conxid, event, symbol): reset symbol dictionary (
{'subscribed': false, 'subscribing': false, 'data':{}})
...
,
'wsconf': {
'conx-tpls': {
'default': {
'type': 'ws',
'baseurl': 'wss://real.okex.com:10441/websocket',
},
},
'methodmap': {
},
'events': {
'ob': {
'conx-tpl': 'default',
'conx-param': {
'url': '{baseurl}',
'id': '{id}',
},
},
},
}
...
_websocketOnMsg (contextId, data) {
let msg = JSON.parse (data);
console.log(msg);
}
_websocketSubscribe (contextId, event, symbol, nonce, params = {}) {
if (event !== 'ob') {
throw new NotSupported ('subscribe ' + event + '(' + symbol + ') not supported for exchange ' + this.id);
}
let data = this._contextGetSymbolData (contextId, 'ob', symbol);
data['limit'] = this.safeInteger (params, 'limit', undefined);
this._contextSetSymbolData (contextId, 'ob', symbol, data);
this.websocketSendJson ({
event: 'addChannel',
channel: 'ok_sub_spot_' + pairId + '_depth',
});
}
_websocketunSubscribe (contextId, event, symbol, nonce, params = {}) {
if (event !== 'ob') {
throw new NotSupported ('subscribe ' + event + '(' + symbol + ') not supported for exchange ' + this.id);
}
this.websocketSendJson ({
event: 'removeChannel',
channel: 'ok_sub_spot_' + pairId + '_depth',
});
}- node: pako, ws
- php: ratchet/pawl, clue/block-react
- python: autobahn, pyee























