ccxt 4.3.44 → 4.3.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +130 -130
  2. package/dist/ccxt.browser.min.js +3 -3
  3. package/dist/cjs/ccxt.js +6 -1
  4. package/dist/cjs/src/abstract/oxfun.js +9 -0
  5. package/dist/cjs/src/base/Exchange.js +1 -0
  6. package/dist/cjs/src/binance.js +2 -0
  7. package/dist/cjs/src/bingx.js +25 -17
  8. package/dist/cjs/src/bitmart.js +5 -0
  9. package/dist/cjs/src/bitstamp.js +18 -2
  10. package/dist/cjs/src/bitteam.js +5 -7
  11. package/dist/cjs/src/coinmetro.js +8 -17
  12. package/dist/cjs/src/hyperliquid.js +29 -21
  13. package/dist/cjs/src/idex.js +1 -0
  14. package/dist/cjs/src/kucoin.js +28 -1
  15. package/dist/cjs/src/luno.js +9 -1
  16. package/dist/cjs/src/mexc.js +8 -6
  17. package/dist/cjs/src/okx.js +1 -0
  18. package/dist/cjs/src/oxfun.js +2900 -0
  19. package/dist/cjs/src/pro/binanceus.js +0 -8
  20. package/dist/cjs/src/pro/oxfun.js +1034 -0
  21. package/dist/cjs/src/tokocrypto.js +8 -10
  22. package/dist/cjs/src/wavesexchange.js +122 -110
  23. package/dist/cjs/src/woofipro.js +1 -0
  24. package/dist/cjs/src/xt.js +1 -1
  25. package/js/ccxt.d.ts +8 -2
  26. package/js/ccxt.js +6 -2
  27. package/js/src/abstract/binance.d.ts +2 -0
  28. package/js/src/abstract/binancecoinm.d.ts +2 -0
  29. package/js/src/abstract/binanceus.d.ts +2 -0
  30. package/js/src/abstract/binanceusdm.d.ts +2 -0
  31. package/js/src/abstract/bitstamp.d.ts +16 -0
  32. package/js/src/abstract/kucoin.d.ts +14 -0
  33. package/js/src/abstract/kucoinfutures.d.ts +14 -0
  34. package/js/src/abstract/mexc.d.ts +2 -0
  35. package/js/src/abstract/oxfun.d.ts +37 -0
  36. package/js/src/abstract/oxfun.js +11 -0
  37. package/js/src/base/Exchange.d.ts +1 -0
  38. package/js/src/base/Exchange.js +1 -0
  39. package/js/src/binance.js +2 -0
  40. package/js/src/bingx.js +26 -18
  41. package/js/src/bitmart.js +5 -0
  42. package/js/src/bitstamp.js +18 -2
  43. package/js/src/bitteam.js +6 -8
  44. package/js/src/coinmetro.js +9 -18
  45. package/js/src/hyperliquid.d.ts +3 -3
  46. package/js/src/hyperliquid.js +29 -21
  47. package/js/src/idex.js +1 -0
  48. package/js/src/kucoin.js +28 -1
  49. package/js/src/luno.d.ts +1 -1
  50. package/js/src/luno.js +9 -1
  51. package/js/src/mexc.js +8 -6
  52. package/js/src/okx.js +1 -0
  53. package/js/src/oxfun.d.ts +129 -0
  54. package/js/src/oxfun.js +2901 -0
  55. package/js/src/pro/binanceus.js +0 -8
  56. package/js/src/pro/oxfun.d.ts +38 -0
  57. package/js/src/pro/oxfun.js +1035 -0
  58. package/js/src/static_dependencies/jsencrypt/lib/jsbn/jsbn.d.ts +1 -1
  59. package/js/src/tokocrypto.js +9 -11
  60. package/js/src/wavesexchange.d.ts +7 -7
  61. package/js/src/wavesexchange.js +123 -111
  62. package/js/src/woofipro.js +1 -0
  63. package/js/src/xt.js +1 -1
  64. package/package.json +1 -1
@@ -0,0 +1,1035 @@
1
+ // ----------------------------------------------------------------------------
2
+
3
+ // PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
4
+ // https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
5
+ // EDIT THE CORRESPONDENT .ts FILE INSTEAD
6
+
7
+ // ---------------------------------------------------------------------------
8
+ import oxfunRest from '../oxfun.js';
9
+ import { ArgumentsRequired, AuthenticationError, BadRequest } from '../base/errors.js';
10
+ import { sha256 } from '../static_dependencies/noble-hashes/sha256.js';
11
+ import { ArrayCache, ArrayCacheBySymbolById, ArrayCacheBySymbolBySide, ArrayCacheByTimestamp } from '../base/ws/Cache.js';
12
+ // ---------------------------------------------------------------------------
13
+ export default class oxfun extends oxfunRest {
14
+ describe() {
15
+ return this.deepExtend(super.describe(), {
16
+ 'has': {
17
+ 'ws': true,
18
+ 'watchTrades': true,
19
+ 'watchTradesForSymbols': true,
20
+ 'watchOrderBook': true,
21
+ 'watchOrderBookForSymbols': true,
22
+ 'watchOHLCV': true,
23
+ 'watchOHLCVForSymbols': true,
24
+ 'watchOrders': true,
25
+ 'watchMyTrades': false,
26
+ 'watchTicker': true,
27
+ 'watchTickers': true,
28
+ 'watchBalance': true,
29
+ 'createOrderWs': true,
30
+ 'editOrderWs': true,
31
+ 'cancelOrderWs': true,
32
+ 'cancelOrdersWs': true,
33
+ },
34
+ 'urls': {
35
+ 'api': {
36
+ 'ws': 'wss://api.ox.fun/v2/websocket',
37
+ 'test': 'wss://stgapi.ox.fun/v2/websocket',
38
+ },
39
+ },
40
+ 'options': {
41
+ 'timeframes': {
42
+ '1m': '60s',
43
+ '3m': '180s',
44
+ '5m': '300s',
45
+ '15m': '900s',
46
+ '30m': '1800s',
47
+ '1h': '3600s',
48
+ '2h': '7200s',
49
+ '4h': '14400s',
50
+ '6h': '21600s',
51
+ '12h': '43200s',
52
+ '1d': '86400s',
53
+ },
54
+ 'watchOrderBook': {
55
+ 'channel': 'depth', // depth, depthL5, depthL10, depthL25
56
+ },
57
+ },
58
+ 'streaming': {
59
+ 'ping': this.ping,
60
+ 'keepAlive': 50000,
61
+ },
62
+ });
63
+ }
64
+ async subscribeMultiple(messageHashes, argsArray, params = {}) {
65
+ const url = this.urls['api']['ws'];
66
+ const request = {
67
+ 'op': 'subscribe',
68
+ 'args': argsArray,
69
+ };
70
+ return await this.watchMultiple(url, messageHashes, this.extend(request, params), messageHashes);
71
+ }
72
+ async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
73
+ /**
74
+ * @method
75
+ * @name oxfun#watchTrades
76
+ * @description watches information on multiple trades made in a market
77
+ * @see https://docs.ox.fun/?json#trade
78
+ * @param {string} symbol unified market symbol of the market trades were made in
79
+ * @param {int} [since] the earliest time in ms to fetch orders for
80
+ * @param {int} [limit] the maximum number of trade structures to retrieve
81
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
82
+ * @param {int|string} [params.tag] If given it will be echoed in the reply and the max size of tag is 32
83
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure
84
+ */
85
+ return await this.watchTradesForSymbols([symbol], since, limit, params);
86
+ }
87
+ async watchTradesForSymbols(symbols, since = undefined, limit = undefined, params = {}) {
88
+ /**
89
+ * @method
90
+ * @name oxfun#watchTradesForSymbols
91
+ * @description get the list of most recent trades for a particular symbol
92
+ * @see https://docs.ox.fun/?json#trade
93
+ * @param {string} symbol unified symbol of the market to fetch trades for
94
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
95
+ * @param {int} [limit] the maximum amount of trades to fetch
96
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
97
+ * @param {int|string} [params.tag] If given it will be echoed in the reply and the max size of tag is 32
98
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
99
+ */
100
+ await this.loadMarkets();
101
+ symbols = this.marketSymbols(symbols, undefined, false);
102
+ const args = [];
103
+ const messageHashes = [];
104
+ for (let i = 0; i < symbols.length; i++) {
105
+ const symbol = symbols[i];
106
+ const messageHash = 'trades' + ':' + symbol;
107
+ messageHashes.push(messageHash);
108
+ const marketId = this.marketId(symbol);
109
+ const arg = 'trade:' + marketId;
110
+ args.push(arg);
111
+ }
112
+ const trades = await this.subscribeMultiple(messageHashes, args, params);
113
+ if (this.newUpdates) {
114
+ const first = this.safeDict(trades, 0, {});
115
+ const tradeSymbol = this.safeString(first, 'symbol');
116
+ limit = trades.getLimit(tradeSymbol, limit);
117
+ }
118
+ return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
119
+ }
120
+ handleTrades(client, message) {
121
+ //
122
+ // {
123
+ // table: 'trade',
124
+ // data: [
125
+ // {
126
+ // side: 'SELL',
127
+ // quantity: '0.074',
128
+ // matchType: 'TAKER',
129
+ // price: '3079.5',
130
+ // marketCode: 'ETH-USD-SWAP-LIN',
131
+ // tradeId: '400017157974517783',
132
+ // timestamp: '1716124156643'
133
+ // }
134
+ // ]
135
+ // }
136
+ //
137
+ const data = this.safeList(message, 'data', []);
138
+ for (let i = 0; i < data.length; i++) {
139
+ const trade = this.safeDict(data, i, {});
140
+ const parsedTrade = this.parseWsTrade(trade);
141
+ const symbol = this.safeString(parsedTrade, 'symbol');
142
+ const messageHash = 'trades:' + symbol;
143
+ if (!(symbol in this.trades)) {
144
+ const tradesLimit = this.safeInteger(this.options, 'tradesLimit', 1000);
145
+ this.trades[symbol] = new ArrayCache(tradesLimit);
146
+ }
147
+ const stored = this.trades[symbol];
148
+ stored.append(parsedTrade);
149
+ client.resolve(stored, messageHash);
150
+ }
151
+ }
152
+ parseWsTrade(trade, market = undefined) {
153
+ //
154
+ // {
155
+ // side: 'SELL',
156
+ // quantity: '0.074',
157
+ // matchType: 'TAKER',
158
+ // price: '3079.5',
159
+ // marketCode: 'ETH-USD-SWAP-LIN',
160
+ // tradeId: '400017157974517783',
161
+ // timestamp: '1716124156643'
162
+ // }
163
+ //
164
+ const marketId = this.safeString(trade, 'marketCode');
165
+ market = this.safeMarket(marketId, market);
166
+ const timestamp = this.safeInteger(trade, 'timestamp');
167
+ return this.safeTrade({
168
+ 'info': trade,
169
+ 'timestamp': timestamp,
170
+ 'datetime': this.iso8601(timestamp),
171
+ 'symbol': market['symbol'],
172
+ 'id': this.safeString(trade, 'tradeId'),
173
+ 'order': undefined,
174
+ 'type': undefined,
175
+ 'takerOrMaker': this.safeStringLower(trade, 'matchType'),
176
+ 'side': this.safeStringLower(trade, 'side'),
177
+ 'price': this.safeNumber(trade, 'price'),
178
+ 'amount': this.safeNumber(trade, 'quantity'),
179
+ 'cost': undefined,
180
+ 'fee': undefined,
181
+ });
182
+ }
183
+ async watchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
184
+ /**
185
+ * @method
186
+ * @name oxfun#watchOHLCV
187
+ * @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
188
+ * @see https://docs.ox.fun/?json#candles
189
+ * @param {string} symbol unified symbol of the market to fetch OHLCV data for
190
+ * @param {string} timeframe the length of time each candle represents
191
+ * @param {int} [since] timestamp in ms of the earliest candle to fetch
192
+ * @param {int} [limit] the maximum amount of candles to fetch
193
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
194
+ * @param {int|string} [params.tag] If given it will be echoed in the reply and the max size of tag is 32
195
+ * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
196
+ */
197
+ await this.loadMarkets();
198
+ const market = this.market(symbol);
199
+ const timeframes = this.safeDict(this.options, 'timeframes', {});
200
+ const interval = this.safeString(timeframes, timeframe, timeframe);
201
+ const args = 'candles' + interval + ':' + market['id'];
202
+ const messageHash = 'ohlcv:' + symbol + ':' + timeframe;
203
+ const url = this.urls['api']['ws'];
204
+ const request = {
205
+ 'op': 'subscribe',
206
+ 'args': [args],
207
+ };
208
+ const ohlcvs = await this.watch(url, messageHash, this.extend(request, params), messageHash);
209
+ if (this.newUpdates) {
210
+ limit = ohlcvs.getLimit(symbol, limit);
211
+ }
212
+ return this.filterBySinceLimit(ohlcvs, since, limit, 0, true);
213
+ }
214
+ async watchOHLCVForSymbols(symbolsAndTimeframes, since = undefined, limit = undefined, params = {}) {
215
+ /**
216
+ * @method
217
+ * @name oxfun#watchOHLCVForSymbols
218
+ * @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
219
+ * @see https://docs.ox.fun/?json#candles
220
+ * @param {string[][]} symbolsAndTimeframes array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
221
+ * @param {int} [since] timestamp in ms of the earliest candle to fetch
222
+ * @param {int} [limit] the maximum amount of candles to fetch
223
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
224
+ * @param {int|string} [params.tag] If given it will be echoed in the reply and the max size of tag is 32
225
+ * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
226
+ */
227
+ const symbolsLength = symbolsAndTimeframes.length;
228
+ if (symbolsLength === 0 || !Array.isArray(symbolsAndTimeframes[0])) {
229
+ throw new ArgumentsRequired(this.id + " watchOHLCVForSymbols() requires a an array of symbols and timeframes, like [['BTC/USDT:OX', '1m'], ['OX/USDT', '5m']]");
230
+ }
231
+ await this.loadMarkets();
232
+ const args = [];
233
+ const messageHashes = [];
234
+ const timeframes = this.safeDict(this.options, 'timeframes', {});
235
+ for (let i = 0; i < symbolsAndTimeframes.length; i++) {
236
+ const symbolAndTimeframe = symbolsAndTimeframes[i];
237
+ const sym = symbolAndTimeframe[0];
238
+ const tf = symbolAndTimeframe[1];
239
+ const marketId = this.marketId(sym);
240
+ const interval = this.safeString(timeframes, tf, tf);
241
+ const arg = 'candles' + interval + ':' + marketId;
242
+ args.push(arg);
243
+ const messageHash = 'multi:ohlcv:' + sym + ':' + tf;
244
+ messageHashes.push(messageHash);
245
+ }
246
+ const [symbol, timeframe, candles] = await this.subscribeMultiple(messageHashes, args, params);
247
+ if (this.newUpdates) {
248
+ limit = candles.getLimit(symbol, limit);
249
+ }
250
+ const filtered = this.filterBySinceLimit(candles, since, limit, 0, true);
251
+ return this.createOHLCVObject(symbol, timeframe, filtered);
252
+ }
253
+ handleOHLCV(client, message) {
254
+ //
255
+ // {
256
+ // "table": "candles60s",
257
+ // "data": [
258
+ // {
259
+ // "marketCode": "BTC-USD-SWAP-LIN",
260
+ // "candle": [
261
+ // "1594313762698", //timestamp
262
+ // "9633.1", //open
263
+ // "9693.9", //high
264
+ // "9238.1", //low
265
+ // "9630.2", //close
266
+ // "45247", //volume in OX
267
+ // "5.3" //volume in Contracts
268
+ // ]
269
+ // }
270
+ // ]
271
+ // }
272
+ //
273
+ const table = this.safeString(message, 'table');
274
+ const parts = table.split('candles');
275
+ const timeframeId = this.safeString(parts, 1, '');
276
+ const timeframe = this.findTimeframe(timeframeId);
277
+ const messageData = this.safeList(message, 'data', []);
278
+ const data = this.safeDict(messageData, 0, {});
279
+ const marketId = this.safeString(data, 'marketCode');
280
+ const market = this.safeMarket(marketId);
281
+ const symbol = this.safeSymbol(marketId, market);
282
+ if (!(symbol in this.ohlcvs)) {
283
+ this.ohlcvs[symbol] = {};
284
+ }
285
+ if (!(timeframe in this.ohlcvs[symbol])) {
286
+ const limit = this.safeInteger(this.options, 'OHLCVLimit', 1000);
287
+ this.ohlcvs[symbol][timeframe] = new ArrayCacheByTimestamp(limit);
288
+ }
289
+ const candle = this.safeList(data, 'candle', []);
290
+ const parsed = this.parseWsOHLCV(candle, market);
291
+ const stored = this.ohlcvs[symbol][timeframe];
292
+ stored.append(parsed);
293
+ const messageHash = 'ohlcv:' + symbol + ':' + timeframe;
294
+ client.resolve(stored, messageHash);
295
+ // for multiOHLCV we need special object, as opposed to other "multi"
296
+ // methods, because OHLCV response item does not contain symbol
297
+ // or timeframe, thus otherwise it would be unrecognizable
298
+ const messageHashForMulti = 'multi:' + messageHash;
299
+ client.resolve([symbol, timeframe, stored], messageHashForMulti);
300
+ }
301
+ parseWsOHLCV(ohlcv, market = undefined) {
302
+ //
303
+ // [
304
+ // "1594313762698", //timestamp
305
+ // "9633.1", //open
306
+ // "9693.9", //high
307
+ // "9238.1", //low
308
+ // "9630.2", //close
309
+ // "45247", //volume in OX
310
+ // "5.3" //volume in Contracts
311
+ // ]
312
+ //
313
+ return [
314
+ this.safeInteger(ohlcv, 0),
315
+ this.safeNumber(ohlcv, 1),
316
+ this.safeNumber(ohlcv, 2),
317
+ this.safeNumber(ohlcv, 3),
318
+ this.safeNumber(ohlcv, 4),
319
+ this.safeNumber(ohlcv, 6),
320
+ ];
321
+ }
322
+ async watchOrderBook(symbol, limit = undefined, params = {}) {
323
+ /**
324
+ * @method
325
+ * @name oxfun#watchOrderBook
326
+ * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
327
+ * @see https://docs.ox.fun/?json#fixed-size-order-book
328
+ * @see https://docs.ox.fun/?json#full-order-book
329
+ * @param {string} symbol unified symbol of the market to fetch the order book for
330
+ * @param {int} [limit] the maximum amount of order book entries to return
331
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
332
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
333
+ */
334
+ return await this.watchOrderBookForSymbols([symbol], limit, params);
335
+ }
336
+ async watchOrderBookForSymbols(symbols, limit = undefined, params = {}) {
337
+ /**
338
+ * @method
339
+ * @name oxfun#watchOrderBookForSymbols
340
+ * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
341
+ * @see https://docs.ox.fun/?json#fixed-size-order-book
342
+ * @see https://docs.ox.fun/?json#full-order-book
343
+ * @param {string[]} symbols unified array of symbols
344
+ * @param {int} [limit] the maximum amount of order book entries to return
345
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
346
+ * @param {int|string} [params.tag] If given it will be echoed in the reply and the max size of tag is 32
347
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
348
+ */
349
+ await this.loadMarkets();
350
+ symbols = this.marketSymbols(symbols);
351
+ let channel = 'depth';
352
+ const options = this.safeDict(this.options, 'watchOrderBook', {});
353
+ const defaultChannel = this.safeString(options, 'channel');
354
+ if (defaultChannel !== undefined) {
355
+ channel = defaultChannel;
356
+ }
357
+ else if (limit !== undefined) {
358
+ if (limit <= 5) {
359
+ channel = 'depthL5';
360
+ }
361
+ else if (limit <= 10) {
362
+ channel = 'depthL10';
363
+ }
364
+ else if (limit <= 25) {
365
+ channel = 'depthL25';
366
+ }
367
+ }
368
+ const args = [];
369
+ const messageHashes = [];
370
+ for (let i = 0; i < symbols.length; i++) {
371
+ const symbol = symbols[i];
372
+ const messageHash = 'orderbook:' + symbol;
373
+ messageHashes.push(messageHash);
374
+ const marketId = this.marketId(symbol);
375
+ const arg = channel + ':' + marketId;
376
+ args.push(arg);
377
+ }
378
+ const orderbook = await this.subscribeMultiple(messageHashes, args, params);
379
+ return orderbook.limit();
380
+ }
381
+ handleOrderBook(client, message) {
382
+ //
383
+ // {
384
+ // "table": "depth",
385
+ // "data": {
386
+ // "seqNum": "100170478917895032",
387
+ // "asks": [
388
+ // [ 0.01, 100500 ],
389
+ // ...
390
+ // ],
391
+ // "bids": [
392
+ // [ 69.69696, 69 ],
393
+ // ...
394
+ // ],
395
+ // "checksum": 261021645,
396
+ // "marketCode": "OX-USDT",
397
+ // "timestamp": 1716204786184
398
+ // },
399
+ // "action": "partial"
400
+ // }
401
+ //
402
+ const data = this.safeDict(message, 'data', {});
403
+ const marketId = this.safeString(data, 'marketCode');
404
+ const symbol = this.safeSymbol(marketId);
405
+ const timestamp = this.safeInteger(data, 'timestamp');
406
+ const messageHash = 'orderbook:' + symbol;
407
+ if (!(symbol in this.orderbooks)) {
408
+ this.orderbooks[symbol] = this.orderBook({});
409
+ }
410
+ const orderbook = this.orderbooks[symbol];
411
+ const snapshot = this.parseOrderBook(data, symbol, timestamp, 'asks', 'bids');
412
+ orderbook.reset(snapshot);
413
+ orderbook['nonce'] = this.safeInteger(data, 'seqNum');
414
+ this.orderbooks[symbol] = orderbook;
415
+ client.resolve(orderbook, messageHash);
416
+ }
417
+ async watchTicker(symbol, params = {}) {
418
+ /**
419
+ * @method
420
+ * @name oxfun#watchTicker
421
+ * @see https://docs.ox.fun/?json#ticker
422
+ * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
423
+ * @param {string} symbol unified symbol of the market to fetch the ticker for
424
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
425
+ * @param {int|string} [params.tag] If given it will be echoed in the reply and the max size of tag is 32
426
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
427
+ */
428
+ const ticker = await this.watchTickers([symbol], params);
429
+ return this.safeValue(ticker, symbol);
430
+ }
431
+ async watchTickers(symbols = undefined, params = {}) {
432
+ /**
433
+ * @method
434
+ * @name oxfun#watchTickers
435
+ * @see https://docs.ox.fun/?json#ticker
436
+ * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
437
+ * @param {string[]} [symbols] unified symbol of the market to fetch the ticker for
438
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
439
+ * @param {int|string} [params.tag] If given it will be echoed in the reply and the max size of tag is 32
440
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
441
+ */
442
+ await this.loadMarkets();
443
+ const allSymbols = (symbols === undefined);
444
+ let sym = symbols;
445
+ const args = [];
446
+ if (allSymbols) {
447
+ sym = this.symbols;
448
+ args.push('ticker:all');
449
+ }
450
+ const messageHashes = [];
451
+ for (let i = 0; i < sym.length; i++) {
452
+ const symbol = sym[i];
453
+ const messageHash = 'tickers' + ':' + symbol;
454
+ messageHashes.push(messageHash);
455
+ const marketId = this.marketId(symbol);
456
+ if (!allSymbols) {
457
+ args.push('ticker:' + marketId);
458
+ }
459
+ }
460
+ const newTicker = await this.subscribeMultiple(messageHashes, args, params);
461
+ if (this.newUpdates) {
462
+ const result = {};
463
+ result[newTicker['symbol']] = newTicker;
464
+ return result;
465
+ }
466
+ return this.filterByArray(this.tickers, 'symbol', symbols);
467
+ }
468
+ handleTicker(client, message) {
469
+ //
470
+ // {
471
+ // "table": "ticker",
472
+ // "data": [
473
+ // {
474
+ // "last": "3088.6",
475
+ // "open24h": "3087.2",
476
+ // "high24h": "3142.0",
477
+ // "low24h": "3053.9",
478
+ // "volume24h": "450512672.1800",
479
+ // "currencyVolume24h": "1458.579",
480
+ // "openInterest": "3786.801",
481
+ // "marketCode": "ETH-USD-SWAP-LIN",
482
+ // "timestamp": "1716212747050",
483
+ // "lastQty": "0.813",
484
+ // "markPrice": "3088.6",
485
+ // "lastMarkPrice": "3088.6",
486
+ // "indexPrice": "3086.5"
487
+ // },
488
+ // ...
489
+ // ]
490
+ // }
491
+ //
492
+ const data = this.safeList(message, 'data', []);
493
+ for (let i = 0; i < data.length; i++) {
494
+ const rawTicker = this.safeDict(data, i, {});
495
+ const ticker = this.parseTicker(rawTicker);
496
+ const symbol = ticker['symbol'];
497
+ const messageHash = 'tickers:' + symbol;
498
+ this.tickers[symbol] = ticker;
499
+ client.resolve(ticker, messageHash);
500
+ }
501
+ }
502
+ async watchBalance(params = {}) {
503
+ /**
504
+ * @method
505
+ * @name oxfun#watchBalance
506
+ * @see https://docs.ox.fun/?json#balance-channel
507
+ * @description watch balance and get the amount of funds available for trading or funds locked in orders
508
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
509
+ * @param {int|string} [params.tag] If given it will be echoed in the reply and the max size of tag is 32
510
+ * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
511
+ */
512
+ await this.loadMarkets();
513
+ this.authenticate();
514
+ const args = 'balance:all';
515
+ const messageHash = 'balance';
516
+ const url = this.urls['api']['ws'];
517
+ const request = {
518
+ 'op': 'subscribe',
519
+ 'args': [args],
520
+ };
521
+ return await this.watch(url, messageHash, this.extend(request, params), messageHash);
522
+ }
523
+ handleBalance(client, message) {
524
+ //
525
+ // {
526
+ // "table": "balance",
527
+ // "accountId": "106464",
528
+ // "timestamp": "1716549132780",
529
+ // "tradeType": "PORTFOLIO",
530
+ // "data": [
531
+ // {
532
+ // "instrumentId": "xOX",
533
+ // "total": "23.375591220",
534
+ // "available": "23.375591220",
535
+ // "reserved": "0",
536
+ // "quantityLastUpdated": "1716509744262",
537
+ // "locked": "0"
538
+ // },
539
+ // ...
540
+ // ]
541
+ // }
542
+ //
543
+ const balances = this.safeList(message, 'data');
544
+ const timestamp = this.safeInteger(message, 'timestamp');
545
+ this.balance['info'] = message;
546
+ this.balance['timestamp'] = timestamp;
547
+ this.balance['datetime'] = this.iso8601(timestamp);
548
+ for (let i = 0; i < balances.length; i++) {
549
+ const balance = this.safeDict(balances, i, {});
550
+ const currencyId = this.safeString(balance, 'instrumentId');
551
+ const code = this.safeCurrencyCode(currencyId);
552
+ if (!(code in this.balance)) {
553
+ this.balance[code] = this.account();
554
+ }
555
+ const account = this.balance[code];
556
+ account['total'] = this.safeString(balance, 'total');
557
+ account['used'] = this.safeString(balance, 'reserved');
558
+ account['free'] = this.safeString(balance, 'available');
559
+ this.balance[code] = account;
560
+ }
561
+ this.balance = this.safeBalance(this.balance);
562
+ client.resolve(this.balance, 'balance');
563
+ }
564
+ async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
565
+ /**
566
+ * @method
567
+ * @name oxfun#watchPositions
568
+ * @see https://docs.ox.fun/?json#position-channel
569
+ * @description watch all open positions
570
+ * @param {string[]|undefined} symbols list of unified market symbols
571
+ * @param {object} params extra parameters specific to the exchange API endpoint
572
+ * @param {int|string} [params.tag] If given it will be echoed in the reply and the max size of tag is 32
573
+ * @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
574
+ */
575
+ await this.loadMarkets();
576
+ await this.authenticate();
577
+ const allSymbols = (symbols === undefined);
578
+ let sym = symbols;
579
+ const args = [];
580
+ if (allSymbols) {
581
+ sym = this.symbols;
582
+ args.push('position:all');
583
+ }
584
+ const messageHashes = [];
585
+ for (let i = 0; i < sym.length; i++) {
586
+ const symbol = sym[i];
587
+ const messageHash = 'positions' + ':' + symbol;
588
+ messageHashes.push(messageHash);
589
+ const marketId = this.marketId(symbol);
590
+ if (!allSymbols) {
591
+ args.push('position:' + marketId);
592
+ }
593
+ }
594
+ const newPositions = await this.subscribeMultiple(messageHashes, args, params);
595
+ if (this.newUpdates) {
596
+ return newPositions;
597
+ }
598
+ return this.filterBySymbolsSinceLimit(this.positions, symbols, since, limit, true);
599
+ }
600
+ handlePositions(client, message) {
601
+ //
602
+ // {
603
+ // "table": "position",
604
+ // "accountId": "106464",
605
+ // "timestamp": "1716550771582",
606
+ // "data": [
607
+ // {
608
+ // "instrumentId": "ETH-USD-SWAP-LIN",
609
+ // "quantity": "0.01",
610
+ // "lastUpdated": "1716550757299",
611
+ // "contractValCurrency": "ETH",
612
+ // "entryPrice": "3709.6",
613
+ // "positionPnl": "-5.000",
614
+ // "estLiquidationPrice": "743.4",
615
+ // "margin": "0",
616
+ // "leverage": "0"
617
+ // }
618
+ // ]
619
+ // }
620
+ //
621
+ if (this.positions === undefined) {
622
+ this.positions = new ArrayCacheBySymbolBySide();
623
+ }
624
+ const cache = this.positions;
625
+ const data = this.safeList(message, 'data', []);
626
+ for (let i = 0; i < data.length; i++) {
627
+ const rawPosition = this.safeDict(data, i, {});
628
+ const position = this.parseWsPosition(rawPosition);
629
+ const symbol = position['symbol'];
630
+ const messageHash = 'positions:' + symbol;
631
+ cache.append(position);
632
+ client.resolve(position, messageHash);
633
+ }
634
+ }
635
+ parseWsPosition(position, market = undefined) {
636
+ //
637
+ // {
638
+ // "instrumentId": "ETH-USD-SWAP-LIN",
639
+ // "quantity": "0.01",
640
+ // "lastUpdated": "1716550757299",
641
+ // "contractValCurrency": "ETH",
642
+ // "entryPrice": "3709.6",
643
+ // "positionPnl": "-5.000",
644
+ // "estLiquidationPrice": "743.4",
645
+ // "margin": "0", // Currently always reports 0
646
+ // "leverage": "0" // Currently always reports 0
647
+ // }
648
+ //
649
+ const marketId = this.safeString(position, 'instrumentId');
650
+ market = this.safeMarket(marketId, market);
651
+ return this.safePosition({
652
+ 'info': position,
653
+ 'id': undefined,
654
+ 'symbol': market['symbol'],
655
+ 'notional': undefined,
656
+ 'marginMode': 'cross',
657
+ 'liquidationPrice': this.safeNumber(position, 'estLiquidationPrice'),
658
+ 'entryPrice': this.safeNumber(position, 'entryPrice'),
659
+ 'unrealizedPnl': this.safeNumber(position, 'positionPnl'),
660
+ 'realizedPnl': undefined,
661
+ 'percentage': undefined,
662
+ 'contracts': this.safeNumber(position, 'quantity'),
663
+ 'contractSize': undefined,
664
+ 'markPrice': undefined,
665
+ 'lastPrice': undefined,
666
+ 'side': undefined,
667
+ 'hedged': undefined,
668
+ 'timestamp': undefined,
669
+ 'datetime': undefined,
670
+ 'lastUpdateTimestamp': this.safeInteger(position, 'lastUpdated'),
671
+ 'maintenanceMargin': undefined,
672
+ 'maintenanceMarginPercentage': undefined,
673
+ 'collateral': undefined,
674
+ 'initialMargin': undefined,
675
+ 'initialMarginPercentage': undefined,
676
+ 'leverage': undefined,
677
+ 'marginRatio': undefined,
678
+ 'stopLossPrice': undefined,
679
+ 'takeProfitPrice': undefined,
680
+ });
681
+ }
682
+ async watchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
683
+ /**
684
+ * @method
685
+ * @name oxfun#watchOrders
686
+ * @description watches information on multiple orders made by the user
687
+ * @see https://docs.ox.fun/?json#order-channel
688
+ * @param {string} symbol unified market symbol of the market orders were made in
689
+ * @param {int} [since] the earliest time in ms to fetch orders for
690
+ * @param {int} [limit] the maximum number of order structures to retrieve
691
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
692
+ * @param {int|string} [params.tag] If given it will be echoed in the reply and the max size of tag is 32
693
+ * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
694
+ */
695
+ await this.loadMarkets();
696
+ await this.authenticate();
697
+ let messageHash = 'orders';
698
+ let args = 'order:';
699
+ const market = this.safeMarket(symbol);
700
+ if (symbol === undefined) {
701
+ args += 'all';
702
+ }
703
+ else {
704
+ messageHash += ':' + symbol;
705
+ args += ':' + market['id'];
706
+ }
707
+ const request = {
708
+ 'op': 'subscribe',
709
+ 'args': [
710
+ args,
711
+ ],
712
+ };
713
+ const url = this.urls['api']['ws'];
714
+ const orders = await this.watch(url, messageHash, request, messageHash);
715
+ if (this.newUpdates) {
716
+ limit = orders.getLimit(symbol, limit);
717
+ }
718
+ return this.filterBySymbolSinceLimit(orders, symbol, since, limit, true);
719
+ }
720
+ handleOrders(client, message) {
721
+ //
722
+ // {
723
+ // "table": "order",
724
+ // "data": [
725
+ // {
726
+ // "accountId": "106464",
727
+ // "clientOrderId": "1716713676233",
728
+ // "orderId": "1000116921319",
729
+ // "price": "1000.0",
730
+ // "quantity": "0.01",
731
+ // "amount": "0.0",
732
+ // "side": "BUY",
733
+ // "status": "OPEN",
734
+ // "marketCode": "ETH-USD-SWAP-LIN",
735
+ // "timeInForce": "MAKER_ONLY",
736
+ // "timestamp": "1716713677834",
737
+ // "remainQuantity": "0.01",
738
+ // "limitPrice": "1000.0",
739
+ // "notice": "OrderOpened",
740
+ // "orderType": "LIMIT",
741
+ // "isTriggered": "false",
742
+ // "displayQuantity": "0.01"
743
+ // }
744
+ // ]
745
+ // }
746
+ //
747
+ const data = this.safeList(message, 'data', []);
748
+ let messageHash = 'orders';
749
+ if (this.orders === undefined) {
750
+ const limit = this.safeInteger(this.options, 'ordersLimit', 1000);
751
+ this.orders = new ArrayCacheBySymbolById(limit);
752
+ }
753
+ const orders = this.orders;
754
+ for (let i = 0; i < data.length; i++) {
755
+ const order = this.safeDict(data, i, {});
756
+ const parsedOrder = this.parseOrder(order);
757
+ orders.append(parsedOrder);
758
+ messageHash += ':' + parsedOrder['symbol'];
759
+ client.resolve(this.orders, messageHash);
760
+ }
761
+ }
762
+ async createOrderWs(symbol, type, side, amount, price = undefined, params = {}) {
763
+ /**
764
+ * @method
765
+ * @name oxfun#createOrderWs
766
+ * @see https://docs.ox.fun/?json#order-commands
767
+ * @description create a trade order
768
+ * @param {string} symbol unified symbol of the market to create an order in
769
+ * @param {string} type 'market', 'limit', 'STOP_LIMIT' or 'STOP_MARKET'
770
+ * @param {string} side 'buy' or 'sell'
771
+ * @param {float} amount how much of currency you want to trade in units of base currency
772
+ * @param {float} [price] the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
773
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
774
+ * @param {int} [params.clientOrderId] a unique id for the order
775
+ * @param {int} [params.timestamp] in milliseconds. If an order reaches the matching engine and the current timestamp exceeds timestamp + recvWindow, then the order will be rejected.
776
+ * @param {int} [params.recvWindow] in milliseconds. If an order reaches the matching engine and the current timestamp exceeds timestamp + recvWindow, then the order will be rejected. If timestamp is provided without recvWindow, then a default recvWindow of 1000ms is used.
777
+ * @param {float} [params.cost] the quote quantity that can be used as an alternative for the amount for market buy orders
778
+ * @param {float} [params.triggerPrice] The price at which a trigger order is triggered at
779
+ * @param {float} [params.limitPrice] Limit price for the STOP_LIMIT order
780
+ * @param {bool} [params.postOnly] if true, the order will only be posted if it will be a maker order
781
+ * @param {string} [params.timeInForce] GTC (default), IOC, FOK, PO, MAKER_ONLY or MAKER_ONLY_REPRICE (reprices order to the best maker only price if the specified price were to lead to a taker trade)
782
+ * @param {string} [params.selfTradePreventionMode] NONE, EXPIRE_MAKER, EXPIRE_TAKER or EXPIRE_BOTH for more info check here {@link https://docs.ox.fun/?json#self-trade-prevention-modes}
783
+ * @param {string} [params.displayQuantity] for an iceberg order, pass both quantity and displayQuantity fields in the order request
784
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
785
+ */
786
+ await this.loadMarkets();
787
+ await this.authenticate();
788
+ const messageHash = this.nonce().toString();
789
+ const request = {
790
+ 'op': 'placeorder',
791
+ 'tag': messageHash,
792
+ };
793
+ params = this.omit(params, 'tag');
794
+ const orderRequest = this.createOrderRequest(symbol, type, side, amount, price, params);
795
+ const timestamp = this.safeInteger(orderRequest, 'timestamp');
796
+ if (timestamp === undefined) {
797
+ orderRequest['timestamp'] = this.milliseconds();
798
+ }
799
+ request['data'] = orderRequest;
800
+ const url = this.urls['api']['ws'];
801
+ return await this.watch(url, messageHash, request, messageHash);
802
+ }
803
+ async editOrderWs(id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
804
+ /**
805
+ * @method
806
+ * @name oxfun#editOrderWs
807
+ * @description edit a trade order
808
+ * @see https://docs.ox.fun/?json#modify-order
809
+ * @param {string} id order id
810
+ * @param {string} symbol unified symbol of the market to create an order in
811
+ * @param {string} type 'market' or 'limit'
812
+ * @param {string} side 'buy' or 'sell'
813
+ * @param {float} amount how much of the currency you want to trade in units of the base currency
814
+ * @param {float|undefined} [price] the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
815
+ * @param {int} [params.timestamp] in milliseconds. If an order reaches the matching engine and the current timestamp exceeds timestamp + recvWindow, then the order will be rejected.
816
+ * @param {int} [params.recvWindow] in milliseconds. If an order reaches the matching engine and the current timestamp exceeds timestamp + recvWindow, then the order will be rejected. If timestamp is provided without recvWindow, then a default recvWindow of 1000ms is used.
817
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
818
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
819
+ */
820
+ await this.loadMarkets();
821
+ await this.authenticate();
822
+ const messageHash = this.nonce().toString();
823
+ const request = {
824
+ 'op': 'modifyorder',
825
+ 'tag': messageHash,
826
+ };
827
+ params = this.omit(params, 'tag');
828
+ let orderRequest = this.createOrderRequest(symbol, type, side, amount, price, params);
829
+ orderRequest = this.extend(orderRequest, { 'orderId': id });
830
+ const timestamp = this.safeInteger(orderRequest, 'timestamp');
831
+ if (timestamp === undefined) {
832
+ orderRequest['timestamp'] = this.milliseconds();
833
+ }
834
+ request['data'] = orderRequest;
835
+ const url = this.urls['api']['ws'];
836
+ return await this.watch(url, messageHash, request, messageHash);
837
+ }
838
+ handlePlaceOrders(client, message) {
839
+ //
840
+ // {
841
+ // "event": "placeorder",
842
+ // "submitted": true,
843
+ // "tag": "1716934577",
844
+ // "timestamp": "1716932973899",
845
+ // "data": {
846
+ // "marketCode": "ETH-USD-SWAP-LIN",
847
+ // "side": "BUY",
848
+ // "orderType": "LIMIT",
849
+ // "quantity": "0.010",
850
+ // "timeInForce": "GTC",
851
+ // "price": "400.0",
852
+ // "limitPrice": "400.0",
853
+ // "orderId": "1000117429736",
854
+ // "source": 13
855
+ // }
856
+ // }
857
+ //
858
+ //
859
+ // Failure response format
860
+ // {
861
+ // "event": "placeorder",
862
+ // "submitted": false,
863
+ // "message": "JSON data format is invalid",
864
+ // "code": "20009",
865
+ // "timestamp": "1716932877381"
866
+ // }
867
+ //
868
+ const messageHash = this.safeString(message, 'tag');
869
+ const submitted = this.safeBool(message, 'submitted');
870
+ // filter out partial errors
871
+ if (!submitted) {
872
+ const method = this.safeString(message, 'event');
873
+ const stringMsg = this.json(message);
874
+ const code = this.safeInteger(message, 'code');
875
+ this.handleErrors(code, undefined, client.url, method, undefined, stringMsg, message, undefined, undefined);
876
+ }
877
+ const data = this.safeValue(message, 'data', {});
878
+ const order = this.parseOrder(data);
879
+ client.resolve(order, messageHash);
880
+ }
881
+ async cancelOrderWs(id, symbol = undefined, params = {}) {
882
+ /**
883
+ * @method
884
+ * @name oxfun#cancelOrderWs
885
+ * @see https://docs.ox.fun/?json#cancel-order
886
+ * @description cancels an open order
887
+ * @param {string} id order id
888
+ * @param {string} symbol unified market symbol, default is undefined
889
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
890
+ * @returns {object} an list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
891
+ */
892
+ if (symbol === undefined) {
893
+ throw new ArgumentsRequired(this.id + ' cancelOrderWs() requires a symbol argument');
894
+ }
895
+ await this.loadMarkets();
896
+ await this.authenticate();
897
+ const messageHash = this.nonce().toString();
898
+ const data = {
899
+ 'marketCode': this.marketId(symbol),
900
+ 'orderId': id,
901
+ };
902
+ const request = {
903
+ 'op': 'cancelorder',
904
+ 'tag': messageHash,
905
+ 'data': data,
906
+ };
907
+ const url = this.urls['api']['ws'];
908
+ return await this.watch(url, messageHash, request, messageHash);
909
+ }
910
+ async cancelOrdersWs(ids, symbol = undefined, params = {}) {
911
+ /**
912
+ * @method
913
+ * @name okx#cancelOrdersWs
914
+ * @see https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-mass-cancel-order
915
+ * @description cancel multiple orders
916
+ * @param {string[]} ids order ids
917
+ * @param {string} symbol unified market symbol, default is undefined
918
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
919
+ * @returns {object} an list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
920
+ */
921
+ const idsLength = ids.length;
922
+ if (idsLength > 20) {
923
+ throw new BadRequest(this.id + ' cancelOrdersWs() accepts up to 20 ids at a time');
924
+ }
925
+ if (symbol === undefined) {
926
+ throw new ArgumentsRequired(this.id + ' cancelOrdersWs() requires a symbol argument');
927
+ }
928
+ await this.loadMarkets();
929
+ await this.authenticate();
930
+ const messageHash = this.nonce().toString();
931
+ const marketId = this.marketId(symbol);
932
+ const dataArray = [];
933
+ for (let i = 0; i < idsLength; i++) {
934
+ const data = {
935
+ 'instId': marketId,
936
+ 'ordId': ids[i],
937
+ };
938
+ dataArray.push(data);
939
+ }
940
+ const request = {
941
+ 'op': 'cancelorders',
942
+ 'tag': messageHash,
943
+ 'dataArray': dataArray,
944
+ };
945
+ const url = this.urls['api']['ws'];
946
+ return await this.watch(url, messageHash, this.deepExtend(request, params), messageHash);
947
+ }
948
+ async authenticate(params = {}) {
949
+ const url = this.urls['api']['ws'];
950
+ const client = this.client(url);
951
+ const messageHash = 'authenticated';
952
+ const future = client.future(messageHash);
953
+ const authenticated = this.safeDict(client.subscriptions, messageHash);
954
+ if (authenticated === undefined) {
955
+ this.checkRequiredCredentials();
956
+ const timestamp = this.milliseconds();
957
+ const payload = timestamp.toString() + 'GET/auth/self/verify';
958
+ const signature = this.hmac(this.encode(payload), this.encode(this.secret), sha256, 'base64');
959
+ const request = {
960
+ 'op': 'login',
961
+ 'data': {
962
+ 'apiKey': this.apiKey,
963
+ 'timestamp': timestamp,
964
+ 'signature': signature,
965
+ },
966
+ };
967
+ const message = this.extend(request, params);
968
+ this.watch(url, messageHash, message, messageHash);
969
+ }
970
+ return await future;
971
+ }
972
+ handleAuthenticationMessage(client, message) {
973
+ const authenticated = this.safeBool(message, 'success', false);
974
+ const messageHash = 'authenticated';
975
+ if (authenticated) {
976
+ // we resolve the future here permanently so authentication only happens once
977
+ const future = this.safeDict(client.futures, messageHash);
978
+ future.resolve(true);
979
+ }
980
+ else {
981
+ const error = new AuthenticationError(this.json(message));
982
+ client.reject(error, messageHash);
983
+ if (messageHash in client.subscriptions) {
984
+ delete client.subscriptions[messageHash];
985
+ }
986
+ }
987
+ }
988
+ ping(client) {
989
+ return 'ping';
990
+ }
991
+ handlePong(client, message) {
992
+ client.lastPong = this.milliseconds();
993
+ return message;
994
+ }
995
+ handleMessage(client, message) {
996
+ if (message === 'pong') {
997
+ this.handlePong(client, message);
998
+ return;
999
+ }
1000
+ const table = this.safeString(message, 'table');
1001
+ const data = this.safeList(message, 'data', []);
1002
+ const event = this.safeString(message, 'event');
1003
+ if ((table !== undefined) && (data !== undefined)) {
1004
+ if (table === 'trade') {
1005
+ this.handleTrades(client, message);
1006
+ }
1007
+ if (table === 'ticker') {
1008
+ this.handleTicker(client, message);
1009
+ }
1010
+ if (table.indexOf('candles') > -1) {
1011
+ this.handleOHLCV(client, message);
1012
+ }
1013
+ if (table.indexOf('depth') > -1) {
1014
+ this.handleOrderBook(client, message);
1015
+ }
1016
+ if (table.indexOf('balance') > -1) {
1017
+ this.handleBalance(client, message);
1018
+ }
1019
+ if (table.indexOf('position') > -1) {
1020
+ this.handlePositions(client, message);
1021
+ }
1022
+ if (table.indexOf('order') > -1) {
1023
+ this.handleOrders(client, message);
1024
+ }
1025
+ }
1026
+ else {
1027
+ if (event === 'login') {
1028
+ this.handleAuthenticationMessage(client, message);
1029
+ }
1030
+ if ((event === 'placeorder') || (event === 'modifyorder') || (event === 'cancelorder')) {
1031
+ this.handlePlaceOrders(client, message);
1032
+ }
1033
+ }
1034
+ }
1035
+ }