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