ccxt 4.5.5 → 4.5.7

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 (151) hide show
  1. package/README.md +4 -4
  2. package/dist/ccxt.browser.min.js +15 -15
  3. package/dist/cjs/ccxt.js +6 -6
  4. package/dist/cjs/src/abstract/toobit.js +11 -0
  5. package/dist/cjs/src/abstract/tradeogre.js +1 -1
  6. package/dist/cjs/src/apex.js +2 -2
  7. package/dist/cjs/src/backpack.js +1 -1
  8. package/dist/cjs/src/base/Exchange.js +129 -2
  9. package/dist/cjs/src/bigone.js +4 -4
  10. package/dist/cjs/src/binance.js +82 -20
  11. package/dist/cjs/src/bingx.js +5 -2
  12. package/dist/cjs/src/bitbank.js +1 -0
  13. package/dist/cjs/src/bitbns.js +1 -0
  14. package/dist/cjs/src/bitflyer.js +1 -0
  15. package/dist/cjs/src/bitget.js +16 -9
  16. package/dist/cjs/src/bithumb.js +1 -0
  17. package/dist/cjs/src/bitso.js +1 -0
  18. package/dist/cjs/src/bitvavo.js +26 -40
  19. package/dist/cjs/src/blockchaincom.js +1 -0
  20. package/dist/cjs/src/btcalpha.js +1 -0
  21. package/dist/cjs/src/btcbox.js +1 -0
  22. package/dist/cjs/src/btcmarkets.js +1 -0
  23. package/dist/cjs/src/btcturk.js +1 -0
  24. package/dist/cjs/src/bybit.js +186 -127
  25. package/dist/cjs/src/coinsph.js +4 -1
  26. package/dist/cjs/src/cryptocom.js +6 -3
  27. package/dist/cjs/src/deribit.js +3 -2
  28. package/dist/cjs/src/digifinex.js +1 -1
  29. package/dist/cjs/src/gate.js +9 -13
  30. package/dist/cjs/src/gemini.js +5 -5
  31. package/dist/cjs/src/htx.js +11 -1
  32. package/dist/cjs/src/hyperliquid.js +3 -0
  33. package/dist/cjs/src/independentreserve.js +1 -0
  34. package/dist/cjs/src/indodax.js +17 -6
  35. package/dist/cjs/src/kraken.js +31 -8
  36. package/dist/cjs/src/krakenfutures.js +1 -0
  37. package/dist/cjs/src/kucoin.js +1 -2
  38. package/dist/cjs/src/luno.js +4 -1
  39. package/dist/cjs/src/mercado.js +1 -0
  40. package/dist/cjs/src/mexc.js +84 -37
  41. package/dist/cjs/src/novadax.js +1 -0
  42. package/dist/cjs/src/oceanex.js +1 -0
  43. package/dist/cjs/src/okcoin.js +4 -1
  44. package/dist/cjs/src/okx.js +52 -8
  45. package/dist/cjs/src/phemex.js +1 -1
  46. package/dist/cjs/src/pro/apex.js +8 -4
  47. package/dist/cjs/src/pro/backpack.js +7 -5
  48. package/dist/cjs/src/pro/binance.js +150 -19
  49. package/dist/cjs/src/pro/bingx.js +206 -220
  50. package/dist/cjs/src/pro/bitget.js +332 -76
  51. package/dist/cjs/src/pro/cex.js +1 -0
  52. package/dist/cjs/src/pro/htx.js +1 -1
  53. package/dist/cjs/src/pro/independentreserve.js +1 -0
  54. package/dist/cjs/src/pro/mexc.js +23 -23
  55. package/dist/cjs/src/pro/okx.js +46 -10
  56. package/dist/cjs/src/pro/toobit.js +1163 -0
  57. package/dist/cjs/src/pro/tradeogre.js +1 -1
  58. package/dist/cjs/src/toobit.js +2999 -0
  59. package/dist/cjs/src/tradeogre.js +1 -1
  60. package/dist/cjs/src/upbit.js +1 -0
  61. package/dist/cjs/src/wavesexchange.js +1 -0
  62. package/dist/cjs/src/yobit.js +1 -0
  63. package/dist/cjs/src/zaif.js +1 -0
  64. package/dist/cjs/src/zonda.js +1 -0
  65. package/js/ccxt.d.ts +8 -8
  66. package/js/ccxt.js +6 -6
  67. package/js/src/abstract/mexc.d.ts +1 -0
  68. package/js/src/abstract/myokx.d.ts +1 -0
  69. package/js/src/abstract/okx.d.ts +1 -0
  70. package/js/src/abstract/okxus.d.ts +1 -0
  71. package/js/src/abstract/toobit.d.ts +66 -0
  72. package/js/src/apex.js +2 -2
  73. package/js/src/backpack.js +1 -1
  74. package/js/src/base/Exchange.d.ts +9 -0
  75. package/js/src/base/Exchange.js +129 -2
  76. package/js/src/bigone.js +4 -4
  77. package/js/src/binance.d.ts +9 -0
  78. package/js/src/binance.js +82 -20
  79. package/js/src/bingx.js +5 -2
  80. package/js/src/bitbank.js +1 -0
  81. package/js/src/bitbns.js +1 -0
  82. package/js/src/bitflyer.js +1 -0
  83. package/js/src/bitget.js +16 -9
  84. package/js/src/bithumb.js +1 -0
  85. package/js/src/bitso.js +1 -0
  86. package/js/src/bitvavo.d.ts +0 -2
  87. package/js/src/bitvavo.js +27 -41
  88. package/js/src/blockchaincom.js +1 -0
  89. package/js/src/btcalpha.js +1 -0
  90. package/js/src/btcbox.js +1 -0
  91. package/js/src/btcmarkets.js +1 -0
  92. package/js/src/btcturk.js +1 -0
  93. package/js/src/bybit.d.ts +8 -0
  94. package/js/src/bybit.js +186 -127
  95. package/js/src/coinsph.js +4 -1
  96. package/js/src/cryptocom.js +6 -3
  97. package/js/src/deribit.js +3 -2
  98. package/js/src/digifinex.js +1 -1
  99. package/js/src/gate.d.ts +2 -2
  100. package/js/src/gate.js +9 -13
  101. package/js/src/gemini.js +5 -5
  102. package/js/src/htx.js +11 -1
  103. package/js/src/hyperliquid.js +3 -0
  104. package/js/src/independentreserve.js +1 -0
  105. package/js/src/indodax.js +17 -6
  106. package/js/src/kraken.d.ts +2 -2
  107. package/js/src/kraken.js +31 -8
  108. package/js/src/krakenfutures.js +1 -0
  109. package/js/src/kucoin.js +1 -2
  110. package/js/src/luno.js +4 -1
  111. package/js/src/mercado.js +1 -0
  112. package/js/src/mexc.d.ts +4 -1
  113. package/js/src/mexc.js +84 -37
  114. package/js/src/novadax.js +1 -0
  115. package/js/src/oceanex.js +1 -0
  116. package/js/src/okcoin.js +4 -1
  117. package/js/src/okx.js +52 -8
  118. package/js/src/phemex.js +1 -1
  119. package/js/src/pro/apex.js +8 -4
  120. package/js/src/pro/backpack.d.ts +1 -1
  121. package/js/src/pro/backpack.js +7 -5
  122. package/js/src/pro/binance.d.ts +24 -0
  123. package/js/src/pro/binance.js +150 -19
  124. package/js/src/pro/bingx.d.ts +53 -33
  125. package/js/src/pro/bingx.js +207 -221
  126. package/js/src/pro/bitget.d.ts +6 -0
  127. package/js/src/pro/bitget.js +332 -76
  128. package/js/src/pro/cex.js +1 -0
  129. package/js/src/pro/htx.js +1 -1
  130. package/js/src/pro/independentreserve.js +1 -0
  131. package/js/src/pro/mexc.js +23 -23
  132. package/js/src/pro/okx.d.ts +7 -1
  133. package/js/src/pro/okx.js +46 -10
  134. package/js/src/pro/toobit.d.ts +174 -0
  135. package/js/src/pro/toobit.js +1162 -0
  136. package/js/src/toobit.d.ts +456 -0
  137. package/js/src/toobit.js +2992 -0
  138. package/js/src/upbit.js +1 -0
  139. package/js/src/wavesexchange.js +1 -0
  140. package/js/src/yobit.js +1 -0
  141. package/js/src/zaif.js +1 -0
  142. package/js/src/zonda.js +1 -0
  143. package/package.json +1 -1
  144. package/dist/373.ccxt.browser.js +0 -7630
  145. package/dist/373.ccxt.browser.min.js +0 -1
  146. package/js/src/abstract/tradeogre.d.ts +0 -21
  147. package/js/src/pro/tradeogre.d.ts +0 -49
  148. package/js/src/pro/tradeogre.js +0 -278
  149. package/js/src/tradeogre.d.ts +0 -149
  150. package/js/src/tradeogre.js +0 -872
  151. /package/js/src/abstract/{tradeogre.js → toobit.js} +0 -0
package/js/src/okx.js CHANGED
@@ -502,6 +502,7 @@ export default class okx extends Exchange {
502
502
  'account/fixed-loan/repay-borrowing-order': 5,
503
503
  'account/bills-history-archive': 72000,
504
504
  'account/move-positions': 10,
505
+ 'account/set-settle-currency': 1,
505
506
  // subaccount
506
507
  'users/subaccount/modify-apikey': 10,
507
508
  'asset/subaccount/transfer': 10,
@@ -684,6 +685,7 @@ export default class okx extends Exchange {
684
685
  '51031': InvalidOrder,
685
686
  '51046': InvalidOrder,
686
687
  '51047': InvalidOrder,
688
+ '51051': InvalidOrder,
687
689
  '51072': InvalidOrder,
688
690
  '51073': InvalidOrder,
689
691
  '51074': InvalidOrder,
@@ -823,6 +825,9 @@ export default class okx extends Exchange {
823
825
  '54008': InvalidOrder,
824
826
  '54009': InvalidOrder,
825
827
  '54011': InvalidOrder,
828
+ '54072': ExchangeError,
829
+ '54073': BadRequest,
830
+ '54074': ExchangeError,
826
831
  // Trading bot Error Code from 55100 to 55999
827
832
  '55100': InvalidOrder,
828
833
  '55101': InvalidOrder,
@@ -928,6 +933,9 @@ export default class okx extends Exchange {
928
933
  '59519': ExchangeError,
929
934
  '59642': BadRequest,
930
935
  '59643': ExchangeError,
936
+ '59683': ExchangeError,
937
+ '59684': BadRequest,
938
+ '59686': BadRequest,
931
939
  // WebSocket error Codes from 60000-63999
932
940
  '60001': AuthenticationError,
933
941
  '60002': AuthenticationError,
@@ -1294,6 +1302,9 @@ export default class okx extends Exchange {
1294
1302
  },
1295
1303
  'spot': {
1296
1304
  'extends': 'default',
1305
+ 'fetchCurrencies': {
1306
+ 'private': true,
1307
+ },
1297
1308
  },
1298
1309
  'swap': {
1299
1310
  'linear': {
@@ -1501,14 +1512,33 @@ export default class okx extends Exchange {
1501
1512
  // "data": [
1502
1513
  // {
1503
1514
  // "acctLv": "2",
1515
+ // "acctStpMode": "cancel_maker",
1504
1516
  // "autoLoan": false,
1505
1517
  // "ctIsoMode": "automatic",
1518
+ // "enableSpotBorrow": false,
1506
1519
  // "greeksType": "PA",
1520
+ // "feeType": "0",
1521
+ // "ip": "",
1522
+ // "type": "0",
1523
+ // "kycLv": "3",
1524
+ // "label": "v5 test",
1507
1525
  // "level": "Lv1",
1508
1526
  // "levelTmp": "",
1527
+ // "liquidationGear": "-1",
1528
+ // "mainUid": "44705892343619584",
1509
1529
  // "mgnIsoMode": "automatic",
1530
+ // "opAuth": "1",
1531
+ // "perm": "read_only,withdraw,trade",
1510
1532
  // "posMode": "long_short_mode",
1511
- // "uid": "88018754289672195"
1533
+ // "roleType": "0",
1534
+ // "spotBorrowAutoRepay": false,
1535
+ // "spotOffsetType": "",
1536
+ // "spotRoleType": "0",
1537
+ // "spotTraderInsts": [],
1538
+ // "traderInsts": [],
1539
+ // "uid": "44705892343619584",
1540
+ // "settleCcy": "USDT",
1541
+ // "settleCcyList": ["USD", "USDC", "USDG"],
1512
1542
  // }
1513
1543
  // ],
1514
1544
  // "msg": ""
@@ -1790,7 +1820,7 @@ export default class okx extends Exchange {
1790
1820
  // and fallback to generating the currencies from the markets
1791
1821
  const isSandboxMode = this.safeBool(this.options, 'sandboxMode', false);
1792
1822
  if (!this.checkRequiredCredentials(false) || isSandboxMode) {
1793
- return undefined;
1823
+ return {};
1794
1824
  }
1795
1825
  //
1796
1826
  // has['fetchCurrencies'] is currently set to true, but an unauthorized request returns
@@ -3154,7 +3184,8 @@ export default class okx extends Exchange {
3154
3184
  request['attachAlgoOrds'] = [attachAlgoOrd];
3155
3185
  }
3156
3186
  }
3157
- else if (trigger) {
3187
+ // algo order details
3188
+ if (trigger) {
3158
3189
  request['ordType'] = 'trigger';
3159
3190
  request['triggerPx'] = this.priceToPrecision(symbol, triggerPrice);
3160
3191
  request['orderPx'] = isMarketOrder ? '-1' : this.priceToPrecision(symbol, price);
@@ -3605,10 +3636,18 @@ export default class okx extends Exchange {
3605
3636
  }
3606
3637
  else {
3607
3638
  for (let i = 0; i < clientOrderIds.length; i++) {
3608
- request.push({
3609
- 'instId': market['id'],
3610
- 'clOrdId': clientOrderIds[i],
3611
- });
3639
+ if (trailing || trigger) {
3640
+ request.push({
3641
+ 'instId': market['id'],
3642
+ 'algoClOrdId': clientOrderIds[i],
3643
+ });
3644
+ }
3645
+ else {
3646
+ request.push({
3647
+ 'instId': market['id'],
3648
+ 'clOrdId': clientOrderIds[i],
3649
+ });
3650
+ }
3612
3651
  }
3613
3652
  }
3614
3653
  let response = undefined;
@@ -3685,7 +3724,12 @@ export default class okx extends Exchange {
3685
3724
  idKey = 'algoId';
3686
3725
  }
3687
3726
  else if (clientOrderId !== undefined) {
3688
- idKey = 'clOrdId';
3727
+ if (isStopOrTrailing) {
3728
+ idKey = 'algoClOrdId';
3729
+ }
3730
+ else {
3731
+ idKey = 'clOrdId';
3732
+ }
3689
3733
  }
3690
3734
  const requestItem = {
3691
3735
  'instId': market['id'],
package/js/src/phemex.js CHANGED
@@ -4067,7 +4067,7 @@ export default class phemex extends Exchange {
4067
4067
  const isCross = this.safeValue(position, 'crossMargin');
4068
4068
  return this.safePosition({
4069
4069
  'info': position,
4070
- 'id': undefined,
4070
+ 'id': this.safeString(position, 'execSeq'),
4071
4071
  'symbol': symbol,
4072
4072
  'contracts': this.parseNumber(contracts),
4073
4073
  'contractSize': contractSize,
@@ -112,9 +112,10 @@ export default class apex extends apexRest {
112
112
  // "v": "0.001",
113
113
  // "p": "16578.50",
114
114
  // "L": "PlusTick",
115
- // "i": "20f43950-d8dd-5b31-9112-a178eb6023af",
115
+ // "i": "20f43950-d8dd-5b31-9112-a178eb6023ef",
116
116
  // "BT": false
117
- // }
117
+ // },
118
+ // // sorted by newest first
118
119
  // ]
119
120
  // }
120
121
  //
@@ -131,8 +132,10 @@ export default class apex extends apexRest {
131
132
  stored = new ArrayCache(limit);
132
133
  this.trades[symbol] = stored;
133
134
  }
134
- for (let j = 0; j < trades.length; j++) {
135
- const parsed = this.parseWsTrade(trades[j], market);
135
+ const length = trades.length;
136
+ for (let j = 0; j < length; j++) {
137
+ const index = length - j - 1;
138
+ const parsed = this.parseWsTrade(trades[index], market);
136
139
  stored.append(parsed);
137
140
  }
138
141
  const messageHash = 'trade' + ':' + symbol;
@@ -959,6 +962,7 @@ export default class apex extends apexRest {
959
962
  }
960
963
  ping(client) {
961
964
  const timeStamp = this.milliseconds().toString();
965
+ client.lastPong = timeStamp; // server won't send a pong, so we set it here
962
966
  return {
963
967
  'args': [timeStamp],
964
968
  'op': 'ping',
@@ -197,7 +197,7 @@ export default class backpack extends backpackRest {
197
197
  unWatchOrderBook(symbol: string, params?: {}): Promise<any>;
198
198
  /**
199
199
  * @method
200
- * @name kucoin#unWatchOrderBookForSymbols
200
+ * @name backpack#unWatchOrderBookForSymbols
201
201
  * @description unWatches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
202
202
  * @param {string[]} symbols unified array of symbols
203
203
  * @param {object} [params] extra parameters specific to the exchange API endpoint
@@ -797,7 +797,7 @@ export default class backpack extends backpackRest {
797
797
  }
798
798
  /**
799
799
  * @method
800
- * @name kucoin#unWatchOrderBookForSymbols
800
+ * @name backpack#unWatchOrderBookForSymbols
801
801
  * @description unWatches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
802
802
  * @param {string[]} symbols unified array of symbols
803
803
  * @param {object} [params] extra parameters specific to the exchange API endpoint
@@ -859,7 +859,7 @@ export default class backpack extends backpackRest {
859
859
  storedOrderBook.cache.push(data);
860
860
  return;
861
861
  }
862
- else if (nonce >= deltaNonce) {
862
+ else if (nonce > deltaNonce) {
863
863
  return;
864
864
  }
865
865
  this.handleDelta(storedOrderBook, data);
@@ -884,16 +884,18 @@ export default class backpack extends backpackRest {
884
884
  }
885
885
  }
886
886
  getCacheIndex(orderbook, cache) {
887
+ //
888
+ // {"E":"1759338824897386","T":"1759338824895616","U":1662976171,"a":[],"b":[["117357.0","0.00000"]],"e":"depth","s":"BTC_USDC_PERP","u":1662976171}
887
889
  const firstDelta = this.safeDict(cache, 0);
888
890
  const nonce = this.safeInteger(orderbook, 'nonce');
889
- const firstDeltaStart = this.safeInteger(firstDelta, 'sequenceStart');
891
+ const firstDeltaStart = this.safeInteger(firstDelta, 'U');
890
892
  if (nonce < firstDeltaStart - 1) {
891
893
  return -1;
892
894
  }
893
895
  for (let i = 0; i < cache.length; i++) {
894
896
  const delta = cache[i];
895
- const deltaStart = this.safeInteger(delta, 'sequenceStart');
896
- const deltaEnd = this.safeInteger(delta, 'sequenceEnd');
897
+ const deltaStart = this.safeInteger(delta, 'U');
898
+ const deltaEnd = this.safeInteger(delta, 'u');
897
899
  if ((nonce >= deltaStart - 1) && (nonce < deltaEnd)) {
898
900
  return i;
899
901
  }
@@ -62,6 +62,19 @@ export default class binance extends binanceRest {
62
62
  };
63
63
  };
64
64
  };
65
+ demo: {
66
+ ws: {
67
+ spot: string;
68
+ margin: string;
69
+ future: string;
70
+ delivery: string;
71
+ 'ws-api': {
72
+ spot: string;
73
+ future: string;
74
+ delivery: string;
75
+ };
76
+ };
77
+ };
65
78
  api: {
66
79
  ws: {
67
80
  spot: string;
@@ -149,6 +162,7 @@ export default class binance extends binanceRest {
149
162
  };
150
163
  };
151
164
  requestId(url: any): any;
165
+ isSpotUrl(client: Client): boolean;
152
166
  stream(type: Str, subscriptionHash: Str, numSubscriptions?: number): string;
153
167
  /**
154
168
  * @method
@@ -541,6 +555,14 @@ export default class binance extends binanceRest {
541
555
  handleTickersAndBidsAsks(client: Client, message: any, methodType: any): void;
542
556
  getMessageHash(channelName: string, symbol: Str, isBidAsk: boolean): string;
543
557
  signParams(params?: {}): any;
558
+ /**
559
+ * Ensures a User Data Stream WebSocket subscription is active for the specified scope
560
+ * @param marketType {string} only support on 'spot'
561
+ * @see {@link https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/user-data-stream-requests#subscribe-to-user-data-stream-through-signature-subscription-user_data Binance User Data Stream Documentation}
562
+ * @returns Promise<number> The subscription ID for the user data stream
563
+ */
564
+ ensureUserDataStreamWsSubscribeSignature(marketType?: string): Promise<void>;
565
+ handleUserDataStreamSubscribe(client: Client, message: any): void;
544
566
  authenticate(params?: {}): Promise<void>;
545
567
  keepAliveListenKey(params?: {}): Promise<void>;
546
568
  setBalanceCache(client: Client, type: any, isPortfolioMargin?: boolean): void;
@@ -596,6 +618,7 @@ export default class binance extends binanceRest {
596
618
  */
597
619
  watchBalance(params?: {}): Promise<Balances>;
598
620
  handleBalance(client: Client, message: any): void;
621
+ getAccountTypeFromSubscriptions(subscriptions: string[]): string;
599
622
  getMarketType(method: any, market: any, params?: {}): any;
600
623
  /**
601
624
  * @method
@@ -792,5 +815,6 @@ export default class binance extends binanceRest {
792
815
  handleOrder(client: Client, message: any): void;
793
816
  handleAcountUpdate(client: any, message: any): void;
794
817
  handleWsError(client: Client, message: any): void;
818
+ handleEventStreamTerminated(client: Client, message: any): void;
795
819
  handleMessage(client: Client, message: any): void;
796
820
  }
@@ -73,6 +73,19 @@ export default class binance extends binanceRest {
73
73
  },
74
74
  },
75
75
  },
76
+ 'demo': {
77
+ 'ws': {
78
+ 'spot': 'wss://demo-stream.binance.com/ws',
79
+ 'margin': 'wss://demo-stream.binance.com/ws',
80
+ 'future': 'wss://fstream.binancefuture.com/ws',
81
+ 'delivery': 'wss://dstream.binancefuture.com/ws',
82
+ 'ws-api': {
83
+ 'spot': 'wss://demo-ws-api.binance.com/ws-api/v3',
84
+ 'future': 'wss://testnet.binancefuture.com/ws-fapi/v1',
85
+ 'delivery': 'wss://testnet.binancefuture.com/ws-dapi/v1',
86
+ },
87
+ },
88
+ },
76
89
  'api': {
77
90
  'ws': {
78
91
  'spot': 'wss://stream.binance.com:9443/ws',
@@ -170,6 +183,9 @@ export default class binance extends binanceRest {
170
183
  this.options['requestId'][url] = newValue;
171
184
  return newValue;
172
185
  }
186
+ isSpotUrl(client) {
187
+ return (client.url.indexOf('/stream') > -1) || (client.url.indexOf('demo-stream') > -1);
188
+ }
173
189
  stream(type, subscriptionHash, numSubscriptions = 1) {
174
190
  const streamBySubscriptionsHash = this.safeDict(this.options, 'streamBySubscriptionsHash', this.createSafeDictionary());
175
191
  let stream = this.safeString(streamBySubscriptionsHash, subscriptionHash);
@@ -899,7 +915,7 @@ export default class binance extends binanceRest {
899
915
  // ]
900
916
  // }
901
917
  //
902
- const isSpot = (client.url.indexOf('/stream') > -1);
918
+ const isSpot = this.isSpotUrl(client);
903
919
  const marketType = (isSpot) ? 'spot' : 'contract';
904
920
  const marketId = this.safeString(message, 's');
905
921
  const market = this.safeMarket(marketId, undefined, undefined, marketType);
@@ -1359,7 +1375,7 @@ export default class binance extends binanceRest {
1359
1375
  handleTrade(client, message) {
1360
1376
  // the trade streams push raw trade information in real-time
1361
1377
  // each trade has a unique buyer and seller
1362
- const isSpot = (client.url.indexOf('/stream') > -1);
1378
+ const isSpot = this.isSpotUrl(client);
1363
1379
  const marketType = (isSpot) ? 'spot' : 'contract';
1364
1380
  const marketId = this.safeString(message, 's');
1365
1381
  const market = this.safeMarket(marketId, undefined, undefined, marketType);
@@ -1601,7 +1617,7 @@ export default class binance extends binanceRest {
1601
1617
  this.safeFloat(kline, 'c'),
1602
1618
  this.safeFloat(kline, 'v'),
1603
1619
  ];
1604
- const isSpot = (client.url.indexOf('/stream') > -1);
1620
+ const isSpot = this.isSpotUrl(client);
1605
1621
  const marketType = (isSpot) ? 'spot' : 'contract';
1606
1622
  const symbol = this.safeSymbol(marketId, undefined, undefined, marketType);
1607
1623
  const messageHash = 'ohlcv::' + symbol + '::' + unifiedTimeframe;
@@ -2246,7 +2262,7 @@ export default class binance extends binanceRest {
2246
2262
  this.handleTickersAndBidsAsks(client, message, 'tickers');
2247
2263
  }
2248
2264
  handleTickersAndBidsAsks(client, message, methodType) {
2249
- const isSpot = (client.url.indexOf('/stream') > -1);
2265
+ const isSpot = this.isSpotUrl(client);
2250
2266
  const marketType = (isSpot) ? 'spot' : 'contract';
2251
2267
  const isBidAsk = (methodType === 'bidasks');
2252
2268
  let channelName = undefined;
@@ -2329,6 +2345,58 @@ export default class binance extends binanceRest {
2329
2345
  extendedParams['signature'] = signature;
2330
2346
  return extendedParams;
2331
2347
  }
2348
+ /**
2349
+ * Ensures a User Data Stream WebSocket subscription is active for the specified scope
2350
+ * @param marketType {string} only support on 'spot'
2351
+ * @see {@link https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/user-data-stream-requests#subscribe-to-user-data-stream-through-signature-subscription-user_data Binance User Data Stream Documentation}
2352
+ * @returns Promise<number> The subscription ID for the user data stream
2353
+ */
2354
+ async ensureUserDataStreamWsSubscribeSignature(marketType = 'spot') {
2355
+ const url = this.urls['api']['ws']['ws-api'][marketType];
2356
+ const client = this.client(url);
2357
+ const subscriptions = client.subscriptions;
2358
+ const subscriptionsKeys = Object.keys(subscriptions);
2359
+ const accountType = this.getAccountTypeFromSubscriptions(subscriptionsKeys);
2360
+ if (accountType === marketType) {
2361
+ return;
2362
+ }
2363
+ client.subscriptions[marketType] = true;
2364
+ const requestId = this.requestId(url);
2365
+ const messageHash = requestId.toString();
2366
+ const message = {
2367
+ 'id': messageHash,
2368
+ 'method': 'userDataStream.subscribe.signature',
2369
+ 'params': this.signParams({}),
2370
+ };
2371
+ const subscription = {
2372
+ 'id': messageHash,
2373
+ 'method': this.handleUserDataStreamSubscribe,
2374
+ 'subscription': marketType,
2375
+ };
2376
+ await this.watch(url, messageHash, message, messageHash, subscription);
2377
+ }
2378
+ handleUserDataStreamSubscribe(client, message) {
2379
+ //
2380
+ // {
2381
+ // "id": 1,
2382
+ // "status": 200,
2383
+ // "result": {
2384
+ // "subscriptionId": 0
2385
+ // }
2386
+ // }
2387
+ //
2388
+ const messageHash = this.safeString(message, 'id');
2389
+ const subscriptions = client.subscriptions;
2390
+ const subscriptionsKeys = Object.keys(subscriptions);
2391
+ const accountType = this.getAccountTypeFromSubscriptions(subscriptionsKeys);
2392
+ const result = this.safeDict(message, 'result', {});
2393
+ const subscriptionId = this.safeInteger(result, 'subscriptionId');
2394
+ if (subscriptionId === undefined) {
2395
+ delete client.subscriptions[accountType];
2396
+ client.reject(message, accountType);
2397
+ }
2398
+ client.resolve(message, messageHash);
2399
+ }
2332
2400
  async authenticate(params = {}) {
2333
2401
  const time = this.milliseconds();
2334
2402
  let type = undefined;
@@ -2343,6 +2411,11 @@ export default class binance extends binanceRest {
2343
2411
  else if (this.isInverse(type, subType)) {
2344
2412
  type = 'delivery';
2345
2413
  }
2414
+ // For spot use WebSocket API signature subscription
2415
+ if (type === 'spot') {
2416
+ await this.ensureUserDataStreamWsSubscribeSignature('spot');
2417
+ return;
2418
+ }
2346
2419
  let marginMode = undefined;
2347
2420
  [marginMode, params] = this.handleMarginModeAndParams('authenticate', params);
2348
2421
  const isIsolatedMargin = (marginMode === 'isolated');
@@ -2470,7 +2543,7 @@ export default class binance extends binanceRest {
2470
2543
  }
2471
2544
  }
2472
2545
  setBalanceCache(client, type, isPortfolioMargin = false) {
2473
- if (type in client.subscriptions) {
2546
+ if ((type in client.subscriptions) && (type in this.balance)) {
2474
2547
  return;
2475
2548
  }
2476
2549
  const options = this.safeValue(this.options, 'watchBalance');
@@ -2734,11 +2807,18 @@ export default class binance extends binanceRest {
2734
2807
  else if (this.isInverse(type, subType)) {
2735
2808
  type = 'delivery';
2736
2809
  }
2810
+ let url = '';
2737
2811
  let urlType = type;
2738
- if (isPortfolioMargin) {
2739
- urlType = 'papi';
2812
+ if (type === 'spot') {
2813
+ // route to WebSocket API connection where the user data stream is subscribed
2814
+ url = this.urls['api']['ws']['ws-api'][type];
2815
+ }
2816
+ else {
2817
+ if (isPortfolioMargin) {
2818
+ urlType = 'papi';
2819
+ }
2820
+ url = this.urls['api']['ws'][urlType] + '/' + this.options[type]['listenKey'];
2740
2821
  }
2741
- const url = this.urls['api']['ws'][urlType] + '/' + this.options[type]['listenKey'];
2742
2822
  const client = this.client(url);
2743
2823
  this.setBalanceCache(client, type, isPortfolioMargin);
2744
2824
  this.setPositionsCache(client, type, undefined, isPortfolioMargin);
@@ -2820,9 +2900,9 @@ export default class binance extends binanceRest {
2820
2900
  //
2821
2901
  const wallet = this.safeString(this.options, 'wallet', 'wb'); // cw for cross wallet
2822
2902
  // each account is connected to a different endpoint
2823
- // and has exactly one subscriptionhash which is the account type
2824
- const subscriptions = Object.keys(client.subscriptions);
2825
- const accountType = subscriptions[0];
2903
+ const subscriptions = client.subscriptions;
2904
+ const subscriptionsKeys = Object.keys(subscriptions);
2905
+ const accountType = this.getAccountTypeFromSubscriptions(subscriptionsKeys);
2826
2906
  const messageHash = accountType + ':balance';
2827
2907
  if (this.balance[accountType] === undefined) {
2828
2908
  this.balance[accountType] = {};
@@ -2866,6 +2946,17 @@ export default class binance extends binanceRest {
2866
2946
  this.balance[accountType] = this.safeBalance(this.balance[accountType]);
2867
2947
  client.resolve(this.balance[accountType], messageHash);
2868
2948
  }
2949
+ getAccountTypeFromSubscriptions(subscriptions) {
2950
+ let accountType = '';
2951
+ for (let i = 0; i < subscriptions.length; i++) {
2952
+ const subscription = subscriptions[i];
2953
+ if ((subscription === 'spot') || (subscription === 'margin') || (subscription === 'future') || (subscription === 'delivery')) {
2954
+ accountType = subscription;
2955
+ break;
2956
+ }
2957
+ }
2958
+ return accountType;
2959
+ }
2869
2960
  getMarketType(method, market, params = {}) {
2870
2961
  let type = undefined;
2871
2962
  [type, params] = this.handleMarketTypeAndParams(method, market, params);
@@ -3467,10 +3558,17 @@ export default class binance extends binanceRest {
3467
3558
  }
3468
3559
  let isPortfolioMargin = undefined;
3469
3560
  [isPortfolioMargin, params] = this.handleOptionAndParams2(params, 'watchOrders', 'papi', 'portfolioMargin', false);
3470
- if (isPortfolioMargin) {
3471
- urlType = 'papi';
3561
+ let url = '';
3562
+ if (type === 'spot') {
3563
+ // route orders to ws-api user data stream
3564
+ url = this.urls['api']['ws']['ws-api'][type];
3565
+ }
3566
+ else {
3567
+ if (isPortfolioMargin) {
3568
+ urlType = 'papi';
3569
+ }
3570
+ url = this.urls['api']['ws'][urlType] + '/' + this.options[type]['listenKey'];
3472
3571
  }
3473
- const url = this.urls['api']['ws'][urlType] + '/' + this.options[type]['listenKey'];
3474
3572
  const client = this.client(url);
3475
3573
  this.setBalanceCache(client, type, isPortfolioMargin);
3476
3574
  this.setPositionsCache(client, type, undefined, isPortfolioMargin);
@@ -3857,8 +3955,9 @@ export default class binance extends binanceRest {
3857
3955
  //
3858
3956
  // each account is connected to a different endpoint
3859
3957
  // and has exactly one subscriptionhash which is the account type
3860
- const subscriptions = Object.keys(client.subscriptions);
3861
- const accountType = subscriptions[0];
3958
+ const subscriptions = client.subscriptions;
3959
+ const subscriptionsKeys = Object.keys(subscriptions);
3960
+ const accountType = this.getAccountTypeFromSubscriptions(subscriptionsKeys);
3862
3961
  if (this.positions === undefined) {
3863
3962
  this.positions = {};
3864
3963
  }
@@ -4135,10 +4234,16 @@ export default class binance extends binanceRest {
4135
4234
  }
4136
4235
  let isPortfolioMargin = undefined;
4137
4236
  [isPortfolioMargin, params] = this.handleOptionAndParams2(params, 'watchMyTrades', 'papi', 'portfolioMargin', false);
4138
- if (isPortfolioMargin) {
4139
- urlType = 'papi';
4237
+ let url = '';
4238
+ if (type === 'spot') {
4239
+ url = this.urls['api']['ws']['ws-api'][type];
4240
+ }
4241
+ else {
4242
+ if (isPortfolioMargin) {
4243
+ urlType = 'papi';
4244
+ }
4245
+ url = this.urls['api']['ws'][urlType] + '/' + this.options[type]['listenKey'];
4140
4246
  }
4141
- const url = this.urls['api']['ws'][urlType] + '/' + this.options[type]['listenKey'];
4142
4247
  const client = this.client(url);
4143
4248
  this.setBalanceCache(client, type, isPortfolioMargin);
4144
4249
  this.setPositionsCache(client, type, undefined, isPortfolioMargin);
@@ -4284,8 +4389,12 @@ export default class binance extends binanceRest {
4284
4389
  for (let i = 0; i < subscriptionKeys.length; i++) {
4285
4390
  const subscriptionHash = subscriptionKeys[i];
4286
4391
  const subscriptionId = this.safeString(client.subscriptions[subscriptionHash], 'id');
4392
+ const subscription = this.safeString(client.subscriptions[subscriptionHash], 'subscription');
4287
4393
  if (id === subscriptionId) {
4288
4394
  client.reject(e, subscriptionHash);
4395
+ if (subscription !== undefined) {
4396
+ delete client.subscriptions[subscription];
4397
+ }
4289
4398
  }
4290
4399
  }
4291
4400
  }
@@ -4298,14 +4407,35 @@ export default class binance extends binanceRest {
4298
4407
  client.reset(message);
4299
4408
  }
4300
4409
  }
4410
+ handleEventStreamTerminated(client, message) {
4411
+ //
4412
+ // {
4413
+ // e: 'eventStreamTerminated',
4414
+ // E: 1757896885229
4415
+ // }
4416
+ //
4417
+ const event = this.safeString(message, 'e');
4418
+ const subscriptions = client.subscriptions;
4419
+ const subscriptionsKeys = Object.keys(subscriptions);
4420
+ const accountType = this.getAccountTypeFromSubscriptions(subscriptionsKeys);
4421
+ if (event === 'eventStreamTerminated') {
4422
+ delete client.subscriptions[accountType];
4423
+ client.reject(message, accountType);
4424
+ }
4425
+ }
4301
4426
  handleMessage(client, message) {
4302
4427
  // handle WebSocketAPI
4428
+ const eventMsg = this.safeDict(message, 'event');
4429
+ if (eventMsg !== undefined) {
4430
+ message = eventMsg;
4431
+ }
4303
4432
  const status = this.safeString(message, 'status');
4304
4433
  const error = this.safeValue(message, 'error');
4305
4434
  if ((error !== undefined) || (status !== undefined && status !== '200')) {
4306
4435
  this.handleWsError(client, message);
4307
4436
  return;
4308
4437
  }
4438
+ // user subscription wraps message in subscriptionId and event
4309
4439
  const id = this.safeString(message, 'id');
4310
4440
  const subscriptions = this.safeValue(client.subscriptions, id);
4311
4441
  let method = this.safeValue(subscriptions, 'method');
@@ -4340,6 +4470,7 @@ export default class binance extends binanceRest {
4340
4470
  'executionReport': this.handleOrderUpdate,
4341
4471
  'ORDER_TRADE_UPDATE': this.handleOrderUpdate,
4342
4472
  'forceOrder': this.handleLiquidation,
4473
+ 'eventStreamTerminated': this.handleEventStreamTerminated,
4343
4474
  'externalLockUpdate': this.handleBalance,
4344
4475
  };
4345
4476
  let event = this.safeString(message, 'e');