ccxt 4.5.48 → 4.5.50

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 (60) hide show
  1. package/README.md +7 -5
  2. package/dist/ccxt.browser.min.js +10 -10
  3. package/dist/cjs/ccxt.js +6 -1
  4. package/dist/cjs/src/abstract/weex.js +11 -0
  5. package/dist/cjs/src/base/Exchange.js +48 -13
  6. package/dist/cjs/src/bitget.js +1 -0
  7. package/dist/cjs/src/btcbox.js +1 -1
  8. package/dist/cjs/src/bullish.js +2 -1
  9. package/dist/cjs/src/gate.js +0 -1
  10. package/dist/cjs/src/hibachi.js +1 -1
  11. package/dist/cjs/src/kraken.js +1 -0
  12. package/dist/cjs/src/krakenfutures.js +10 -1
  13. package/dist/cjs/src/kucoin.js +5 -1
  14. package/dist/cjs/src/lighter.js +312 -144
  15. package/dist/cjs/src/mexc.js +7 -12
  16. package/dist/cjs/src/okx.js +46 -1
  17. package/dist/cjs/src/paradex.js +5 -2
  18. package/dist/cjs/src/pro/binance.js +1 -1
  19. package/dist/cjs/src/pro/cex.js +1 -1
  20. package/dist/cjs/src/pro/coinbase.js +1 -1
  21. package/dist/cjs/src/pro/hyperliquid.js +361 -1
  22. package/dist/cjs/src/pro/lighter.js +339 -18
  23. package/dist/cjs/src/pro/weex.js +1906 -0
  24. package/dist/cjs/src/weex.js +3823 -0
  25. package/js/ccxt.d.ts +8 -2
  26. package/js/ccxt.js +6 -2
  27. package/js/src/abstract/myokx.d.ts +34 -0
  28. package/js/src/abstract/okx.d.ts +34 -0
  29. package/js/src/abstract/okxus.d.ts +34 -0
  30. package/js/src/abstract/weex.d.ts +83 -0
  31. package/js/src/abstract/weex.js +11 -0
  32. package/js/src/base/Exchange.d.ts +5 -1
  33. package/js/src/base/Exchange.js +48 -13
  34. package/js/src/bitget.js +1 -0
  35. package/js/src/btcbox.js +1 -1
  36. package/js/src/bullish.js +2 -1
  37. package/js/src/gate.js +0 -1
  38. package/js/src/hibachi.js +1 -1
  39. package/js/src/kraken.js +1 -0
  40. package/js/src/krakenfutures.js +10 -1
  41. package/js/src/kucoin.d.ts +4 -0
  42. package/js/src/kucoin.js +5 -1
  43. package/js/src/lighter.d.ts +12 -2
  44. package/js/src/lighter.js +313 -145
  45. package/js/src/mexc.d.ts +2 -0
  46. package/js/src/mexc.js +7 -12
  47. package/js/src/okx.js +46 -1
  48. package/js/src/paradex.js +5 -2
  49. package/js/src/pro/binance.js +1 -1
  50. package/js/src/pro/cex.js +1 -1
  51. package/js/src/pro/coinbase.js +1 -1
  52. package/js/src/pro/hyperliquid.d.ts +48 -1
  53. package/js/src/pro/hyperliquid.js +362 -2
  54. package/js/src/pro/lighter.d.ts +37 -2
  55. package/js/src/pro/lighter.js +339 -18
  56. package/js/src/pro/weex.d.ts +330 -0
  57. package/js/src/pro/weex.js +1905 -0
  58. package/js/src/weex.d.ts +675 -0
  59. package/js/src/weex.js +3822 -0
  60. package/package.json +1 -1
@@ -479,11 +479,6 @@ class mexc extends mexc$1["default"] {
479
479
  'options': {
480
480
  'adjustForTimeDifference': false,
481
481
  'timeDifference': 0,
482
- 'unavailableContracts': {
483
- 'BTC/USDT:USDT': true,
484
- 'LTC/USDT:USDT': true,
485
- 'ETH/USDT:USDT': true,
486
- },
487
482
  'fetchMarkets': {
488
483
  'types': {
489
484
  'spot': true,
@@ -2305,6 +2300,7 @@ class mexc extends mexc$1["default"] {
2305
2300
  * @name mexc#createOrder
2306
2301
  * @description create a trade order
2307
2302
  * @see https://mexcdevelop.github.io/apidocs/spot_v3_en/#new-order
2303
+ * @see https://www.mexc.com/api-docs/futures/account-and-trading-endpoints#place-order
2308
2304
  * @see https://mexcdevelop.github.io/apidocs/contract_v1_en/#order-under-maintenance
2309
2305
  * @see https://mexcdevelop.github.io/apidocs/contract_v1_en/#trigger-order-under-maintenance
2310
2306
  * @param {string} symbol unified symbol of the market to create an order in
@@ -2462,6 +2458,7 @@ class mexc extends mexc$1["default"] {
2462
2458
  * @method
2463
2459
  * @name mexc#createSwapOrder
2464
2460
  * @description create a trade order
2461
+ * @see https://www.mexc.com/api-docs/futures/account-and-trading-endpoints#place-order
2465
2462
  * @see https://mexcdevelop.github.io/apidocs/spot_v3_en/#new-order
2466
2463
  * @see https://mexcdevelop.github.io/apidocs/contract_v1_en/#order-under-maintenance
2467
2464
  * @see https://mexcdevelop.github.io/apidocs/contract_v1_en/#trigger-order-under-maintenance
@@ -2487,11 +2484,6 @@ class mexc extends mexc$1["default"] {
2487
2484
  async createSwapOrder(market, type, side, amount, price = undefined, marginMode = undefined, params = {}) {
2488
2485
  await this.loadMarkets();
2489
2486
  const symbol = market['symbol'];
2490
- const unavailableContracts = this.safeValue(this.options, 'unavailableContracts', {});
2491
- const isContractUnavaiable = this.safeBool(unavailableContracts, symbol, false);
2492
- if (isContractUnavaiable) {
2493
- throw new errors.NotSupported(this.id + ' createSwapOrder() does not support yet this symbol:' + symbol);
2494
- }
2495
2487
  let openType = undefined;
2496
2488
  if (marginMode !== undefined) {
2497
2489
  if (marginMode === 'cross') {
@@ -2562,14 +2554,17 @@ class mexc extends mexc$1["default"] {
2562
2554
  if (hedged) {
2563
2555
  if (reduceOnly) {
2564
2556
  params = this.omit(params, 'reduceOnly'); // hedged mode does not accept this parameter
2565
- side = (side === 'buy') ? 'sell' : 'buy';
2557
+ sideInteger = (side === 'buy') ? 4 : 2; // close short, close long
2558
+ }
2559
+ else {
2560
+ sideInteger = (side === 'buy') ? 1 : 3;
2566
2561
  }
2567
- sideInteger = (side === 'buy') ? 1 : 3;
2568
2562
  request['positionMode'] = 1;
2569
2563
  }
2570
2564
  else {
2571
2565
  if (reduceOnly) {
2572
2566
  sideInteger = (side === 'buy') ? 2 : 4;
2567
+ params = this.omit(params, 'reduceOnly');
2573
2568
  }
2574
2569
  else {
2575
2570
  sideInteger = (side === 'buy') ? 1 : 3;
@@ -206,6 +206,7 @@ class okx extends okx$1["default"] {
206
206
  'market/option/instrument-family-trades': 1,
207
207
  'market/platform-24-volume': 10,
208
208
  'market/call-auction-detail': 1,
209
+ 'market/call-auction-details': 1,
209
210
  'market/books-sbe': 10,
210
211
  'market/block-tickers': 1,
211
212
  'market/block-ticker': 1,
@@ -246,6 +247,9 @@ class okx extends okx$1["default"] {
246
247
  'public/premium-history': 1,
247
248
  'public/economic-calendar': 50,
248
249
  'public/market-data-history': 4,
250
+ 'public/event-contract/events': 1,
251
+ 'public/event-contract/markets': 1,
252
+ 'public/event-contract/series': 1,
249
253
  'public/vip-interest-rate-loan-quota': 10,
250
254
  // rubik
251
255
  'rubik/stat/trading-data/support-coin': 4,
@@ -254,6 +258,7 @@ class okx extends okx$1["default"] {
254
258
  'rubik/stat/taker-volume-contract': 4,
255
259
  'rubik/stat/margin/loan-ratio': 4,
256
260
  'rubik/stat/contracts/long-short-account-ratio-contract-top-trader': 4,
261
+ 'rubik/stat/contracts/long-short-position-ratio-contract-top-trader': 4,
257
262
  'rubik/stat/contracts/long-short-account-ratio-contract': 4,
258
263
  'rubik/stat/contracts/long-short-account-ratio': 4,
259
264
  'rubik/stat/contracts/open-interest-volume': 4,
@@ -295,6 +300,7 @@ class okx extends okx$1["default"] {
295
300
  'copytrading/public-copy-traders': 4,
296
301
  'support/announcements': 4,
297
302
  'support/announcements-types': 20,
303
+ 'support/announcement-types': 20,
298
304
  },
299
305
  'post': {
300
306
  'tradingBot/grid/min-investment': 1, // public
@@ -361,6 +367,7 @@ class okx extends okx$1["default"] {
361
367
  'account/bills-archive': 4,
362
368
  'account/bills-history-archive': 2,
363
369
  'account/config': 4,
370
+ 'account/subtypes': 4,
364
371
  'account/max-size': 1,
365
372
  'account/max-avail-size': 1,
366
373
  'account/leverage-info': 1,
@@ -420,6 +427,11 @@ class okx extends okx$1["default"] {
420
427
  'tradingBot/recurring/orders-algo-history': 1,
421
428
  'tradingBot/recurring/orders-algo-details': 1,
422
429
  'tradingBot/recurring/sub-orders': 1,
430
+ 'tradingBot/dca/ongoing-list': 1,
431
+ 'tradingBot/dca/history-list': 1,
432
+ 'tradingBot/dca/orders': 1,
433
+ 'tradingBot/dca/position-details': 1,
434
+ 'tradingBot/dca/cycle-list': 1,
423
435
  // earn
424
436
  'finance/savings/balance': 5 / 3,
425
437
  'finance/savings/lending-history': 5 / 3,
@@ -469,6 +481,9 @@ class okx extends okx$1["default"] {
469
481
  'broker/nd/rebate-per-orders': 300,
470
482
  'finance/sfp/dcd/order': 2,
471
483
  'finance/sfp/dcd/orders': 2,
484
+ 'finance/sfp/dcd/currency-pair': 2,
485
+ 'finance/sfp/dcd/order-status': 2,
486
+ 'finance/sfp/dcd/order-history': 2,
472
487
  // affiliate
473
488
  'affiliate/invitee/detail': 1,
474
489
  'users/partner/if-rebate': 1,
@@ -539,6 +554,7 @@ class okx extends okx$1["default"] {
539
554
  'account/position-builder': 10,
540
555
  'account/position-builder-graph': 50,
541
556
  'account/set-riskOffset-type': 2,
557
+ 'account/set-riskOffset-amt': 2,
542
558
  'account/activate-option': 4,
543
559
  'account/set-auto-loan': 4,
544
560
  'account/account-level-switch-preset': 4,
@@ -565,6 +581,7 @@ class okx extends okx$1["default"] {
565
581
  'users/subaccount/set-transfer-out': 10,
566
582
  // grid trading
567
583
  'tradingBot/grid/order-algo': 1,
584
+ 'tradingBot/grid/copy-order-algo': 1,
568
585
  'tradingBot/grid/amend-algo-basic-param': 1,
569
586
  'tradingBot/grid/amend-order-algo': 1,
570
587
  'tradingBot/grid/stop-order-algo': 1,
@@ -588,6 +605,20 @@ class okx extends okx$1["default"] {
588
605
  'tradingBot/recurring/order-algo': 1,
589
606
  'tradingBot/recurring/amend-order-algo': 1,
590
607
  'tradingBot/recurring/stop-order-algo': 1,
608
+ 'tradingBot/dca/create': 1,
609
+ 'tradingBot/dca/amend-order-algo': 1,
610
+ 'tradingBot/dca/stop': 1,
611
+ 'tradingBot/dca/orders/manual-buy': 1,
612
+ 'tradingBot/dca/settings/reinvestment': 1,
613
+ 'tradingBot/dca/settings/take-profit': 1,
614
+ 'tradingBot/dca/margin/add': 1,
615
+ 'tradingBot/dca/margin/reduce': 1,
616
+ 'tradingBot/recurring/add-investment': 1,
617
+ 'tradingBot/recurring/amend-price-range': 1,
618
+ 'tradingBot/recurring/amend-recurring-amount': 1,
619
+ 'tradingBot/recurring/amend-recurring-time': 1,
620
+ 'tradingBot/recurring/pause': 1,
621
+ 'tradingBot/recurring/restart': 1,
591
622
  // earn
592
623
  'finance/savings/purchase-redempt': 5 / 3,
593
624
  'finance/savings/set-lending-rate': 5 / 3,
@@ -626,6 +657,9 @@ class okx extends okx$1["default"] {
626
657
  'broker/nd/rebate-per-orders': 36000,
627
658
  'finance/sfp/dcd/quote': 10,
628
659
  'finance/sfp/dcd/order': 10,
660
+ 'finance/sfp/dcd/trade': 10,
661
+ 'finance/sfp/dcd/redeem-quote': 10,
662
+ 'finance/sfp/dcd/redeem': 10,
629
663
  'broker/nd/report-subaccount-ip': 0.25,
630
664
  'broker/dma/subaccount/apikey': 1 / 4,
631
665
  'broker/dma/trades': 36000,
@@ -5779,6 +5813,16 @@ class okx extends okx$1["default"] {
5779
5813
  }
5780
5814
  const currencyId = this.safeString(transaction, 'ccy');
5781
5815
  const code = this.safeCurrencyCode(currencyId);
5816
+ let network = undefined;
5817
+ const chain = this.safeString(transaction, 'chain');
5818
+ if (chain !== undefined) {
5819
+ const chainParts = chain.split('-');
5820
+ const networkParts = this.arraySlice(chainParts, 1);
5821
+ const networkId = networkParts.join('-');
5822
+ if (networkId !== undefined) {
5823
+ network = this.networkIdToCode(networkId, code);
5824
+ }
5825
+ }
5782
5826
  const amount = this.safeNumber(transaction, 'amt');
5783
5827
  const status = this.parseTransactionStatus(this.safeString(transaction, 'state'));
5784
5828
  const txid = this.safeString(transaction, 'txId');
@@ -5796,7 +5840,7 @@ class okx extends okx$1["default"] {
5796
5840
  'id': id,
5797
5841
  'currency': code,
5798
5842
  'amount': amount,
5799
- 'network': undefined,
5843
+ 'network': network,
5800
5844
  'addressFrom': addressFrom,
5801
5845
  'addressTo': addressTo,
5802
5846
  'address': address,
@@ -6613,6 +6657,7 @@ class okx extends okx$1["default"] {
6613
6657
  parseFundingInterval(interval) {
6614
6658
  const intervals = {
6615
6659
  '3600000': '1h',
6660
+ '7200000': '2h',
6616
6661
  '14400000': '4h',
6617
6662
  '28800000': '8h',
6618
6663
  '57600000': '16h',
@@ -544,7 +544,9 @@ class paradex extends paradex$1["default"] {
544
544
  // }
545
545
  //
546
546
  const assetKind = this.safeString(market, 'asset_kind');
547
- const isOption = (assetKind === 'PERP_OPTION');
547
+ const isOptionPerpetual = (assetKind === 'PERP_OPTION');
548
+ const isOptionDelivery = (assetKind === 'OPTION');
549
+ const isOption = isOptionPerpetual || isOptionDelivery;
548
550
  const type = (isOption) ? 'option' : 'swap';
549
551
  const isSwap = (type === 'swap');
550
552
  const marketId = this.safeString(market, 'symbol');
@@ -562,7 +564,8 @@ class paradex extends paradex$1["default"] {
562
564
  let makerFee = this.parseNumber('-0.00005');
563
565
  if (isOption) {
564
566
  const optionTypeSuffix = (optionType === 'CALL') ? 'C' : 'P';
565
- symbol = symbol + '-' + strikePrice + '-' + optionTypeSuffix;
567
+ const deliveryValue = (expiry === 0) ? '' : this.yymmdd(expiry) + '-';
568
+ symbol = symbol + '-' + deliveryValue + strikePrice + '-' + optionTypeSuffix;
566
569
  makerFee = this.parseNumber('0.0003');
567
570
  }
568
571
  else {
@@ -249,7 +249,7 @@ class binance extends binance$1["default"] {
249
249
  return baseUrl;
250
250
  }
251
251
  getFutureWsCategory(channel) {
252
- if (channel === 'depth' || channel === 'rpiDepth' || channel === 'bookTicker' || channel === 'trade' || channel === 'aggTrade') {
252
+ if (channel === 'depth' || channel === 'rpiDepth' || channel === 'bookTicker' || channel === 'trade') {
253
253
  return 'public';
254
254
  }
255
255
  return 'market';
@@ -883,7 +883,7 @@ class cex extends cex$1["default"] {
883
883
  // {
884
884
  // "e": "open-orders",
885
885
  // "data": [{
886
- // "id": "59098421630",
886
+ // "id": "59098421631",
887
887
  // "time": "1664062285425",
888
888
  // "type": "buy",
889
889
  // "price": "18920",
@@ -689,7 +689,7 @@ class coinbase extends coinbase$1["default"] {
689
689
  const currentEvent = events[i];
690
690
  const currentTrades = this.safeList(currentEvent, 'trades');
691
691
  for (let j = 0; j < currentTrades.length; j++) {
692
- const item = currentTrades[i];
692
+ const item = currentTrades[j];
693
693
  tradesArray.append(this.parseTrade(item));
694
694
  }
695
695
  }
@@ -18,7 +18,7 @@ class hyperliquid extends hyperliquid$1["default"] {
18
18
  'createOrderWs': true,
19
19
  'createOrdersWs': true,
20
20
  'editOrderWs': true,
21
- 'watchBalance': false,
21
+ 'watchBalance': true,
22
22
  'watchMyTrades': true,
23
23
  'watchOHLCV': true,
24
24
  'watchOrderBook': true,
@@ -28,6 +28,9 @@ class hyperliquid extends hyperliquid$1["default"] {
28
28
  'watchTrades': true,
29
29
  'watchTradesForSymbols': false,
30
30
  'watchPosition': false,
31
+ 'unWatchBalance': true,
32
+ 'watchPositions': true,
33
+ 'unWatchPositions': true,
31
34
  'unWatchOrderBook': true,
32
35
  'unWatchTickers': true,
33
36
  'unWatchTrades': true,
@@ -911,6 +914,334 @@ class hyperliquid extends hyperliquid$1["default"] {
911
914
  const payload = this.safeDict(response, 'payload');
912
915
  client.resolve(payload, id);
913
916
  }
917
+ /**
918
+ * @method
919
+ * @name hyperliquid#watchBalance
920
+ * @description watch balance and get the amount of funds available for trading or funds locked in orders
921
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions
922
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
923
+ * @param {string} [params.dex] for for hip3 tokens subscription, eg: 'xyz' or 'flx'
924
+ * @returns {object} a [balance structure]{@link https://docs.ccxt.com/?id=balance-structure}
925
+ */
926
+ async watchBalance(params = {}) {
927
+ await this.loadMarkets();
928
+ let userAddress = undefined;
929
+ [userAddress, params] = this.handlePublicAddress('watchBalance', params);
930
+ let type = undefined;
931
+ [type, params] = this.handleMarketTypeAndParams('watchBalance', undefined, params);
932
+ let isUnifiedEnabled = undefined;
933
+ [isUnifiedEnabled, params] = await this.isUnifiedEnabled('watchBalance', userAddress, false, params);
934
+ const dex = this.safeString(params, 'dex');
935
+ const isSpot = ((type === 'spot') || isUnifiedEnabled) && (dex === undefined);
936
+ const topic = (isSpot) ? 'spotState' : 'clearinghouseState';
937
+ const messageHash = topic + '::balance';
938
+ const url = this.urls['api']['ws']['public'];
939
+ const subscription = {
940
+ 'type': topic,
941
+ 'user': userAddress,
942
+ };
943
+ if (isSpot) {
944
+ if (isUnifiedEnabled) {
945
+ subscription['isPortfolioMargin'] = true;
946
+ }
947
+ }
948
+ else {
949
+ if (dex !== undefined) {
950
+ subscription['dex'] = dex;
951
+ }
952
+ }
953
+ const request = {
954
+ 'method': 'subscribe',
955
+ 'subscription': subscription,
956
+ };
957
+ const message = this.extend(request, params);
958
+ return await this.watch(url, messageHash, message, topic);
959
+ }
960
+ /**
961
+ * @method
962
+ * @name hyperliquid#unWatchBalance
963
+ * @description unWatches balance
964
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions
965
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
966
+ * @returns {object} status of the unwatch request
967
+ */
968
+ async unWatchBalance(params = {}) {
969
+ await this.loadMarkets();
970
+ const url = this.urls['api']['ws']['public'];
971
+ let userAddress = undefined;
972
+ [userAddress, params] = this.handlePublicAddress('unWatchBalance', params);
973
+ let type = undefined;
974
+ [type, params] = this.handleMarketTypeAndParams('unWatchBalance', undefined, params);
975
+ let isUnifiedEnabled = undefined;
976
+ [isUnifiedEnabled, params] = await this.isUnifiedEnabled('unWatchBalance', userAddress, false, params);
977
+ const dex = this.safeString(params, 'dex');
978
+ const isSpot = ((type === 'spot') || isUnifiedEnabled) && (dex === undefined);
979
+ const topic = (isSpot) ? 'spotState' : 'clearinghouseState';
980
+ const messageHash = 'unsubscribe' + ':' + topic;
981
+ const request = {
982
+ 'method': 'unsubscribe',
983
+ 'subscription': {
984
+ 'type': topic,
985
+ 'user': userAddress,
986
+ },
987
+ };
988
+ const message = this.extend(request, params);
989
+ return await this.watch(url, messageHash, message, messageHash);
990
+ }
991
+ handleBalance(client, message) {
992
+ //
993
+ // spot
994
+ // {
995
+ // "channel": "spotState",
996
+ // "data": {
997
+ // "user": "0xeeeeexxxxeeeee",
998
+ // "spotState": {
999
+ // "balances": [
1000
+ // {
1001
+ // "coin": "USDH",
1002
+ // "token": 360,
1003
+ // "total": "0.0",
1004
+ // "hold": "0.0",
1005
+ // "entryNtl": "0.0"
1006
+ // }
1007
+ // ],
1008
+ // "tokenToAvailableAfterMaintenance": [
1009
+ // [
1010
+ // 0,
1011
+ // "56.1"
1012
+ // ]
1013
+ // ]
1014
+ // }
1015
+ // }
1016
+ // }
1017
+ // swap
1018
+ // {
1019
+ // "channel": "clearinghouseState",
1020
+ // "data": {
1021
+ // "dex": "",
1022
+ // "user": "0xeeeeexxxxeeeee",
1023
+ // "clearinghouseState": {
1024
+ // "marginSummary": {
1025
+ // "accountValue": "0.0",
1026
+ // "totalNtlPos": "0.0",
1027
+ // "totalRawUsd": "0.0",
1028
+ // "totalMarginUsed": "0.0"
1029
+ // },
1030
+ // "crossMarginSummary": {
1031
+ // "accountValue": "0.0",
1032
+ // "totalNtlPos": "0.0",
1033
+ // "totalRawUsd": "0.0",
1034
+ // "totalMarginUsed": "0.0"
1035
+ // },
1036
+ // "crossMaintenanceMarginUsed": "0.0",
1037
+ // "withdrawable": "0.0",
1038
+ // "assetPositions": [],
1039
+ // "time": 1776000003409
1040
+ // }
1041
+ // }
1042
+ // }
1043
+ //
1044
+ if (this.balance === undefined) {
1045
+ this.balance = {};
1046
+ }
1047
+ const topic = this.safeValue(message, 'channel');
1048
+ const messageHash = topic + '::balance';
1049
+ let info = undefined;
1050
+ let rawBalances = [];
1051
+ let account = undefined;
1052
+ let timestamp = undefined;
1053
+ const data = this.safeValue(message, 'data', []);
1054
+ if (topic === 'spotState') {
1055
+ const spotState = this.safeDict(data, 'spotState');
1056
+ rawBalances = this.safeList(spotState, 'balances');
1057
+ account = 'spot';
1058
+ info = rawBalances;
1059
+ }
1060
+ if (topic === 'clearinghouseState') {
1061
+ account = 'swap';
1062
+ const clearinghouseState = this.safeDict(data, 'clearinghouseState');
1063
+ rawBalances.push(clearinghouseState);
1064
+ info = clearinghouseState;
1065
+ timestamp = this.safeInteger(clearinghouseState, 'time');
1066
+ this.handlePositions(client, message);
1067
+ }
1068
+ for (let i = 0; i < rawBalances.length; i++) {
1069
+ this.parseWsBalance(rawBalances[i], account);
1070
+ }
1071
+ if (this.safeValue(this.balance, account) === undefined) {
1072
+ this.balance[account] = {};
1073
+ }
1074
+ this.balance[account]['info'] = info;
1075
+ this.balance[account]['timestamp'] = timestamp;
1076
+ this.balance[account]['datetime'] = this.iso8601(timestamp);
1077
+ this.balance[account] = this.safeBalance(this.balance[account]);
1078
+ client.resolve(this.balance[account], messageHash);
1079
+ }
1080
+ parseWsBalance(balance, accountType = undefined) {
1081
+ //
1082
+ // spot
1083
+ // {
1084
+ // "coin": "USDH",
1085
+ // "token": 360,
1086
+ // "total": "0.0",
1087
+ // "hold": "0.0",
1088
+ // "entryNtl": "0.0"
1089
+ // }
1090
+ // swap
1091
+ // {
1092
+ // "marginSummary": {
1093
+ // "accountValue": "0.0",
1094
+ // "totalNtlPos": "0.0",
1095
+ // "totalRawUsd": "0.0",
1096
+ // "totalMarginUsed": "0.0"
1097
+ // },
1098
+ // "crossMarginSummary": {
1099
+ // "accountValue": "0.0",
1100
+ // "totalNtlPos": "0.0",
1101
+ // "totalRawUsd": "0.0",
1102
+ // "totalMarginUsed": "0.0"
1103
+ // },
1104
+ // "crossMaintenanceMarginUsed": "0.0",
1105
+ // "withdrawable": "0.0",
1106
+ // "assetPositions": [],
1107
+ // "time": 1776000003409
1108
+ // }
1109
+ //
1110
+ const account = this.account();
1111
+ const currencyId = this.safeString(balance, 'coin');
1112
+ let code = undefined;
1113
+ if (currencyId === undefined) {
1114
+ code = 'USDC';
1115
+ const marginSummary = this.safeDict(balance, 'marginSummary', {});
1116
+ account['free'] = this.safeString(balance, 'withdrawable');
1117
+ account['used'] = this.safeString(marginSummary, 'totalMarginUsed');
1118
+ account['total'] = this.safeString(marginSummary, 'accountValue');
1119
+ }
1120
+ else {
1121
+ code = this.safeCurrencyCode(currencyId);
1122
+ account['used'] = this.safeString(balance, 'hold');
1123
+ account['total'] = this.safeString(balance, 'total');
1124
+ }
1125
+ if (accountType !== undefined) {
1126
+ if (this.safeValue(this.balance, accountType) === undefined) {
1127
+ this.balance[accountType] = {};
1128
+ }
1129
+ this.balance[accountType][code] = account;
1130
+ }
1131
+ else {
1132
+ this.balance[code] = account;
1133
+ }
1134
+ }
1135
+ /**
1136
+ * @method
1137
+ * @name hyperliquid#watchPositions
1138
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions
1139
+ * @description watch all open positions
1140
+ * @param {string[]} [symbols] list of unified market symbols
1141
+ * @param {int} [since] the earliest time in ms to fetch positions for
1142
+ * @param {int} [limit] the maximum number of positions to retrieve
1143
+ * @param {object} params extra parameters specific to the exchange API endpoint
1144
+ * @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
1145
+ */
1146
+ async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
1147
+ await this.loadMarkets();
1148
+ let userAddress = undefined;
1149
+ [userAddress, params] = this.handlePublicAddress('watchPositions', params);
1150
+ const topic = 'clearinghouseState';
1151
+ let messageHash = topic + '::positions';
1152
+ if (!this.isEmpty(symbols)) {
1153
+ symbols = this.marketSymbols(symbols);
1154
+ messageHash += '::' + symbols.join(',');
1155
+ }
1156
+ const url = this.urls['api']['ws']['public'];
1157
+ const subscription = {
1158
+ 'type': topic,
1159
+ 'user': userAddress,
1160
+ };
1161
+ const dexName = this.getDexFromSymbols('watchPositions', symbols);
1162
+ if (dexName !== undefined) {
1163
+ subscription['dex'] = dexName;
1164
+ }
1165
+ const request = {
1166
+ 'method': 'subscribe',
1167
+ 'subscription': subscription,
1168
+ };
1169
+ const message = this.extend(request, params);
1170
+ const client = this.client(url);
1171
+ this.setPositionsCache(client, symbols);
1172
+ const cache = this.positions;
1173
+ const newPositions = await this.watch(url, messageHash, message, topic);
1174
+ if (this.newUpdates) {
1175
+ return newPositions;
1176
+ }
1177
+ return this.filterBySymbolsSinceLimit(cache, symbols, since, limit, true);
1178
+ }
1179
+ setPositionsCache(client, symbols = undefined) {
1180
+ if (this.positions !== undefined) {
1181
+ return;
1182
+ }
1183
+ this.positions = new Cache.ArrayCacheBySymbolBySide();
1184
+ }
1185
+ handlePositions(client, message) {
1186
+ if (this.positions === undefined) {
1187
+ this.positions = new Cache.ArrayCacheBySymbolBySide();
1188
+ }
1189
+ const cache = this.positions;
1190
+ const data = this.safeDict(message, 'data', {});
1191
+ const clearinghouseState = this.safeDict(data, 'clearinghouseState', {});
1192
+ const newPositions = [];
1193
+ const rawPositions = this.safeList(clearinghouseState, 'assetPositions', []);
1194
+ for (let i = 0; i < rawPositions.length; i++) {
1195
+ const rawPosition = rawPositions[i];
1196
+ const position = this.parsePosition(rawPosition);
1197
+ newPositions.push(position);
1198
+ cache.append(position);
1199
+ }
1200
+ const baseMessageHash = 'clearinghouseState::positions';
1201
+ const messageHashes = this.findMessageHashes(client, baseMessageHash);
1202
+ for (let i = 0; i < messageHashes.length; i++) {
1203
+ const messageHash = messageHashes[i];
1204
+ const parts = messageHash.split('::');
1205
+ const symbolsString = this.safeString(parts, 2);
1206
+ if (symbolsString === undefined) {
1207
+ continue;
1208
+ }
1209
+ const symbols = symbolsString.split(',');
1210
+ const positions = this.filterByArray(newPositions, 'symbol', symbols, false);
1211
+ if (!this.isEmpty(positions)) {
1212
+ client.resolve(positions, messageHash);
1213
+ }
1214
+ }
1215
+ client.resolve(newPositions, baseMessageHash);
1216
+ }
1217
+ /**
1218
+ * @method
1219
+ * @name hyperliquid#unWatchPositions
1220
+ * @description unWatches all open positions
1221
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions
1222
+ * @param {string[]} [symbols] list of unified market symbols
1223
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1224
+ * @returns {object} status of the unwatch request
1225
+ */
1226
+ async unWatchPositions(symbols = undefined, params = {}) {
1227
+ await this.loadMarkets();
1228
+ if (!this.isEmpty(symbols)) {
1229
+ throw new errors.NotSupported(this.id + ' unWatchPositions() does not support a symbol parameter, you must unwatch all orders');
1230
+ }
1231
+ const messageHash = 'unsubscribe:clearinghouseState';
1232
+ const url = this.urls['api']['ws']['public'];
1233
+ let userAddress = undefined;
1234
+ [userAddress, params] = this.handlePublicAddress('unWatchPositions', params);
1235
+ const request = {
1236
+ 'method': 'unsubscribe',
1237
+ 'subscription': {
1238
+ 'type': 'clearinghouseState',
1239
+ 'user': userAddress,
1240
+ },
1241
+ };
1242
+ const message = this.extend(request, params);
1243
+ return await this.watch(url, messageHash, message, messageHash);
1244
+ }
914
1245
  /**
915
1246
  * @method
916
1247
  * @name hyperliquid#watchOrders
@@ -1165,6 +1496,27 @@ class hyperliquid extends hyperliquid$1["default"] {
1165
1496
  };
1166
1497
  this.cleanCache(topicStructure);
1167
1498
  }
1499
+ handlePositionsUnsubscription(client, subscription) {
1500
+ const subHash = 'clearinghouseState';
1501
+ const unSubHash = 'unsubscribe:' + subHash;
1502
+ this.cleanUnsubscription(client, subHash, unSubHash, true);
1503
+ const topicStructure = {
1504
+ 'topic': 'positions',
1505
+ };
1506
+ this.cleanCache(topicStructure);
1507
+ // clean swap balance if it existed
1508
+ if ('swap' in this.balance) {
1509
+ delete this.balance['swap'];
1510
+ }
1511
+ }
1512
+ handleSpotBalanceUnsubscription(client, subscription) {
1513
+ const subHash = 'spotState';
1514
+ const unSubHash = 'unsubscribe:' + subHash;
1515
+ this.cleanUnsubscription(client, subHash, unSubHash, true);
1516
+ if ('spot' in this.balance) {
1517
+ delete this.balance['spot'];
1518
+ }
1519
+ }
1168
1520
  handleSubscriptionResponse(client, message) {
1169
1521
  // {
1170
1522
  // "channel":"subscriptionResponse",
@@ -1213,6 +1565,12 @@ class hyperliquid extends hyperliquid$1["default"] {
1213
1565
  else if (type === 'userFills') {
1214
1566
  this.handleMyTradesUnsubscription(client, subscription);
1215
1567
  }
1568
+ else if (type === 'clearinghoustState') {
1569
+ this.handlePositionsUnsubscription(client, subscription);
1570
+ }
1571
+ else if (type === 'spotState') {
1572
+ this.handleSpotBalanceUnsubscription(client, subscription);
1573
+ }
1216
1574
  }
1217
1575
  }
1218
1576
  handleMessage(client, message) {
@@ -1245,6 +1603,8 @@ class hyperliquid extends hyperliquid$1["default"] {
1245
1603
  'allMids': this.handleWsTickers,
1246
1604
  'post': this.handleWsPost,
1247
1605
  'subscriptionResponse': this.handleSubscriptionResponse,
1606
+ 'clearinghouseState': this.handleBalance,
1607
+ 'spotState': this.handleBalance,
1248
1608
  };
1249
1609
  const exacMethod = this.safeValue(methods, topic);
1250
1610
  if (exacMethod !== undefined) {