ccxt 4.3.57 → 4.3.59

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 (82) hide show
  1. package/README.md +4 -4
  2. package/dist/ccxt.browser.min.js +3 -3
  3. package/dist/cjs/ccxt.js +4 -2
  4. package/dist/cjs/src/alpaca.js +5 -1
  5. package/dist/cjs/src/base/Exchange.js +4 -4
  6. package/dist/cjs/src/base/errors.js +22 -22
  7. package/dist/cjs/src/bigone.js +21 -1
  8. package/dist/cjs/src/bingx.js +131 -26
  9. package/dist/cjs/src/bitmart.js +1 -0
  10. package/dist/cjs/src/btcbox.js +149 -7
  11. package/dist/cjs/src/bybit.js +2 -2
  12. package/dist/cjs/src/coinmate.js +28 -35
  13. package/dist/cjs/src/coinone.js +1 -1
  14. package/dist/cjs/src/deribit.js +15 -1
  15. package/dist/cjs/src/digifinex.js +32 -7
  16. package/dist/cjs/src/gate.js +24 -18
  17. package/dist/cjs/src/htx.js +10 -8
  18. package/dist/cjs/src/hyperliquid.js +107 -1
  19. package/dist/cjs/src/kucoin.js +3 -0
  20. package/dist/cjs/src/latoken.js +5 -1
  21. package/dist/cjs/src/mexc.js +11 -11
  22. package/dist/cjs/src/okx.js +3 -0
  23. package/dist/cjs/src/pro/binance.js +11 -13
  24. package/dist/cjs/src/pro/bingx.js +11 -8
  25. package/dist/cjs/src/pro/okx.js +3 -3
  26. package/dist/cjs/src/pro/xt.js +1108 -0
  27. package/dist/cjs/src/upbit.js +148 -49
  28. package/dist/cjs/src/woo.js +1 -1
  29. package/dist/cjs/src/xt.js +72 -7
  30. package/js/ccxt.d.ts +6 -3
  31. package/js/ccxt.js +5 -3
  32. package/js/src/abstract/bitmart.d.ts +1 -0
  33. package/js/src/abstract/btcbox.d.ts +1 -0
  34. package/js/src/abstract/kucoin.d.ts +1 -0
  35. package/js/src/abstract/kucoinfutures.d.ts +1 -0
  36. package/js/src/abstract/upbit.d.ts +3 -0
  37. package/js/src/abstract/xt.d.ts +1 -0
  38. package/js/src/alpaca.d.ts +1 -1
  39. package/js/src/alpaca.js +5 -1
  40. package/js/src/base/Exchange.d.ts +3 -3
  41. package/js/src/base/Exchange.js +5 -5
  42. package/js/src/base/errorHierarchy.d.ts +5 -5
  43. package/js/src/base/errorHierarchy.js +5 -5
  44. package/js/src/base/errors.d.ts +15 -15
  45. package/js/src/base/errors.js +22 -22
  46. package/js/src/bigone.d.ts +1 -1
  47. package/js/src/bigone.js +21 -1
  48. package/js/src/bingx.js +131 -26
  49. package/js/src/bitmart.js +1 -0
  50. package/js/src/btcbox.d.ts +4 -1
  51. package/js/src/btcbox.js +149 -7
  52. package/js/src/bybit.js +2 -2
  53. package/js/src/coinmate.js +28 -35
  54. package/js/src/coinone.js +1 -1
  55. package/js/src/deribit.d.ts +1 -1
  56. package/js/src/deribit.js +15 -1
  57. package/js/src/digifinex.d.ts +3 -2
  58. package/js/src/digifinex.js +32 -7
  59. package/js/src/gate.js +24 -18
  60. package/js/src/htx.js +10 -8
  61. package/js/src/hyperliquid.d.ts +3 -1
  62. package/js/src/hyperliquid.js +107 -1
  63. package/js/src/kucoin.js +3 -0
  64. package/js/src/latoken.d.ts +1 -1
  65. package/js/src/latoken.js +5 -1
  66. package/js/src/mexc.js +11 -11
  67. package/js/src/okx.js +3 -0
  68. package/js/src/pro/binance.js +11 -13
  69. package/js/src/pro/bingx.js +11 -8
  70. package/js/src/pro/bitmart.d.ts +3 -3
  71. package/js/src/pro/bitopro.d.ts +2 -2
  72. package/js/src/pro/coincheck.d.ts +2 -2
  73. package/js/src/pro/coinone.d.ts +2 -2
  74. package/js/src/pro/hyperliquid.d.ts +2 -2
  75. package/js/src/pro/okx.js +3 -3
  76. package/js/src/pro/xt.d.ts +31 -0
  77. package/js/src/pro/xt.js +1109 -0
  78. package/js/src/upbit.d.ts +0 -1
  79. package/js/src/upbit.js +148 -49
  80. package/js/src/woo.js +2 -2
  81. package/js/src/xt.js +72 -7
  82. package/package.json +1 -1
@@ -0,0 +1,1108 @@
1
+ 'use strict';
2
+
3
+ var xt$1 = require('../xt.js');
4
+ var Cache = require('../base/ws/Cache.js');
5
+
6
+ // ---------------------------------------------------------------------------
7
+ // ---------------------------------------------------------------------------
8
+ class xt extends xt$1 {
9
+ describe() {
10
+ return this.deepExtend(super.describe(), {
11
+ 'has': {
12
+ 'ws': true,
13
+ 'watchOHLCV': true,
14
+ 'watchOrderBook': true,
15
+ 'watchTicker': true,
16
+ 'watchTickers': true,
17
+ 'watchTrades': true,
18
+ 'watchBalance': true,
19
+ 'watchOrders': true,
20
+ 'watchMyTrades': true,
21
+ 'watchPositions': undefined, // TODO https://doc.xt.com/#futures_user_websocket_v2position
22
+ },
23
+ 'urls': {
24
+ 'api': {
25
+ 'ws': {
26
+ 'spot': 'wss://stream.xt.com',
27
+ 'contract': 'wss://fstream.xt.com/ws',
28
+ },
29
+ },
30
+ },
31
+ 'options': {
32
+ 'tradesLimit': 1000,
33
+ 'ordersLimit': 1000,
34
+ 'OHLCVLimit': 1000,
35
+ 'watchTicker': {
36
+ 'method': 'ticker', // agg_ticker (contract only)
37
+ },
38
+ 'watchTickers': {
39
+ 'method': 'tickers', // agg_tickers (contract only)
40
+ },
41
+ },
42
+ 'streaming': {
43
+ 'keepAlive': 20000,
44
+ 'ping': this.ping,
45
+ },
46
+ 'token': undefined,
47
+ });
48
+ }
49
+ async getListenKey(isContract) {
50
+ /**
51
+ * @ignore
52
+ * @method
53
+ * @description required for private endpoints
54
+ * @param {string} isContract true for contract trades
55
+ * @see https://doc.xt.com/#websocket_privategetToken
56
+ * @see https://doc.xt.com/#futures_user_websocket_v2base
57
+ * @returns {string} listen key / access token
58
+ */
59
+ this.checkRequiredCredentials();
60
+ const tradeType = isContract ? 'contract' : 'spot';
61
+ let url = this.urls['api']['ws'][tradeType];
62
+ if (!isContract) {
63
+ url = url + '/private';
64
+ }
65
+ const client = this.client(url);
66
+ const token = this.safeDict(client.subscriptions, 'token');
67
+ if (token === undefined) {
68
+ if (isContract) {
69
+ const response = await this.privateLinearGetFutureUserV1UserListenKey();
70
+ //
71
+ // {
72
+ // returnCode: '0',
73
+ // msgInfo: 'success',
74
+ // error: null,
75
+ // result: '3BC1D71D6CF96DA3458FC35B05B633351684511731128'
76
+ // }
77
+ //
78
+ client.subscriptions['token'] = this.safeString(response, 'result');
79
+ }
80
+ else {
81
+ const response = await this.privateSpotPostWsToken();
82
+ //
83
+ // {
84
+ // "rc": 0,
85
+ // "mc": "SUCCESS",
86
+ // "ma": [],
87
+ // "result": {
88
+ // "token": "eyJhbqGciOiJSUzI1NiJ9.eyJhY2NvdW50SWQiOiIyMTQ2Mjg1MzIyNTU5Iiwic3ViIjoibGh4dDRfMDAwMUBzbmFwbWFpbC5jYyIsInNjb3BlIjoiYXV0aCIsImlzcyI6Inh0LmNvbSIsImxhc3RBdXRoVGltZSI6MTY2MzgxMzY5MDk1NSwic2lnblR5cGUiOiJBSyIsInVzZXJOYW1lIjoibGh4dDRfMDAwMUBzbmFwbWFpbC5jYyIsImV4cCI6MTY2NjQwNTY5MCwiZGV2aWNlIjoidW5rbm93biIsInVzZXJJZCI6MjE0NjI4NTMyMjU1OX0.h3zJlJBQrK2x1HvUxsKivnn6PlSrSDXXXJ7WqHAYSrN2CG5XPTKc4zKnTVoYFbg6fTS0u1fT8wH7wXqcLWXX71vm0YuP8PCvdPAkUIq4-HyzltbPr5uDYd0UByx0FPQtq1exvsQGe7evXQuDXx3SEJXxEqUbq_DNlXPTq_JyScI",
89
+ // "refreshToken": "eyJhbGciOiqJSUzI1NiJ9.eyJhY2NvdW50SWQiOiIyMTQ2Mjg1MzIyNTU5Iiwic3ViIjoibGh4dDRfMDAwMUBzbmFwbWFpbC5jYyIsInNjb3BlIjoicmVmcmVzaCIsImlzcyI6Inh0LmNvbSIsImxhc3RBdXRoVGltZSI6MTY2MzgxMzY5MDk1NSwic2lnblR5cGUiOiJBSyIsInVzZXJOYW1lIjoibGh4dDRfMDAwMUBzbmFwbWFpbC5jYyIsImV4cCI6MTY2NjQwNTY5MCwiZGV2aWNlIjoidW5rbm93biIsInVzZXJJZCI6MjE0NjI4NTMyMjU1OX0.Fs3YVm5YrEOzzYOSQYETSmt9iwxUHBovh2u73liv1hLUec683WGfktA_s28gMk4NCpZKFeQWFii623FvdfNoteXR0v1yZ2519uNvNndtuZICDdv3BQ4wzW1wIHZa1skxFfqvsDnGdXpjqu9UFSbtHwxprxeYfnxChNk4ssei430"
90
+ // }
91
+ // }
92
+ //
93
+ const result = this.safeDict(response, 'result');
94
+ client.subscriptions['token'] = this.safeString(result, 'accessToken');
95
+ }
96
+ }
97
+ return client.subscriptions['token'];
98
+ }
99
+ getCacheIndex(orderbook, cache) {
100
+ // return the first index of the cache that can be applied to the orderbook or -1 if not possible
101
+ const nonce = this.safeInteger(orderbook, 'nonce');
102
+ const firstDelta = this.safeValue(cache, 0);
103
+ const firstDeltaNonce = this.safeInteger2(firstDelta, 'i', 'u');
104
+ if (nonce < firstDeltaNonce - 1) {
105
+ return -1;
106
+ }
107
+ for (let i = 0; i < cache.length; i++) {
108
+ const delta = cache[i];
109
+ const deltaNonce = this.safeInteger2(delta, 'i', 'u');
110
+ if (deltaNonce >= nonce) {
111
+ return i;
112
+ }
113
+ }
114
+ return cache.length;
115
+ }
116
+ handleDelta(orderbook, delta) {
117
+ orderbook['nonce'] = this.safeInteger2(delta, 'i', 'u');
118
+ const obAsks = this.safeList(delta, 'a', []);
119
+ const obBids = this.safeList(delta, 'b', []);
120
+ const bids = orderbook['bids'];
121
+ const asks = orderbook['asks'];
122
+ for (let i = 0; i < obBids.length; i++) {
123
+ const bid = obBids[i];
124
+ const price = this.safeNumber(bid, 0);
125
+ const quantity = this.safeNumber(bid, 1);
126
+ bids.store(price, quantity);
127
+ }
128
+ for (let i = 0; i < obAsks.length; i++) {
129
+ const ask = obAsks[i];
130
+ const price = this.safeNumber(ask, 0);
131
+ const quantity = this.safeNumber(ask, 1);
132
+ asks.store(price, quantity);
133
+ }
134
+ // this.handleBidAsks (storedBids, bids);
135
+ // this.handleBidAsks (storedAsks, asks);
136
+ }
137
+ async subscribe(name, access, methodName, market = undefined, symbols = undefined, params = {}) {
138
+ /**
139
+ * @ignore
140
+ * @method
141
+ * @description Connects to a websocket channel
142
+ * @see https://doc.xt.com/#websocket_privaterequestFormat
143
+ * @see https://doc.xt.com/#futures_market_websocket_v2base
144
+ * @param {string} name name of the channel
145
+ * @param {string} access public or private
146
+ * @param {string} methodName the name of the CCXT class method
147
+ * @param {object} [market] CCXT market
148
+ * @param {string[]} [symbols] unified market symbols
149
+ * @param {object} params extra parameters specific to the xt api
150
+ * @returns {object} data from the websocket stream
151
+ */
152
+ const privateAccess = access === 'private';
153
+ let type = undefined;
154
+ [type, params] = this.handleMarketTypeAndParams(methodName, market, params);
155
+ const isContract = (type !== 'spot');
156
+ const subscribe = {
157
+ 'method': isContract ? 'SUBSCRIBE' : 'subscribe',
158
+ 'id': this.numberToString(this.milliseconds()) + name, // call back ID
159
+ };
160
+ if (privateAccess) {
161
+ if (!isContract) {
162
+ subscribe['params'] = [name];
163
+ subscribe['listenKey'] = await this.getListenKey(isContract);
164
+ }
165
+ else {
166
+ const listenKey = await this.getListenKey(isContract);
167
+ const param = name + '@' + listenKey;
168
+ subscribe['params'] = [param];
169
+ }
170
+ }
171
+ else {
172
+ subscribe['params'] = [name];
173
+ }
174
+ const tradeType = isContract ? 'contract' : 'spot';
175
+ let messageHash = name + '::' + tradeType;
176
+ if (symbols !== undefined) {
177
+ messageHash = messageHash + '::' + symbols.join(',');
178
+ }
179
+ const request = this.extend(subscribe, params);
180
+ let tail = access;
181
+ if (isContract) {
182
+ tail = privateAccess ? 'user' : 'market';
183
+ }
184
+ const url = this.urls['api']['ws'][tradeType] + '/' + tail;
185
+ return await this.watch(url, messageHash, request, messageHash);
186
+ }
187
+ async watchTicker(symbol, params = {}) {
188
+ /**
189
+ * @method
190
+ * @name xt#watchTicker
191
+ * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
192
+ * @see https://doc.xt.com/#websocket_publictickerRealTime
193
+ * @see https://doc.xt.com/#futures_market_websocket_v2tickerRealTime
194
+ * @see https://doc.xt.com/#futures_market_websocket_v2aggTickerRealTime
195
+ * @param {string} symbol unified symbol of the market to fetch the ticker for
196
+ * @param {object} params extra parameters specific to the xt api endpoint
197
+ * @param {string} [params.method] 'agg_ticker' (contract only) or 'ticker', default = 'ticker' - the endpoint that will be streamed
198
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/en/latest/manual.html#ticker-structure}
199
+ */
200
+ await this.loadMarkets();
201
+ const market = this.market(symbol);
202
+ const options = this.safeDict(this.options, 'watchTicker');
203
+ const defaultMethod = this.safeString(options, 'method', 'ticker');
204
+ const method = this.safeString(params, 'method', defaultMethod);
205
+ const name = method + '@' + market['id'];
206
+ return await this.subscribe(name, 'public', 'watchTicker', market, undefined, params);
207
+ }
208
+ async watchTickers(symbols = undefined, params = {}) {
209
+ /**
210
+ * @method
211
+ * @name xt#watchTicker
212
+ * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
213
+ * @see https://doc.xt.com/#websocket_publicallTicker
214
+ * @see https://doc.xt.com/#futures_market_websocket_v2allTicker
215
+ * @see https://doc.xt.com/#futures_market_websocket_v2allAggTicker
216
+ * @param {string} [symbols] unified market symbols
217
+ * @param {object} params extra parameters specific to the xt api endpoint
218
+ * @param {string} [params.method] 'agg_tickers' (contract only) or 'tickers', default = 'tickers' - the endpoint that will be streamed
219
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/en/latest/manual.html#ticker-structure}
220
+ */
221
+ await this.loadMarkets();
222
+ const options = this.safeDict(this.options, 'watchTickers');
223
+ const defaultMethod = this.safeString(options, 'method', 'tickers');
224
+ const name = this.safeString(params, 'method', defaultMethod);
225
+ let market = undefined;
226
+ if (symbols !== undefined) {
227
+ market = this.market(symbols[0]);
228
+ }
229
+ const tickers = await this.subscribe(name, 'public', 'watchTickers', market, symbols, params);
230
+ if (this.newUpdates) {
231
+ return tickers;
232
+ }
233
+ return this.filterByArray(this.tickers, 'symbol', symbols);
234
+ }
235
+ async watchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
236
+ /**
237
+ * @method
238
+ * @name hitbtc#watchOHLCV
239
+ * @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
240
+ * @see https://doc.xt.com/#websocket_publicsymbolKline
241
+ * @see https://doc.xt.com/#futures_market_websocket_v2symbolKline
242
+ * @param {string} symbol unified symbol of the market to fetch OHLCV data for
243
+ * @param {string} timeframe 1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 8h, 12h, 1d, 3d, 1w, or 1M
244
+ * @param {int} [since] not used by xt watchOHLCV
245
+ * @param {int} [limit] not used by xt watchOHLCV
246
+ * @param {object} params extra parameters specific to the xt api endpoint
247
+ * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
248
+ */
249
+ await this.loadMarkets();
250
+ const market = this.market(symbol);
251
+ const name = 'kline@' + market['id'] + ',' + timeframe;
252
+ return await this.subscribe(name, 'public', 'watchOHLCV', market, undefined, params);
253
+ }
254
+ async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
255
+ /**
256
+ * @method
257
+ * @name xt#watchTrades
258
+ * @description get the list of most recent trades for a particular symbol
259
+ * @see https://doc.xt.com/#websocket_publicdealRecord
260
+ * @see https://doc.xt.com/#futures_market_websocket_v2dealRecord
261
+ * @param {string} symbol unified symbol of the market to fetch trades for
262
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
263
+ * @param {int} [limit] the maximum amount of trades to fetch
264
+ * @param {object} params extra parameters specific to the xt api endpoint
265
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/en/latest/manual.html?#public-trades}
266
+ */
267
+ await this.loadMarkets();
268
+ const market = this.market(symbol);
269
+ const name = 'trade@' + market['id'];
270
+ const trades = await this.subscribe(name, 'public', 'watchTrades', market, undefined, params);
271
+ if (this.newUpdates) {
272
+ limit = trades.getLimit(symbol, limit);
273
+ }
274
+ return this.filterBySinceLimit(trades, since, limit, 'timestamp');
275
+ }
276
+ async watchOrderBook(symbol, limit = undefined, params = {}) {
277
+ /**
278
+ * @method
279
+ * @name xt#watchOrderBook
280
+ * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
281
+ * @see https://doc.xt.com/#websocket_publiclimitDepth
282
+ * @see https://doc.xt.com/#websocket_publicincreDepth
283
+ * @see https://doc.xt.com/#futures_market_websocket_v2limitDepth
284
+ * @see https://doc.xt.com/#futures_market_websocket_v2increDepth
285
+ * @param {string} symbol unified symbol of the market to fetch the order book for
286
+ * @param {int} [limit] not used by xt watchOrderBook
287
+ * @param {object} params extra parameters specific to the xt api endpoint
288
+ * @param {int} [params.levels] 5, 10, 20, or 50
289
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/en/latest/manual.html#order-book-structure} indexed by market symbols
290
+ */
291
+ await this.loadMarkets();
292
+ const market = this.market(symbol);
293
+ const levels = this.safeString(params, 'levels');
294
+ params = this.omit(params, 'levels');
295
+ let name = 'depth_update@' + market['id'];
296
+ if (levels !== undefined) {
297
+ name = 'depth@' + market['id'] + ',' + levels;
298
+ }
299
+ const orderbook = await this.subscribe(name, 'public', 'watchOrderBook', market, undefined, params);
300
+ return orderbook.limit();
301
+ }
302
+ async watchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
303
+ /**
304
+ * @method
305
+ * @name xt#watchOrders
306
+ * @description watches information on multiple orders made by the user
307
+ * @see https://doc.xt.com/#websocket_privateorderChange
308
+ * @see https://doc.xt.com/#futures_user_websocket_v2order
309
+ * @param {string} [symbol] unified market symbol
310
+ * @param {int} [since] not used by xt watchOrders
311
+ * @param {int} [limit] the maximum number of orders to return
312
+ * @param {object} params extra parameters specific to the xt api endpoint
313
+ * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure}
314
+ */
315
+ await this.loadMarkets();
316
+ const name = 'order';
317
+ let market = undefined;
318
+ if (symbol !== undefined) {
319
+ market = this.market(symbol);
320
+ }
321
+ const orders = await this.subscribe(name, 'private', 'watchOrders', market, undefined, params);
322
+ if (this.newUpdates) {
323
+ limit = orders.getLimit(symbol, limit);
324
+ }
325
+ return this.filterBySinceLimit(orders, since, limit, 'timestamp');
326
+ }
327
+ async watchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
328
+ /**
329
+ * @method
330
+ * @name xt#watchMyTrades
331
+ * @description watches information on multiple trades made by the user
332
+ * @see https://doc.xt.com/#websocket_privateorderDeal
333
+ * @see https://doc.xt.com/#futures_user_websocket_v2trade
334
+ * @param {string} symbol unified market symbol of the market orders were made in
335
+ * @param {int} [since] the earliest time in ms to fetch orders for
336
+ * @param {int} [limit] the maximum number of orde structures to retrieve
337
+ * @param {object} params extra parameters specific to the kucoin api endpoint
338
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
339
+ */
340
+ await this.loadMarkets();
341
+ const name = 'trade';
342
+ let market = undefined;
343
+ if (symbol !== undefined) {
344
+ market = this.market(symbol);
345
+ }
346
+ const trades = await this.subscribe(name, 'private', 'watchMyTrades', market, undefined, params);
347
+ if (this.newUpdates) {
348
+ limit = trades.getLimit(symbol, limit);
349
+ }
350
+ return this.filterBySinceLimit(trades, since, limit, 'timestamp');
351
+ }
352
+ async watchBalance(params = {}) {
353
+ /**
354
+ * @method
355
+ * @name xt#watchOrders
356
+ * @description watches information on multiple orders made by the user
357
+ * @see https://doc.xt.com/#websocket_privatebalanceChange
358
+ * @see https://doc.xt.com/#futures_user_websocket_v2balance
359
+ * @param {object} params extra parameters specific to the xt api endpoint
360
+ * @returns {object[]} a list of [balance structures]{@link https://docs.ccxt.com/#/?id=balance-structure}
361
+ */
362
+ await this.loadMarkets();
363
+ const name = 'balance';
364
+ return await this.subscribe(name, 'private', 'watchBalance', undefined, undefined, params);
365
+ }
366
+ handleTicker(client, message) {
367
+ //
368
+ // spot
369
+ //
370
+ // {
371
+ // topic: 'ticker',
372
+ // event: 'ticker@btc_usdt',
373
+ // data: {
374
+ // s: 'btc_usdt', // symbol
375
+ // t: 1683501935877, // time(Last transaction time)
376
+ // cv: '-82.67', // priceChangeValue(24 hour price change)
377
+ // cr: '-0.0028', // priceChangeRate 24-hour price change (percentage)
378
+ // o: '28823.87', // open price
379
+ // c: '28741.20', // close price
380
+ // h: '29137.64', // highest price
381
+ // l: '28660.93', // lowest price
382
+ // q: '6372.601573', // quantity
383
+ // v: '184086075.2772391' // volume
384
+ // }
385
+ // }
386
+ //
387
+ // contract
388
+ //
389
+ // {
390
+ // "topic": "ticker",
391
+ // "event": "ticker@btc_usdt",
392
+ // "data": {
393
+ // "s": "btc_index", // trading pair
394
+ // "o": "49000", // opening price
395
+ // "c": "50000", // closing price
396
+ // "h": "0.1", // highest price
397
+ // "l": "0.1", // lowest price
398
+ // "a": "0.1", // volume
399
+ // "v": "0.1", // turnover
400
+ // "ch": "0.21", // quote change
401
+ // "t": 123124124 // timestamp
402
+ // }
403
+ // }
404
+ //
405
+ // agg_ticker (contract)
406
+ //
407
+ // {
408
+ // "topic": "agg_ticker",
409
+ // "event": "agg_ticker@btc_usdt",
410
+ // "data": {
411
+ // "s": "btc_index", // trading pair
412
+ // "o": "49000", // opening price
413
+ // "c": "50000", // closing price
414
+ // "h": "0.1", // highest price
415
+ // "l": "0.1", // lowest price
416
+ // "a": "0.1", // volume
417
+ // "v": "0.1", // turnover
418
+ // "ch": "0.21", // quote change
419
+ // "i": "0.21" , // index price
420
+ // "m": "0.21", // mark price
421
+ // "bp": "0.21", // bid price
422
+ // "ap": "0.21" , // ask price
423
+ // "t": 123124124 // timestamp
424
+ // }
425
+ // }
426
+ //
427
+ const data = this.safeDict(message, 'data');
428
+ const marketId = this.safeString(data, 's');
429
+ if (marketId !== undefined) {
430
+ const cv = this.safeString(data, 'cv');
431
+ const isSpot = cv !== undefined;
432
+ const ticker = this.parseTicker(data);
433
+ const symbol = ticker['symbol'];
434
+ this.tickers[symbol] = ticker;
435
+ const event = this.safeString(message, 'event');
436
+ const messageHashTail = isSpot ? 'spot' : 'contract';
437
+ const messageHash = event + '::' + messageHashTail;
438
+ client.resolve(ticker, messageHash);
439
+ }
440
+ return message;
441
+ }
442
+ handleTickers(client, message) {
443
+ //
444
+ // spot
445
+ //
446
+ // {
447
+ // topic: 'tickers',
448
+ // event: 'tickers',
449
+ // data: [
450
+ // {
451
+ // s: 'elon_usdt',
452
+ // t: 1683502958381,
453
+ // cv: '-0.0000000125',
454
+ // cr: '-0.0495',
455
+ // o: '0.0000002522',
456
+ // c: '0.0000002397',
457
+ // h: '0.0000002690',
458
+ // l: '0.0000002371',
459
+ // q: '3803783034.0000000000',
460
+ // v: '955.3260820022'
461
+ // },
462
+ // ...
463
+ // ]
464
+ // }
465
+ //
466
+ // contract
467
+ //
468
+ // {
469
+ // "topic": "tickers",
470
+ // "event": "tickers",
471
+ // "data": [
472
+ // {
473
+ // "s": "btc_index", // trading pair
474
+ // "o": "49000", // opening price
475
+ // "c": "50000", // closing price
476
+ // "h": "0.1", // highest price
477
+ // "l": "0.1", // lowest price
478
+ // "a": "0.1", // volume
479
+ // "v": "0.1", // turnover
480
+ // "ch": "0.21", // quote change
481
+ // "t": 123124124 // timestamp
482
+ // }
483
+ // ]
484
+ // }
485
+ //
486
+ // agg_ticker (contract)
487
+ //
488
+ // {
489
+ // "topic": "agg_tickers",
490
+ // "event": "agg_tickers",
491
+ // "data": [
492
+ // {
493
+ // "s": "btc_index", // trading pair
494
+ // "o": "49000", // opening price
495
+ // "c": "50000", // closing price
496
+ // "h": "0.1", // highest price
497
+ // "l": "0.1", // lowest price
498
+ // "a": "0.1", // volume
499
+ // "v": "0.1", // turnover
500
+ // "ch": "0.21", // quote change
501
+ // "i": "0.21" , // index price
502
+ // "m": "0.21", // mark price
503
+ // "bp": "0.21", // bid price
504
+ // "ap": "0.21" , // ask price
505
+ // "t": 123124124 // timestamp
506
+ // }
507
+ // ]
508
+ // }
509
+ //
510
+ const data = this.safeList(message, 'data', []);
511
+ const firstTicker = this.safeDict(data, 0);
512
+ const spotTest = this.safeString2(firstTicker, 'cv', 'aq');
513
+ const tradeType = (spotTest !== undefined) ? 'spot' : 'contract';
514
+ const newTickers = [];
515
+ for (let i = 0; i < data.length; i++) {
516
+ const tickerData = data[i];
517
+ const ticker = this.parseTicker(tickerData);
518
+ const symbol = ticker['symbol'];
519
+ this.tickers[symbol] = ticker;
520
+ newTickers.push(ticker);
521
+ }
522
+ const messageHashStart = this.safeString(message, 'topic') + '::' + tradeType;
523
+ const messageHashes = this.findMessageHashes(client, messageHashStart + '::');
524
+ for (let i = 0; i < messageHashes.length; i++) {
525
+ const messageHash = messageHashes[i];
526
+ const parts = messageHash.split('::');
527
+ const symbolsString = parts[2];
528
+ const symbols = symbolsString.split(',');
529
+ const tickers = this.filterByArray(newTickers, 'symbol', symbols);
530
+ const tickersSymbols = Object.keys(tickers);
531
+ const numTickers = tickersSymbols.length;
532
+ if (numTickers > 0) {
533
+ client.resolve(tickers, messageHash);
534
+ }
535
+ }
536
+ client.resolve(this.tickers, messageHashStart);
537
+ return message;
538
+ }
539
+ handleOHLCV(client, message) {
540
+ //
541
+ // spot
542
+ //
543
+ // {
544
+ // "topic": "kline",
545
+ // "event": "kline@btc_usdt,5m",
546
+ // "data": {
547
+ // "s": "btc_usdt", // symbol
548
+ // "t": 1656043200000, // time
549
+ // "i": "5m", // interval
550
+ // "o": "44000", // open price
551
+ // "c": "50000", // close price
552
+ // "h": "52000", // highest price
553
+ // "l": "36000", // lowest price
554
+ // "q": "34.2", // qty(quantity)
555
+ // "v": "230000" // volume
556
+ // }
557
+ // }
558
+ //
559
+ // contract
560
+ //
561
+ // {
562
+ // "topic": "kline",
563
+ // "event": "kline@btc_usdt,5m",
564
+ // "data": {
565
+ // "s": "btc_index", // trading pair
566
+ // "o": "49000", // opening price
567
+ // "c": "50000", // closing price
568
+ // "h": "0.1", // highest price
569
+ // "l": "0.1", // lowest price
570
+ // "a": "0.1", // volume
571
+ // "v": "0.1", // turnover
572
+ // "ch": "0.21", // quote change
573
+ // "t": 123124124 // timestamp
574
+ // }
575
+ // }
576
+ //
577
+ const data = this.safeDict(message, 'data', {});
578
+ const marketId = this.safeString(data, 's');
579
+ if (marketId !== undefined) {
580
+ const timeframe = this.safeString(data, 'i');
581
+ const tradeType = ('q' in data) ? 'spot' : 'contract';
582
+ const market = this.safeMarket(marketId, undefined, undefined, tradeType);
583
+ const symbol = market['symbol'];
584
+ const parsed = this.parseOHLCV(data, market);
585
+ this.ohlcvs[symbol] = this.safeDict(this.ohlcvs, symbol, {});
586
+ let stored = this.safeValue(this.ohlcvs[symbol], timeframe);
587
+ if (stored === undefined) {
588
+ const limit = this.safeInteger(this.options, 'OHLCVLimit', 1000);
589
+ stored = new Cache.ArrayCacheByTimestamp(limit);
590
+ this.ohlcvs[symbol][timeframe] = stored;
591
+ }
592
+ stored.append(parsed);
593
+ const event = this.safeString(message, 'event');
594
+ const messageHash = event + '::' + tradeType;
595
+ client.resolve(stored, messageHash);
596
+ }
597
+ return message;
598
+ }
599
+ handleTrade(client, message) {
600
+ //
601
+ // spot
602
+ //
603
+ // {
604
+ // topic: 'trade',
605
+ // event: 'trade@btc_usdt',
606
+ // data: {
607
+ // s: 'btc_usdt',
608
+ // i: '228825383103928709',
609
+ // t: 1684258222702,
610
+ // p: '27003.65',
611
+ // q: '0.000796',
612
+ // b: true
613
+ // }
614
+ // }
615
+ //
616
+ // contract
617
+ //
618
+ // {
619
+ // "topic": "trade",
620
+ // "event": "trade@btc_usdt",
621
+ // "data": {
622
+ // "s": "btc_index", // trading pair
623
+ // "p": "50000", // price
624
+ // "a": "0.1" // Quantity
625
+ // "m": "BID" // Deal side BID:Buy ASK:Sell
626
+ // "t": 123124124 // timestamp
627
+ // }
628
+ // }
629
+ //
630
+ const data = this.safeDict(message, 'data');
631
+ const marketId = this.safeStringLower(data, 's');
632
+ if (marketId !== undefined) {
633
+ const trade = this.parseTrade(data);
634
+ const i = this.safeString(data, 'i');
635
+ const tradeType = (i !== undefined) ? 'spot' : 'contract';
636
+ const market = this.safeMarket(marketId, undefined, undefined, tradeType);
637
+ const symbol = market['symbol'];
638
+ const event = this.safeString(message, 'event');
639
+ let tradesArray = this.safeValue(this.trades, symbol);
640
+ if (tradesArray === undefined) {
641
+ const tradesLimit = this.safeInteger(this.options, 'tradesLimit', 1000);
642
+ tradesArray = new Cache.ArrayCache(tradesLimit);
643
+ this.trades[symbol] = tradesArray;
644
+ }
645
+ tradesArray.append(trade);
646
+ const messageHash = event + '::' + tradeType;
647
+ client.resolve(tradesArray, messageHash);
648
+ }
649
+ return message;
650
+ }
651
+ handleOrderBook(client, message) {
652
+ //
653
+ // spot
654
+ //
655
+ // {
656
+ // "topic": "depth",
657
+ // "event": "depth@btc_usdt,20",
658
+ // "data": {
659
+ // "s": "btc_usdt", // symbol
660
+ // "fi": 1681433733351, // firstUpdateId = previous lastUpdateId + 1
661
+ // "i": 1681433733371, // updateId
662
+ // "a": [ // asks(sell order)
663
+ // [ // [0]price, [1]quantity
664
+ // "34000", // price
665
+ // "1.2" // quantity
666
+ // ],
667
+ // [
668
+ // "34001",
669
+ // "2.3"
670
+ // ]
671
+ // ],
672
+ // "b": [ // bids(buy order)
673
+ // [
674
+ // "32000",
675
+ // "0.2"
676
+ // ],
677
+ // [
678
+ // "31000",
679
+ // "0.5"
680
+ // ]
681
+ // ]
682
+ // }
683
+ // }
684
+ //
685
+ // contract
686
+ //
687
+ // {
688
+ // "topic": "depth",
689
+ // "event": "depth@btc_usdt,20",
690
+ // "data": {
691
+ // s: "btc_usdt",
692
+ // pu: "548111455664",
693
+ // fu: "548111455665",
694
+ // u: "548111455667",
695
+ // a: [
696
+ // [
697
+ // "26841.5",
698
+ // "50210",
699
+ // ],
700
+ // ],
701
+ // b: [
702
+ // [
703
+ // "26841",
704
+ // "67075",
705
+ // ],
706
+ // ],
707
+ // t: 1684530667083,
708
+ // }
709
+ // }
710
+ //
711
+ const data = this.safeDict(message, 'data');
712
+ const marketId = this.safeString(data, 's');
713
+ if (marketId !== undefined) {
714
+ let event = this.safeString(message, 'event');
715
+ const splitEvent = event.split(',');
716
+ event = this.safeString(splitEvent, 0);
717
+ const tradeType = ('fu' in data) ? 'contract' : 'spot';
718
+ const market = this.safeMarket(marketId, undefined, undefined, tradeType);
719
+ const symbol = market['symbol'];
720
+ const obAsks = this.safeList(data, 'a');
721
+ const obBids = this.safeList(data, 'b');
722
+ const messageHash = event + '::' + tradeType;
723
+ if (!(symbol in this.orderbooks)) {
724
+ const subscription = this.safeDict(client.subscriptions, messageHash, {});
725
+ const limit = this.safeInteger(subscription, 'limit');
726
+ this.orderbooks[symbol] = this.orderBook({}, limit);
727
+ }
728
+ const orderbook = this.orderbooks[symbol];
729
+ const nonce = this.safeInteger(orderbook, 'nonce');
730
+ if (nonce === undefined) {
731
+ const cacheLength = orderbook.cache.length;
732
+ const snapshotDelay = this.handleOption('watchOrderBook', 'snapshotDelay', 25);
733
+ if (cacheLength === snapshotDelay) {
734
+ this.spawn(this.loadOrderBook, client, messageHash, symbol);
735
+ }
736
+ orderbook.cache.push(data);
737
+ return;
738
+ }
739
+ if (obAsks !== undefined) {
740
+ const asks = orderbook['asks'];
741
+ for (let i = 0; i < obAsks.length; i++) {
742
+ const ask = obAsks[i];
743
+ const price = this.safeNumber(ask, 0);
744
+ const quantity = this.safeNumber(ask, 1);
745
+ asks.store(price, quantity);
746
+ }
747
+ }
748
+ if (obBids !== undefined) {
749
+ const bids = orderbook['bids'];
750
+ for (let i = 0; i < obBids.length; i++) {
751
+ const bid = obBids[i];
752
+ const price = this.safeNumber(bid, 0);
753
+ const quantity = this.safeNumber(bid, 1);
754
+ bids.store(price, quantity);
755
+ }
756
+ }
757
+ const timestamp = this.safeInteger(data, 't');
758
+ orderbook['nonce'] = this.safeInteger2(data, 'i', 'u');
759
+ orderbook['timestamp'] = timestamp;
760
+ orderbook['datetime'] = this.iso8601(timestamp);
761
+ orderbook['symbol'] = symbol;
762
+ client.resolve(orderbook, messageHash);
763
+ }
764
+ }
765
+ parseWsOrderTrade(trade, market = undefined) {
766
+ //
767
+ // {
768
+ // "s": "btc_usdt", // symbol
769
+ // "t": 1656043204763, // time happened time
770
+ // "i": "6216559590087220004", // orderId,
771
+ // "ci": "test123", // clientOrderId
772
+ // "st": "PARTIALLY_FILLED", // state
773
+ // "sd": "BUY", // side BUY/SELL
774
+ // "eq": "2", // executedQty executed quantity
775
+ // "ap": "30000", // avg price
776
+ // "f": "0.002" // fee
777
+ // }
778
+ //
779
+ // contract
780
+ //
781
+ // {
782
+ // "symbol": "btc_usdt", // Trading pair
783
+ // "orderId": "1234", // Order Id
784
+ // "origQty": "34244", // Original Quantity
785
+ // "avgPrice": "123", // Quantity
786
+ // "price": "1111", // Average price
787
+ // "executedQty": "34244", // Volume (Cont)
788
+ // "orderSide": "BUY", // BUY, SELL
789
+ // "positionSide": "LONG", // LONG, SHORT
790
+ // "marginFrozen": "123", // Occupied margin
791
+ // "sourceType": "default", // DEFAULT:normal order,ENTRUST:plan commission,PROFIR:Take Profit and Stop Loss
792
+ // "sourceId" : "1231231", // Triggering conditions ID
793
+ // "state": "", // state:NEW:New order (unfilled);PARTIALLY_FILLED:Partial deal;PARTIALLY_CANCELED:Partial revocation;FILLED:Filled;CANCELED:Cancled;REJECTED:Order failed;EXPIRED:Expired
794
+ // "createTime": 1731231231, // CreateTime
795
+ // "clientOrderId": "204788317630342726"
796
+ // }
797
+ //
798
+ const marketId = this.safeString(trade, 's');
799
+ const tradeType = ('symbol' in trade) ? 'contract' : 'spot';
800
+ market = this.safeMarket(marketId, market, undefined, tradeType);
801
+ const timestamp = this.safeString(trade, 't');
802
+ return this.safeTrade({
803
+ 'info': trade,
804
+ 'id': undefined,
805
+ 'timestamp': timestamp,
806
+ 'datetime': this.iso8601(timestamp),
807
+ 'symbol': market['symbol'],
808
+ 'order': this.safeString(trade, 'i', 'orderId'),
809
+ 'type': this.parseOrderStatus(this.safeString(trade, 'st', 'state')),
810
+ 'side': this.safeStringLower(trade, 'sd', 'orderSide'),
811
+ 'takerOrMaker': undefined,
812
+ 'price': this.safeNumber(trade, 'price'),
813
+ 'amount': this.safeString(trade, 'origQty'),
814
+ 'cost': undefined,
815
+ 'fee': {
816
+ 'currency': undefined,
817
+ 'cost': this.safeNumber(trade, 'f'),
818
+ 'rate': undefined,
819
+ },
820
+ }, market);
821
+ }
822
+ parseWsOrder(order, market = undefined) {
823
+ //
824
+ // spot
825
+ //
826
+ // {
827
+ // "s": "btc_usdt", // symbol
828
+ // "bc": "btc", // base currency
829
+ // "qc": "usdt", // quotation currency
830
+ // "t": 1656043204763, // happened time
831
+ // "ct": 1656043204663, // create time
832
+ // "i": "6216559590087220004", // order id,
833
+ // "ci": "test123", // client order id
834
+ // "st": "PARTIALLY_FILLED", // state NEW/PARTIALLY_FILLED/FILLED/CANCELED/REJECTED/EXPIRED
835
+ // "sd": "BUY", // side BUY/SELL
836
+ // "tp": "LIMIT", // type LIMIT/MARKET
837
+ // "oq": "4" // original quantity
838
+ // "oqq": 48000, // original quotation quantity
839
+ // "eq": "2", // executed quantity
840
+ // "lq": "2", // remaining quantity
841
+ // "p": "4000", // price
842
+ // "ap": "30000", // avg price
843
+ // "f":"0.002" // fee
844
+ // }
845
+ //
846
+ // contract
847
+ //
848
+ // {
849
+ // "symbol": "btc_usdt", // Trading pair
850
+ // "orderId": "1234", // Order Id
851
+ // "origQty": "34244", // Original Quantity
852
+ // "avgPrice": "123", // Quantity
853
+ // "price": "1111", // Average price
854
+ // "executedQty": "34244", // Volume (Cont)
855
+ // "orderSide": "BUY", // BUY, SELL
856
+ // "positionSide": "LONG", // LONG, SHORT
857
+ // "marginFrozen": "123", // Occupied margin
858
+ // "sourceType": "default", // DEFAULT:normal order,ENTRUST:plan commission,PROFIR:Take Profit and Stop Loss
859
+ // "sourceId" : "1231231", // Triggering conditions ID
860
+ // "state": "", // state:NEW:New order (unfilled);PARTIALLY_FILLED:Partial deal;PARTIALLY_CANCELED:Partial revocation;FILLED:Filled;CANCELED:Cancled;REJECTED:Order failed;EXPIRED:Expired
861
+ // "createTime": 1731231231, // CreateTime
862
+ // "clientOrderId": "204788317630342726"
863
+ // }
864
+ //
865
+ const marketId = this.safeString2(order, 's', 'symbol');
866
+ const tradeType = ('symbol' in order) ? 'contract' : 'spot';
867
+ market = this.safeMarket(marketId, market, undefined, tradeType);
868
+ const timestamp = this.safeInteger2(order, 'ct', 'createTime');
869
+ return this.safeOrder({
870
+ 'info': order,
871
+ 'id': this.safeString2(order, 'i', 'orderId'),
872
+ 'clientOrderId': this.safeString2(order, 'ci', 'clientOrderId'),
873
+ 'timestamp': timestamp,
874
+ 'datetime': this.iso8601(timestamp),
875
+ 'lastTradeTimestamp': undefined,
876
+ 'symbol': market['symbol'],
877
+ 'type': market['type'],
878
+ 'timeInForce': undefined,
879
+ 'postOnly': undefined,
880
+ 'side': this.safeStringLower2(order, 'sd', 'orderSide'),
881
+ 'price': this.safeNumber2(order, 'p', 'price'),
882
+ 'stopPrice': undefined,
883
+ 'stopLoss': undefined,
884
+ 'takeProfit': undefined,
885
+ 'amount': this.safeString2(order, 'oq', 'origQty'),
886
+ 'filled': this.safeString2(order, 'eq', 'executedQty'),
887
+ 'remaining': this.safeString(order, 'lq'),
888
+ 'cost': undefined,
889
+ 'average': this.safeString2(order, 'ap', 'avgPrice'),
890
+ 'status': this.parseOrderStatus(this.safeString(order, 'st', 'state')),
891
+ 'fee': {
892
+ 'currency': undefined,
893
+ 'cost': this.safeNumber(order, 'f'),
894
+ },
895
+ 'trades': undefined,
896
+ }, market);
897
+ }
898
+ handleOrder(client, message) {
899
+ //
900
+ // spot
901
+ //
902
+ // {
903
+ // "topic": "order",
904
+ // "event": "order",
905
+ // "data": {
906
+ // "s": "btc_usdt", // symbol
907
+ // "t": 1656043204763, // time happened time
908
+ // "i": "6216559590087220004", // orderId,
909
+ // "ci": "test123", // clientOrderId
910
+ // "st": "PARTIALLY_FILLED", // state
911
+ // "sd": "BUY", // side BUY/SELL
912
+ // "eq": "2", // executedQty executed quantity
913
+ // "ap": "30000", // avg price
914
+ // "f": "0.002" // fee
915
+ // }
916
+ // }
917
+ //
918
+ // contract
919
+ //
920
+ // {
921
+ // "topic": "order",
922
+ // "event": "order@123456",
923
+ // "data": {
924
+ // "symbol": "btc_usdt", // Trading pair
925
+ // "orderId": "1234", // Order Id
926
+ // "origQty": "34244", // Original Quantity
927
+ // "avgPrice": "123", // Quantity
928
+ // "price": "1111", // Average price
929
+ // "executedQty": "34244", // Volume (Cont)
930
+ // "orderSide": "BUY", // BUY, SELL
931
+ // "positionSide": "LONG", // LONG, SHORT
932
+ // "marginFrozen": "123", // Occupied margin
933
+ // "sourceType": "default", // DEFAULT:normal order,ENTRUST:plan commission,PROFIR:Take Profit and Stop Loss
934
+ // "sourceId" : "1231231", // Triggering conditions ID
935
+ // "state": "", // state:NEW:New order (unfilled);PARTIALLY_FILLED:Partial deal;PARTIALLY_CANCELED:Partial revocation;FILLED:Filled;CANCELED:Cancled;REJECTED:Order failed;EXPIRED:Expired
936
+ // "createTime": 1731231231, // CreateTime
937
+ // "clientOrderId": "204788317630342726"
938
+ // }
939
+ // }
940
+ //
941
+ let orders = this.orders;
942
+ if (orders === undefined) {
943
+ const limit = this.safeInteger(this.options, 'ordersLimit');
944
+ orders = new Cache.ArrayCacheBySymbolById(limit);
945
+ this.orders = orders;
946
+ }
947
+ const order = this.safeDict(message, 'data', {});
948
+ const marketId = this.safeString2(order, 's', 'symbol');
949
+ if (marketId !== undefined) {
950
+ const tradeType = ('symbol' in order) ? 'contract' : 'spot';
951
+ const market = this.safeMarket(marketId, undefined, undefined, tradeType);
952
+ const parsed = this.parseWsOrder(order, market);
953
+ orders.append(parsed);
954
+ client.resolve(orders, 'order::' + tradeType);
955
+ }
956
+ return message;
957
+ }
958
+ handleBalance(client, message) {
959
+ //
960
+ // spot
961
+ //
962
+ // {
963
+ // topic: 'balance',
964
+ // event: 'balance',
965
+ // data: {
966
+ // a: 3513677381884,
967
+ // t: 1684250056775,
968
+ // c: 'usdt',
969
+ // b: '7.71000000',
970
+ // f: '0.00000000',
971
+ // z: 'SPOT'
972
+ // }
973
+ // }
974
+ //
975
+ // contract
976
+ //
977
+ // {
978
+ // "topic": "balance",
979
+ // "event": "balance@123456",
980
+ // "data": {
981
+ // "coin": "usdt",
982
+ // "underlyingType": 1, // 1:Coin-M,2:USDT-M
983
+ // "walletBalance": "123", // Balance
984
+ // "openOrderMarginFrozen": "123", // Frozen order
985
+ // "isolatedMargin": "213", // Isolated Margin
986
+ // "crossedMargin": "0" // Crossed Margin
987
+ // "availableBalance": '2.256114450000000000',
988
+ // "coupon": '0',
989
+ // "bonus": '0'
990
+ // }
991
+ // }
992
+ //
993
+ const data = this.safeDict(message, 'data', {});
994
+ const currencyId = this.safeString2(data, 'c', 'coin');
995
+ const code = this.safeCurrencyCode(currencyId);
996
+ const account = this.account();
997
+ account['free'] = this.safeString(data, 'availableBalance');
998
+ account['used'] = this.safeString(data, 'f');
999
+ account['total'] = this.safeString2(data, 'b', 'walletBalance');
1000
+ this.balance[code] = account;
1001
+ this.balance = this.safeBalance(this.balance);
1002
+ const tradeType = ('coin' in data) ? 'contract' : 'spot';
1003
+ client.resolve(this.balance, 'balance::' + tradeType);
1004
+ }
1005
+ handleMyTrades(client, message) {
1006
+ //
1007
+ // spot
1008
+ //
1009
+ // {
1010
+ // "topic": "trade",
1011
+ // "event": "trade",
1012
+ // "data": {
1013
+ // "s": "btc_usdt", // symbol
1014
+ // "t": 1656043204763, // time
1015
+ // "i": "6316559590087251233", // tradeId
1016
+ // "oi": "6216559590087220004", // orderId
1017
+ // "p": "30000", // trade price
1018
+ // "q": "3", // qty quantity
1019
+ // "v": "90000" // volume trade amount
1020
+ // }
1021
+ // }
1022
+ //
1023
+ // contract
1024
+ //
1025
+ // {
1026
+ // "topic": "trade",
1027
+ // "event": "trade@123456",
1028
+ // "data": {
1029
+ // "symbol": 'btc_usdt',
1030
+ // "orderSide": 'SELL',
1031
+ // "positionSide": 'LONG',
1032
+ // "orderId": '231485367663419328',
1033
+ // "price": '27152.7',
1034
+ // "quantity": '33',
1035
+ // "marginUnfrozen": '2.85318000',
1036
+ // "timestamp": 1684892412565
1037
+ // }
1038
+ // }
1039
+ //
1040
+ const data = this.safeDict(message, 'data', {});
1041
+ let stored = this.myTrades;
1042
+ if (stored === undefined) {
1043
+ const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
1044
+ stored = new Cache.ArrayCacheBySymbolById(limit);
1045
+ this.myTrades = stored;
1046
+ }
1047
+ const parsedTrade = this.parseTrade(data);
1048
+ const market = this.market(parsedTrade['symbol']);
1049
+ stored.append(parsedTrade);
1050
+ const tradeType = market['contract'] ? 'contract' : 'spot';
1051
+ client.resolve(stored, 'trade::' + tradeType);
1052
+ }
1053
+ handleMessage(client, message) {
1054
+ const event = this.safeString(message, 'event');
1055
+ if (event === 'pong') {
1056
+ client.onPong();
1057
+ }
1058
+ else if (event !== undefined) {
1059
+ const topic = this.safeString(message, 'topic');
1060
+ const methods = {
1061
+ 'kline': this.handleOHLCV,
1062
+ 'depth': this.handleOrderBook,
1063
+ 'depth_update': this.handleOrderBook,
1064
+ 'ticker': this.handleTicker,
1065
+ 'agg_ticker': this.handleTicker,
1066
+ 'tickers': this.handleTickers,
1067
+ 'agg_tickers': this.handleTickers,
1068
+ 'balance': this.handleBalance,
1069
+ 'order': this.handleOrder,
1070
+ };
1071
+ let method = this.safeValue(methods, topic);
1072
+ if (topic === 'trade') {
1073
+ const data = this.safeDict(message, 'data');
1074
+ if (('oi' in data) || ('orderId' in data)) {
1075
+ method = this.handleMyTrades;
1076
+ }
1077
+ else {
1078
+ method = this.handleTrade;
1079
+ }
1080
+ }
1081
+ if (method !== undefined) {
1082
+ method.call(this, client, message);
1083
+ }
1084
+ }
1085
+ }
1086
+ ping(client) {
1087
+ client.lastPong = this.milliseconds();
1088
+ return 'ping';
1089
+ }
1090
+ handleErrorMessage(client, message) {
1091
+ //
1092
+ // {
1093
+ // "id": "123",
1094
+ // "code": 401,
1095
+ // "msg": "token expire"
1096
+ // }
1097
+ //
1098
+ const msg = this.safeString(message, 'msg');
1099
+ if ((msg === 'invalid_listen_key') || (msg === 'token expire')) {
1100
+ client.subscriptions['token'] = undefined;
1101
+ this.getListenKey(true);
1102
+ return;
1103
+ }
1104
+ client.reject(message);
1105
+ }
1106
+ }
1107
+
1108
+ module.exports = xt;