ccxt 4.1.8 → 4.1.9

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 (47) hide show
  1. package/README.md +3 -3
  2. package/dist/ccxt.browser.js +1240 -189
  3. package/dist/ccxt.browser.min.js +7 -7
  4. package/dist/cjs/ccxt.js +3 -1
  5. package/dist/cjs/src/base/Exchange.js +58 -2
  6. package/dist/cjs/src/bingx.js +100 -39
  7. package/dist/cjs/src/bitget.js +26 -2
  8. package/dist/cjs/src/gate.js +9 -1
  9. package/dist/cjs/src/kucoinfutures.js +2 -2
  10. package/dist/cjs/src/pro/bingx.js +891 -0
  11. package/js/ccxt.d.ts +6 -3
  12. package/js/ccxt.js +3 -1
  13. package/js/src/abstract/bingx.d.ts +1 -0
  14. package/js/src/base/Exchange.d.ts +6 -3
  15. package/js/src/base/Exchange.js +58 -2
  16. package/js/src/base/types.d.ts +7 -0
  17. package/js/src/binance.d.ts +17 -17
  18. package/js/src/bingx.d.ts +4 -3
  19. package/js/src/bingx.js +100 -39
  20. package/js/src/bitfinex2.d.ts +13 -13
  21. package/js/src/bitget.d.ts +15 -15
  22. package/js/src/bitget.js +26 -2
  23. package/js/src/bitmex.d.ts +15 -15
  24. package/js/src/bybit.d.ts +23 -23
  25. package/js/src/coinbase.d.ts +16 -16
  26. package/js/src/coinbasepro.d.ts +12 -12
  27. package/js/src/coinex.d.ts +2 -2
  28. package/js/src/cryptocom.d.ts +12 -12
  29. package/js/src/deribit.d.ts +2 -2
  30. package/js/src/digifinex.d.ts +2 -2
  31. package/js/src/gate.d.ts +10 -10
  32. package/js/src/gate.js +9 -1
  33. package/js/src/huobi.d.ts +16 -16
  34. package/js/src/kraken.d.ts +2 -2
  35. package/js/src/krakenfutures.d.ts +6 -6
  36. package/js/src/kucoin.d.ts +13 -13
  37. package/js/src/kucoinfutures.d.ts +10 -10
  38. package/js/src/kucoinfutures.js +2 -2
  39. package/js/src/mexc.d.ts +3 -3
  40. package/js/src/okx.d.ts +13 -13
  41. package/js/src/phemex.d.ts +2 -2
  42. package/js/src/poloniex.d.ts +5 -5
  43. package/js/src/pro/bingx.d.ts +24 -0
  44. package/js/src/pro/bingx.js +892 -0
  45. package/js/src/woo.d.ts +2 -2
  46. package/package.json +1 -1
  47. package/skip-tests.json +3 -0
@@ -0,0 +1,891 @@
1
+ 'use strict';
2
+
3
+ var bingx$1 = require('../bingx.js');
4
+ var errors = require('../base/errors.js');
5
+ var Cache = require('../base/ws/Cache.js');
6
+
7
+ // ---------------------------------------------------------------------------
8
+ // ---------------------------------------------------------------------------
9
+ class bingx extends bingx$1 {
10
+ describe() {
11
+ return this.deepExtend(super.describe(), {
12
+ 'has': {
13
+ 'ws': true,
14
+ 'watchTrades': true,
15
+ 'watchOrderBook': true,
16
+ 'watchOHLCV': true,
17
+ 'watchOrders': true,
18
+ 'watchMyTrades': true,
19
+ 'watchTicker': false,
20
+ 'watchTickers': false,
21
+ 'watchBalance': true,
22
+ },
23
+ 'urls': {
24
+ 'api': {
25
+ 'ws': {
26
+ 'spot': 'wss://open-api-ws.bingx.com/market',
27
+ 'swap': 'wss://open-api-swap.bingx.com/swap-market',
28
+ },
29
+ },
30
+ },
31
+ 'options': {
32
+ 'ws': {
33
+ 'gunzip': true,
34
+ },
35
+ 'swap': {
36
+ 'timeframes': {
37
+ '1m': '1m',
38
+ '3m': '3m',
39
+ '5m': '5m',
40
+ '15m': '15m',
41
+ '30m': '30m',
42
+ '1h': '1h',
43
+ '2h': '2h',
44
+ '4h': '4h',
45
+ '6h': '6h',
46
+ '12h': '12h',
47
+ '1d': '1d',
48
+ '3d': '3d',
49
+ '1w': '1w',
50
+ '1M': '1M',
51
+ },
52
+ },
53
+ 'spot': {
54
+ 'timeframes': {
55
+ '1m': '1min',
56
+ '5m': '5min',
57
+ '15m': '15min',
58
+ '30m': '30min',
59
+ '1h': '60min',
60
+ '1d': '1day',
61
+ },
62
+ },
63
+ },
64
+ 'streaming': {
65
+ 'keepAlive': 1800000, // 30 minutes
66
+ },
67
+ });
68
+ }
69
+ async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
70
+ /**
71
+ * @method
72
+ * @name bingx#watchTrades
73
+ * @description watches information on multiple trades made in a market
74
+ * @see https://bingx-api.github.io/docs/#/spot/socket/market.html#Subscribe%20to%20tick-by-tick
75
+ * @see https://bingx-api.github.io/docs/#/swapV2/socket/market.html#Subscribe%20the%20Latest%20Trade%20Detail
76
+ * @param {string} symbol unified market symbol of the market orders were made in
77
+ * @param {int} [since] the earliest time in ms to fetch orders for
78
+ * @param {int} [limit] the maximum number of orde structures to retrieve
79
+ * @param {object} [params] extra parameters specific to the bingx api endpoint
80
+ * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure
81
+ */
82
+ await this.loadMarkets();
83
+ const market = this.market(symbol);
84
+ const [marketType, query] = this.handleMarketTypeAndParams('watchTrades', market, params);
85
+ const url = this.safeValue(this.urls['api']['ws'], marketType);
86
+ if (url === undefined) {
87
+ throw new errors.BadRequest(this.id + ' watchTrades is not supported for ' + marketType + ' markets.');
88
+ }
89
+ const messageHash = market['id'] + '@trade';
90
+ const uuid = this.uuid();
91
+ const request = {
92
+ 'id': uuid,
93
+ 'dataType': messageHash,
94
+ };
95
+ if (marketType === 'swap') {
96
+ request['reqType'] = 'sub';
97
+ }
98
+ const trades = await this.watch(url, messageHash, this.extend(request, query), messageHash);
99
+ if (this.newUpdates) {
100
+ limit = trades.getLimit(symbol, limit);
101
+ }
102
+ return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
103
+ }
104
+ handleTrades(client, message) {
105
+ //
106
+ // spot
107
+ // first snapshot
108
+ //
109
+ // {
110
+ // id: 'd83b78ce-98be-4dc2-b847-12fe471b5bc5',
111
+ // code: 0,
112
+ // msg: 'SUCCESS',
113
+ // timestamp: 1690214699854
114
+ // }
115
+ //
116
+ // subsequent updates
117
+ //
118
+ // {
119
+ // code: 0,
120
+ // data: {
121
+ // E: 1690214529432,
122
+ // T: 1690214529386,
123
+ // e: 'trade',
124
+ // m: true,
125
+ // p: '29110.19',
126
+ // q: '0.1868',
127
+ // s: 'BTC-USDT',
128
+ // t: '57903921'
129
+ // },
130
+ // dataType: 'BTC-USDT@trade',
131
+ // success: true
132
+ // }
133
+ //
134
+ //
135
+ // swap
136
+ // first snapshot
137
+ //
138
+ // {
139
+ // id: '2aed93b1-6e1e-4038-aeba-f5eeaec2ca48',
140
+ // code: 0,
141
+ // msg: '',
142
+ // dataType: '',
143
+ // data: null
144
+ // }
145
+ //
146
+ // subsequent updates
147
+ //
148
+ //
149
+ // {
150
+ // code: 0,
151
+ // dataType: 'BTC-USDT@trade',
152
+ // data: [
153
+ // {
154
+ // q: '0.0421',
155
+ // p: '29023.5',
156
+ // T: 1690221401344,
157
+ // m: false,
158
+ // s: 'BTC-USDT'
159
+ // },
160
+ // ...
161
+ // ]
162
+ // }
163
+ //
164
+ const data = this.safeValue(message, 'data', []);
165
+ const messageHash = this.safeString(message, 'dataType');
166
+ const marketId = messageHash.split('@')[0];
167
+ const marketType = client.url.indexOf('swap') >= 0 ? 'swap' : 'spot';
168
+ const market = this.safeMarket(marketId, undefined, undefined, marketType);
169
+ const symbol = market['symbol'];
170
+ let trades = undefined;
171
+ if (Array.isArray(data)) {
172
+ trades = this.parseTrades(data, market);
173
+ }
174
+ else {
175
+ trades = [this.parseTrade(data, market)];
176
+ }
177
+ let stored = this.safeValue(this.trades, symbol);
178
+ if (stored === undefined) {
179
+ const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
180
+ stored = new Cache.ArrayCache(limit);
181
+ this.trades[symbol] = stored;
182
+ }
183
+ for (let j = 0; j < trades.length; j++) {
184
+ stored.append(trades[j]);
185
+ }
186
+ client.resolve(stored, messageHash);
187
+ }
188
+ async watchOrderBook(symbol, limit = undefined, params = {}) {
189
+ /**
190
+ * @method
191
+ * @name bingx#watchOrderBook
192
+ * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
193
+ * @see https://bingx-api.github.io/docs/#/spot/socket/market.html#Subscribe%20Market%20Depth%20Data
194
+ * @see https://bingx-api.github.io/docs/#/swapV2/socket/market.html#Subscribe%20Market%20Depth%20Data
195
+ * @param {string} symbol unified symbol of the market to fetch the order book for
196
+ * @param {int} [limit] the maximum amount of order book entries to return
197
+ * @param {object} [params] extra parameters specific to the bingx api endpoint
198
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
199
+ */
200
+ await this.loadMarkets();
201
+ const market = this.market(symbol);
202
+ const [marketType, query] = this.handleMarketTypeAndParams('watchOrderBook', market, params);
203
+ if (limit === undefined) {
204
+ limit = 100;
205
+ }
206
+ else {
207
+ if (marketType === 'swap') {
208
+ if ((limit !== 5) && (limit !== 10) && (limit !== 20) && (limit !== 50) && (limit !== 100)) {
209
+ throw new errors.BadRequest(this.id + ' watchOrderBook() (swap) only supports limit 5, 10, 20, 50, and 100');
210
+ }
211
+ }
212
+ else if (marketType === 'spot') {
213
+ if ((limit !== 20) && (limit !== 100)) {
214
+ throw new errors.BadRequest(this.id + ' watchOrderBook() (spot) only supports limit 20, and 100');
215
+ }
216
+ }
217
+ }
218
+ const url = this.safeValue(this.urls['api']['ws'], marketType);
219
+ if (url === undefined) {
220
+ throw new errors.BadRequest(this.id + ' watchOrderBook is not supported for ' + marketType + ' markets.');
221
+ }
222
+ const messageHash = market['id'] + '@depth' + limit.toString();
223
+ const uuid = this.uuid();
224
+ const request = {
225
+ 'id': uuid,
226
+ 'dataType': messageHash,
227
+ };
228
+ if (marketType === 'swap') {
229
+ request['reqType'] = 'sub';
230
+ }
231
+ const orderbook = await this.watch(url, messageHash, this.deepExtend(request, query), messageHash);
232
+ return orderbook.limit();
233
+ }
234
+ handleDelta(bookside, delta) {
235
+ const price = this.safeFloat(delta, 0);
236
+ const amount = this.safeFloat(delta, 1);
237
+ bookside.store(price, amount);
238
+ }
239
+ handleOrderBook(client, message) {
240
+ //
241
+ // spot
242
+ //
243
+ //
244
+ // {
245
+ // code: 0,
246
+ // dataType: 'BTC-USDT@depth20',
247
+ // data: {
248
+ // bids: [
249
+ // [ '28852.9', '34.2621' ],
250
+ // ...
251
+ // ],
252
+ // asks: [
253
+ // [ '28864.9', '23.4079' ],
254
+ // ...
255
+ // ]
256
+ // },
257
+ // dataType: 'BTC-USDT@depth20',
258
+ // success: true
259
+ // }
260
+ //
261
+ // swap
262
+ //
263
+ //
264
+ // {
265
+ // code: 0,
266
+ // dataType: 'BTC-USDT@depth20',
267
+ // data: {
268
+ // bids: [
269
+ // [ '28852.9', '34.2621' ],
270
+ // ...
271
+ // ],
272
+ // asks: [
273
+ // [ '28864.9', '23.4079' ],
274
+ // ...
275
+ // ]
276
+ // }
277
+ // }
278
+ //
279
+ const data = this.safeValue(message, 'data', []);
280
+ const messageHash = this.safeString(message, 'dataType');
281
+ const marketId = messageHash.split('@')[0];
282
+ const marketType = client.url.indexOf('swap') >= 0 ? 'swap' : 'spot';
283
+ const market = this.safeMarket(marketId, undefined, undefined, marketType);
284
+ const symbol = market['symbol'];
285
+ let orderbook = this.safeValue(this.orderbooks, symbol);
286
+ if (orderbook === undefined) {
287
+ orderbook = this.orderBook();
288
+ }
289
+ const snapshot = this.parseOrderBook(data, symbol, undefined, 'bids', 'asks', 0, 1);
290
+ orderbook.reset(snapshot);
291
+ this.orderbooks[symbol] = orderbook;
292
+ client.resolve(orderbook, messageHash);
293
+ }
294
+ parseWsOHLCV(ohlcv, market = undefined) {
295
+ //
296
+ // {
297
+ // c: '28909.0',
298
+ // o: '28915.4',
299
+ // h: '28915.4',
300
+ // l: '28896.1',
301
+ // v: '27.6919',
302
+ // T: 1690907580000
303
+ // }
304
+ //
305
+ return [
306
+ this.safeInteger(ohlcv, 'T'),
307
+ this.safeNumber(ohlcv, 'o'),
308
+ this.safeNumber(ohlcv, 'h'),
309
+ this.safeNumber(ohlcv, 'l'),
310
+ this.safeNumber(ohlcv, 'c'),
311
+ this.safeNumber(ohlcv, 'v'),
312
+ ];
313
+ }
314
+ handleOHLCV(client, message) {
315
+ //
316
+ // spot
317
+ //
318
+ // {
319
+ // code: 0,
320
+ // data: {
321
+ // E: 1696687498608,
322
+ // K: {
323
+ // T: 1696687499999,
324
+ // c: '27917.829',
325
+ // h: '27918.427',
326
+ // i: '1min',
327
+ // l: '27917.7',
328
+ // n: 262,
329
+ // o: '27917.91',
330
+ // q: '25715.359197',
331
+ // s: 'BTC-USDT',
332
+ // t: 1696687440000,
333
+ // v: '0.921100'
334
+ // },
335
+ // e: 'kline',
336
+ // s: 'BTC-USDT'
337
+ // },
338
+ // dataType: 'BTC-USDT@kline_1min',
339
+ // success: true
340
+ // }
341
+ //
342
+ // swap
343
+ // {
344
+ // code: 0,
345
+ // dataType: 'BTC-USDT@kline_1m',
346
+ // s: 'BTC-USDT',
347
+ // data: [
348
+ // {
349
+ // c: '28909.0',
350
+ // o: '28915.4',
351
+ // h: '28915.4',
352
+ // l: '28896.1',
353
+ // v: '27.6919',
354
+ // T: 1690907580000
355
+ // }
356
+ // ]
357
+ // }
358
+ //
359
+ const data = this.safeValue(message, 'data', []);
360
+ let candles = undefined;
361
+ if (Array.isArray(data)) {
362
+ candles = data;
363
+ }
364
+ else {
365
+ candles = [this.safeValue(data, 'K', [])];
366
+ }
367
+ const messageHash = this.safeString(message, 'dataType');
368
+ const timeframeId = messageHash.split('_')[1];
369
+ const marketId = messageHash.split('@')[0];
370
+ const marketType = client.url.indexOf('swap') >= 0 ? 'swap' : 'spot';
371
+ const market = this.safeMarket(marketId, undefined, undefined, marketType);
372
+ const symbol = market['symbol'];
373
+ this.ohlcvs[symbol] = this.safeValue(this.ohlcvs, symbol, {});
374
+ let stored = this.safeValue(this.ohlcvs[symbol], timeframeId);
375
+ if (stored === undefined) {
376
+ const limit = this.safeInteger(this.options, 'OHLCVLimit', 1000);
377
+ stored = new Cache.ArrayCacheByTimestamp(limit);
378
+ this.ohlcvs[symbol][timeframeId] = stored;
379
+ }
380
+ for (let i = 0; i < candles.length; i++) {
381
+ const candle = candles[i];
382
+ const parsed = this.parseWsOHLCV(candle, market);
383
+ stored.append(parsed);
384
+ }
385
+ client.resolve(stored, messageHash);
386
+ }
387
+ async watchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
388
+ /**
389
+ * @method
390
+ * @name bingx#watchOHLCV
391
+ * @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
392
+ * @see https://bingx-api.github.io/docs/#/spot/socket/market.html#K%E7%BA%BF%20Streams
393
+ * @see https://bingx-api.github.io/docs/#/swapV2/socket/market.html#Subscribe%20K-Line%20Data
394
+ * @param {string} symbol unified symbol of the market to fetch OHLCV data for
395
+ * @param {string} timeframe the length of time each candle represents
396
+ * @param {int} [since] timestamp in ms of the earliest candle to fetch
397
+ * @param {int} [limit] the maximum amount of candles to fetch
398
+ * @param {object} [params] extra parameters specific to the bingx api endpoint
399
+ * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
400
+ */
401
+ const market = this.market(symbol);
402
+ const [marketType, query] = this.handleMarketTypeAndParams('watchOHLCV', market, params);
403
+ const url = this.safeValue(this.urls['api']['ws'], marketType);
404
+ if (url === undefined) {
405
+ throw new errors.BadRequest(this.id + ' watchOHLCV is not supported for ' + marketType + ' markets.');
406
+ }
407
+ const options = this.safeValue(this.options, marketType, {});
408
+ const timeframes = this.safeValue(options, 'timeframes', {});
409
+ const interval = this.safeString(timeframes, timeframe, timeframe);
410
+ const messageHash = market['id'] + '@kline_' + interval;
411
+ const uuid = this.uuid();
412
+ const request = {
413
+ 'id': uuid,
414
+ 'dataType': messageHash,
415
+ };
416
+ if (marketType === 'swap') {
417
+ request['reqType'] = 'sub';
418
+ }
419
+ const ohlcv = await this.watch(url, messageHash, this.extend(request, query), messageHash);
420
+ if (this.newUpdates) {
421
+ limit = ohlcv.getLimit(symbol, limit);
422
+ }
423
+ return this.filterBySinceLimit(ohlcv, since, limit, 0, true);
424
+ }
425
+ async watchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
426
+ /**
427
+ * @method
428
+ * @name bingx#watchOrders
429
+ * @see https://bingx-api.github.io/docs/#/spot/socket/account.html#Subscription%20order%20update%20data
430
+ * @see https://bingx-api.github.io/docs/#/swapV2/socket/account.html#Account%20balance%20and%20position%20update%20push
431
+ * @description watches information on multiple orders made by the user
432
+ * @param {string} symbol unified market symbol of the market orders were made in
433
+ * @param {int} [since] the earliest time in ms to fetch orders for
434
+ * @param {int} [limit] the maximum number of orde structures to retrieve
435
+ * @param {object} [params] extra parameters specific to the bingx api endpoint
436
+ * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
437
+ */
438
+ await this.loadMarkets();
439
+ await this.authenticate();
440
+ let type = undefined;
441
+ let market = undefined;
442
+ if (symbol !== undefined) {
443
+ market = this.market(symbol);
444
+ symbol = market['symbol'];
445
+ }
446
+ [type, params] = this.handleMarketTypeAndParams('watchOrders', market, params);
447
+ const isSpot = (type === 'spot');
448
+ const spotHash = 'spot:private';
449
+ const swapHash = 'swap:private';
450
+ const subscriptionHash = isSpot ? spotHash : swapHash;
451
+ const spotMessageHash = 'spot:order';
452
+ const swapMessageHash = 'swap:order';
453
+ let messageHash = isSpot ? spotMessageHash : swapMessageHash;
454
+ if (market !== undefined) {
455
+ messageHash += ':' + symbol;
456
+ }
457
+ const url = this.urls['api']['ws'][type] + '?listenKey=' + this.options['listenKey'];
458
+ let request = undefined;
459
+ const uuid = this.uuid();
460
+ if (isSpot) {
461
+ request = {
462
+ 'id': uuid,
463
+ 'dataType': 'spot.executionReport',
464
+ };
465
+ }
466
+ const orders = await this.watch(url, messageHash, request, subscriptionHash);
467
+ if (this.newUpdates) {
468
+ limit = orders.getLimit(symbol, limit);
469
+ }
470
+ return this.filterBySymbolSinceLimit(orders, symbol, since, limit, true);
471
+ }
472
+ async watchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
473
+ /**
474
+ * @method
475
+ * @name bingx#watchMyTrades
476
+ * @see https://bingx-api.github.io/docs/#/spot/socket/account.html#Subscription%20order%20update%20data
477
+ * @see https://bingx-api.github.io/docs/#/swapV2/socket/account.html#Account%20balance%20and%20position%20update%20push
478
+ * @description watches information on multiple trades made by the user
479
+ * @param {string} symbol unified market symbol of the market trades were made in
480
+ * @param {int} [since] the earliest time in ms to trades orders for
481
+ * @param {int} [limit] the maximum number of trades structures to retrieve
482
+ * @param {object} [params] extra parameters specific to the bingx api endpoint
483
+ * @returns {object[]} a list of [trade structures]{@link https://github.com/ccxt/ccxt/wiki/Manual#trade-structure
484
+ */
485
+ await this.loadMarkets();
486
+ await this.authenticate();
487
+ let type = undefined;
488
+ let market = undefined;
489
+ if (symbol !== undefined) {
490
+ market = this.market(symbol);
491
+ symbol = market['symbol'];
492
+ }
493
+ [type, params] = this.handleMarketTypeAndParams('watchOrders', market, params);
494
+ const isSpot = (type === 'spot');
495
+ const spotSubHash = 'spot:private';
496
+ const swapSubHash = 'swap:private';
497
+ const subscriptionHash = isSpot ? spotSubHash : swapSubHash;
498
+ const spotMessageHash = 'spot:mytrades';
499
+ const swapMessageHash = 'swap:mytrades';
500
+ let messageHash = isSpot ? spotMessageHash : swapMessageHash;
501
+ if (market !== undefined) {
502
+ messageHash += ':' + symbol;
503
+ }
504
+ const url = this.urls['api']['ws'][type] + '?listenKey=' + this.options['listenKey'];
505
+ let request = undefined;
506
+ const uuid = this.uuid();
507
+ if (isSpot) {
508
+ request = {
509
+ 'id': uuid,
510
+ 'dataType': 'spot.executionReport',
511
+ };
512
+ }
513
+ const trades = await this.watch(url, messageHash, request, subscriptionHash);
514
+ if (this.newUpdates) {
515
+ limit = trades.getLimit(symbol, limit);
516
+ }
517
+ return this.filterBySymbolSinceLimit(trades, symbol, since, limit, true);
518
+ }
519
+ async watchBalance(params = {}) {
520
+ /**
521
+ * @method
522
+ * @name bingx#watchBalance
523
+ * @see https://bingx-api.github.io/docs/#/spot/socket/account.html#Subscription%20order%20update%20data
524
+ * @see https://bingx-api.github.io/docs/#/swapV2/socket/account.html#Account%20balance%20and%20position%20update%20push
525
+ * @description query for balance and get the amount of funds available for trading or funds locked in orders
526
+ * @param {object} [params] extra parameters specific to the bingx api endpoint
527
+ * @returns {object} a [balance structure]{@link https://docs.ccxt.com/en/latest/manual.html?#balance-structure}
528
+ */
529
+ await this.loadMarkets();
530
+ await this.authenticate();
531
+ let type = undefined;
532
+ [type, params] = this.handleMarketTypeAndParams('watchBalance', undefined, params);
533
+ const isSpot = (type === 'spot');
534
+ const spotSubHash = 'spot:balance';
535
+ const swapSubHash = 'swap:private';
536
+ const spotMessageHash = 'spot:balance';
537
+ const swapMessageHash = 'swap:balance';
538
+ const messageHash = isSpot ? spotMessageHash : swapMessageHash;
539
+ const subscriptionHash = isSpot ? spotSubHash : swapSubHash;
540
+ const url = this.urls['api']['ws'][type] + '?listenKey=' + this.options['listenKey'];
541
+ let request = undefined;
542
+ const uuid = this.uuid();
543
+ if (type === 'spot') {
544
+ request = {
545
+ 'id': uuid,
546
+ 'dataType': 'ACCOUNT_UPDATE',
547
+ };
548
+ }
549
+ return await this.watch(url, messageHash, request, subscriptionHash);
550
+ }
551
+ handleErrorMessage(client, message) {
552
+ //
553
+ // { code: 100400, msg: '', timestamp: 1696245808833 }
554
+ //
555
+ // {
556
+ // code: 100500,
557
+ // id: '9cd37d32-da98-440b-bd04-37e7dbcf51ad',
558
+ // msg: '',
559
+ // timestamp: 1696245842307
560
+ // }
561
+ const code = this.safeString(message, 'code');
562
+ try {
563
+ if (code !== undefined) {
564
+ const feedback = this.id + ' ' + this.json(message);
565
+ this.throwExactlyMatchedException(this.exceptions['exact'], code, feedback);
566
+ }
567
+ }
568
+ catch (e) {
569
+ client.reject(e);
570
+ }
571
+ return true;
572
+ }
573
+ async authenticate(params = {}) {
574
+ const time = this.milliseconds();
575
+ const listenKey = this.safeString(this.options, 'listenKey');
576
+ if (listenKey === undefined) {
577
+ const response = await this.userAuthPrivatePostUserDataStream();
578
+ this.options['listenKey'] = this.safeString(response, 'listenKey');
579
+ this.options['lastAuthenticatedTime'] = time;
580
+ return;
581
+ }
582
+ const lastAuthenticatedTime = this.safeInteger(this.options, 'lastAuthenticatedTime', 0);
583
+ const listenKeyRefreshRate = this.safeInteger(this.options, 'listenKeyRefreshRate', 3600000); // 1 hour
584
+ if (time - lastAuthenticatedTime > listenKeyRefreshRate) {
585
+ const response = await this.userAuthPrivatePostUserDataStream({ 'listenKey': listenKey }); // extend the expiry
586
+ this.options['listenKey'] = this.safeString(response, 'listenKey');
587
+ this.options['lastAuthenticatedTime'] = time;
588
+ }
589
+ }
590
+ async pong(client, message) {
591
+ //
592
+ // spot
593
+ // {
594
+ // ping: '5963ba3db76049b2870f9a686b2ebaac',
595
+ // time: '2023-10-02T18:51:55.089+0800'
596
+ // }
597
+ // swap
598
+ // Ping
599
+ //
600
+ if (message === 'Ping') {
601
+ await client.send('Pong');
602
+ }
603
+ else {
604
+ const ping = this.safeString(message, 'ping');
605
+ const time = this.safeString(message, 'time');
606
+ await client.send({
607
+ 'pong': ping,
608
+ 'time': time,
609
+ });
610
+ }
611
+ }
612
+ handleOrder(client, message) {
613
+ //
614
+ // {
615
+ // "code": 0,
616
+ // "dataType": "spot.executionReport",
617
+ // "data": {
618
+ // "e": "executionReport",
619
+ // "E": 1694680212947,
620
+ // "s": "LTC-USDT",
621
+ // "S": "BUY",
622
+ // "o": "LIMIT",
623
+ // "q": 0.1,
624
+ // "p": 50,
625
+ // "x": "NEW",
626
+ // "X": "PENDING",
627
+ // "i": 1702238305204043800,
628
+ // "l": 0,
629
+ // "z": 0,
630
+ // "L": 0,
631
+ // "n": 0,
632
+ // "N": "",
633
+ // "T": 0,
634
+ // "t": 0,
635
+ // "O": 1694680212676,
636
+ // "Z": 0,
637
+ // "Y": 0,
638
+ // "Q": 0,
639
+ // "m": false
640
+ // }
641
+ // }
642
+ //
643
+ // {
644
+ // code: 0,
645
+ // dataType: 'spot.executionReport',
646
+ // data: {
647
+ // e: 'executionReport',
648
+ // E: 1694681809302,
649
+ // s: 'LTC-USDT',
650
+ // S: 'BUY',
651
+ // o: 'MARKET',
652
+ // q: 0,
653
+ // p: 62.29,
654
+ // x: 'TRADE',
655
+ // X: 'FILLED',
656
+ // i: '1702245001712369664',
657
+ // l: 0.0802,
658
+ // z: 0.0802,
659
+ // L: 62.308,
660
+ // n: -0.0000802,
661
+ // N: 'LTC',
662
+ // T: 1694681809256,
663
+ // t: 38259147,
664
+ // O: 1694681809248,
665
+ // Z: 4.9971016,
666
+ // Y: 4.9971016,
667
+ // Q: 5,
668
+ // m: false
669
+ // }
670
+ // }
671
+ // swap
672
+ // {
673
+ // "e": "ORDER_TRADE_UPDATE",
674
+ // "E": 1696843635475,
675
+ // "o": {
676
+ // "s": "LTC-USDT",
677
+ // "c": "",
678
+ // "i": "1711312357852147712",
679
+ // "S": "BUY",
680
+ // "o": "MARKET",
681
+ // "q": "0.10000000",
682
+ // "p": "64.35010000",
683
+ // "ap": "64.36000000",
684
+ // "x": "TRADE",
685
+ // "X": "FILLED",
686
+ // "N": "USDT",
687
+ // "n": "-0.00321800",
688
+ // "T": 0,
689
+ // "wt": "MARK_PRICE",
690
+ // "ps": "LONG",
691
+ // "rp": "0.00000000",
692
+ // "z": "0.10000000"
693
+ // }
694
+ // }
695
+ //
696
+ const isSpot = ('dataType' in message);
697
+ const data = this.safeValue2(message, 'data', 'o', {});
698
+ if (this.orders === undefined) {
699
+ const limit = this.safeInteger(this.options, 'ordersLimit', 1000);
700
+ this.orders = new Cache.ArrayCacheBySymbolById(limit);
701
+ }
702
+ const stored = this.orders;
703
+ const parsedOrder = this.parseOrder(data);
704
+ stored.append(parsedOrder);
705
+ const symbol = parsedOrder['symbol'];
706
+ const spotHash = 'spot:order';
707
+ const swapHash = 'swap:order';
708
+ const messageHash = (isSpot) ? spotHash : swapHash;
709
+ client.resolve(stored, messageHash);
710
+ client.resolve(stored, messageHash + ':' + symbol);
711
+ }
712
+ handleMyTrades(client, message) {
713
+ //
714
+ //
715
+ // {
716
+ // code: 0,
717
+ // dataType: 'spot.executionReport',
718
+ // data: {
719
+ // e: 'executionReport',
720
+ // E: 1694681809302,
721
+ // s: 'LTC-USDT',
722
+ // S: 'BUY',
723
+ // o: 'MARKET',
724
+ // q: 0,
725
+ // p: 62.29,
726
+ // x: 'TRADE',
727
+ // X: 'FILLED',
728
+ // i: '1702245001712369664',
729
+ // l: 0.0802,
730
+ // z: 0.0802,
731
+ // L: 62.308,
732
+ // n: -0.0000802,
733
+ // N: 'LTC',
734
+ // T: 1694681809256,
735
+ // t: 38259147,
736
+ // O: 1694681809248,
737
+ // Z: 4.9971016,
738
+ // Y: 4.9971016,
739
+ // Q: 5,
740
+ // m: false
741
+ // }
742
+ // }
743
+ //
744
+ // swap
745
+ // {
746
+ // "e": "ORDER_TRADE_UPDATE",
747
+ // "E": 1696843635475,
748
+ // "o": {
749
+ // "s": "LTC-USDT",
750
+ // "c": "",
751
+ // "i": "1711312357852147712",
752
+ // "S": "BUY",
753
+ // "o": "MARKET",
754
+ // "q": "0.10000000",
755
+ // "p": "64.35010000",
756
+ // "ap": "64.36000000",
757
+ // "x": "TRADE",
758
+ // "X": "FILLED",
759
+ // "N": "USDT",
760
+ // "n": "-0.00321800",
761
+ // "T": 0,
762
+ // "wt": "MARK_PRICE",
763
+ // "ps": "LONG",
764
+ // "rp": "0.00000000",
765
+ // "z": "0.10000000"
766
+ // }
767
+ // }
768
+ //
769
+ const isSpot = ('dataType' in message);
770
+ const result = this.safeValue2(message, 'data', 'o', {});
771
+ let cachedTrades = this.myTrades;
772
+ if (cachedTrades === undefined) {
773
+ const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
774
+ cachedTrades = new Cache.ArrayCacheBySymbolById(limit);
775
+ this.myTrades = cachedTrades;
776
+ }
777
+ const parsed = this.parseTrade(result);
778
+ const symbol = parsed['symbol'];
779
+ const spotHash = 'spot:mytrades';
780
+ const swapHash = 'swap:mytrades';
781
+ const messageHash = isSpot ? spotHash : swapHash;
782
+ cachedTrades.append(parsed);
783
+ client.resolve(cachedTrades, messageHash);
784
+ client.resolve(cachedTrades, messageHash + ':' + symbol);
785
+ }
786
+ handleBalance(client, message) {
787
+ // spot
788
+ // {
789
+ // "e":"ACCOUNT_UPDATE",
790
+ // "E":1696242817000,
791
+ // "T":1696242817142,
792
+ // "a":{
793
+ // "B":[
794
+ // {
795
+ // "a":"USDT",
796
+ // "bc":"-1.00000000000000000000",
797
+ // "cw":"86.59497382000000050000",
798
+ // "wb":"86.59497382000000050000"
799
+ // }
800
+ // ],
801
+ // "m":"ASSET_TRANSFER"
802
+ // }
803
+ // }
804
+ // swap
805
+ // {
806
+ // "e":"ACCOUNT_UPDATE",
807
+ // "E":1696244249320,
808
+ // "a":{
809
+ // "m":"WITHDRAW",
810
+ // "B":[
811
+ // {
812
+ // "a":"USDT",
813
+ // "wb":"49.81083984",
814
+ // "cw":"49.81083984",
815
+ // "bc":"-1.00000000"
816
+ // }
817
+ // ],
818
+ // "P":[
819
+ // ]
820
+ // }
821
+ // }
822
+ //
823
+ const a = this.safeValue(message, 'a', {});
824
+ const data = this.safeValue(a, 'B', []);
825
+ const timestamp = this.safeInteger2(message, 'T', 'E');
826
+ const type = ('P' in a) ? 'swap' : 'spot';
827
+ if (!(type in this.balance)) {
828
+ this.balance[type] = {};
829
+ }
830
+ this.balance[type]['info'] = data;
831
+ this.balance[type]['timestamp'] = timestamp;
832
+ this.balance[type]['datetime'] = this.iso8601(timestamp);
833
+ for (let i = 0; i < data.length; i++) {
834
+ const balance = data[i];
835
+ const currencyId = this.safeString(balance, 'a');
836
+ const code = this.safeCurrencyCode(currencyId);
837
+ const account = (code in this.balance) ? this.balance[code] : this.account();
838
+ account['total'] = this.safeString(balance, 'wb');
839
+ this.balance[type][code] = account;
840
+ }
841
+ this.balance[type] = this.safeBalance(this.balance[type]);
842
+ client.resolve(this.balance[type], type + ':balance');
843
+ }
844
+ handleMessage(client, message) {
845
+ if (!this.handleErrorMessage(client, message)) {
846
+ return;
847
+ }
848
+ // public subscriptions
849
+ if ((message === 'Ping') || ('ping' in message)) {
850
+ this.spawn(this.pong, client, message);
851
+ return;
852
+ }
853
+ const dataType = this.safeString(message, 'dataType', '');
854
+ if (dataType.indexOf('@depth') >= 0) {
855
+ this.handleOrderBook(client, message);
856
+ return;
857
+ }
858
+ if (dataType.indexOf('@trade') >= 0) {
859
+ this.handleTrades(client, message);
860
+ return;
861
+ }
862
+ if (dataType.indexOf('@kline') >= 0) {
863
+ this.handleOHLCV(client, message);
864
+ return;
865
+ }
866
+ if (dataType.indexOf('executionReport') >= 0) {
867
+ const data = this.safeValue(message, 'data', {});
868
+ const type = this.safeString(data, 'x');
869
+ if (type === 'TRADE') {
870
+ this.handleMyTrades(client, message);
871
+ }
872
+ this.handleOrder(client, message);
873
+ return;
874
+ }
875
+ const e = this.safeString(message, 'e');
876
+ if (e === 'ACCOUNT_UPDATE') {
877
+ this.handleBalance(client, message);
878
+ }
879
+ if (e === 'ORDER_TRADE_UPDATE') {
880
+ this.handleOrder(client, message);
881
+ const data = this.safeValue(message, 'o', {});
882
+ const type = this.safeString(data, 'x');
883
+ const status = this.safeString(data, 'X');
884
+ if ((type === 'TRADE') && (status === 'FILLED')) {
885
+ this.handleMyTrades(client, message);
886
+ }
887
+ }
888
+ }
889
+ }
890
+
891
+ module.exports = bingx;