ccxt 4.4.92__py2.py3-none-any.whl → 4.4.94__py2.py3-none-any.whl

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 (58) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/abstract/lbank.py +1 -1
  3. ccxt/ascendex.py +9 -8
  4. ccxt/async_support/__init__.py +1 -1
  5. ccxt/async_support/ascendex.py +9 -8
  6. ccxt/async_support/base/exchange.py +4 -1
  7. ccxt/async_support/base/ws/client.py +3 -0
  8. ccxt/async_support/binance.py +42 -1
  9. ccxt/async_support/bitmex.py +3 -3
  10. ccxt/async_support/bybit.py +83 -10
  11. ccxt/async_support/coinbase.py +4 -1
  12. ccxt/async_support/coinbaseexchange.py +53 -0
  13. ccxt/async_support/coincheck.py +45 -4
  14. ccxt/async_support/coinex.py +16 -12
  15. ccxt/async_support/coinmetro.py +15 -3
  16. ccxt/async_support/cryptomus.py +30 -52
  17. ccxt/async_support/deribit.py +6 -6
  18. ccxt/async_support/exmo.py +64 -52
  19. ccxt/async_support/htx.py +5 -1
  20. ccxt/async_support/hyperliquid.py +126 -33
  21. ccxt/async_support/kucoin.py +12 -14
  22. ccxt/async_support/latoken.py +19 -71
  23. ccxt/async_support/lbank.py +2 -2
  24. ccxt/async_support/okx.py +159 -3
  25. ccxt/async_support/paradex.py +54 -0
  26. ccxt/async_support/phemex.py +3 -3
  27. ccxt/async_support/wavesexchange.py +12 -2
  28. ccxt/base/exchange.py +96 -31
  29. ccxt/binance.py +42 -1
  30. ccxt/bitmex.py +3 -3
  31. ccxt/bybit.py +83 -10
  32. ccxt/coinbase.py +4 -1
  33. ccxt/coinbaseexchange.py +53 -0
  34. ccxt/coincheck.py +45 -4
  35. ccxt/coinex.py +16 -12
  36. ccxt/coinmetro.py +14 -3
  37. ccxt/cryptomus.py +30 -52
  38. ccxt/deribit.py +6 -6
  39. ccxt/exmo.py +64 -52
  40. ccxt/htx.py +5 -1
  41. ccxt/hyperliquid.py +126 -33
  42. ccxt/kucoin.py +12 -14
  43. ccxt/latoken.py +19 -71
  44. ccxt/lbank.py +2 -2
  45. ccxt/okx.py +159 -3
  46. ccxt/paradex.py +54 -0
  47. ccxt/phemex.py +3 -3
  48. ccxt/pro/__init__.py +1 -1
  49. ccxt/pro/bitstamp.py +48 -16
  50. ccxt/pro/bybit.py +2 -1
  51. ccxt/test/tests_async.py +17 -15
  52. ccxt/test/tests_sync.py +17 -15
  53. ccxt/wavesexchange.py +12 -2
  54. {ccxt-4.4.92.dist-info → ccxt-4.4.94.dist-info}/METADATA +4 -4
  55. {ccxt-4.4.92.dist-info → ccxt-4.4.94.dist-info}/RECORD +58 -58
  56. {ccxt-4.4.92.dist-info → ccxt-4.4.94.dist-info}/LICENSE.txt +0 -0
  57. {ccxt-4.4.92.dist-info → ccxt-4.4.94.dist-info}/WHEEL +0 -0
  58. {ccxt-4.4.92.dist-info → ccxt-4.4.94.dist-info}/top_level.txt +0 -0
@@ -354,6 +354,8 @@ class hyperliquid(Exchange, ImplicitAPI):
354
354
  :param dict [params]: extra parameters specific to the exchange API endpoint
355
355
  :returns dict: an associative dictionary of currencies
356
356
  """
357
+ if self.check_required_credentials(False):
358
+ await self.handle_builder_fee_approval()
357
359
  request: dict = {
358
360
  'type': 'meta',
359
361
  }
@@ -627,6 +629,7 @@ class hyperliquid(Exchange, ImplicitAPI):
627
629
  'quote': quote,
628
630
  'settle': None,
629
631
  'baseId': baseId,
632
+ 'baseName': baseName,
630
633
  'quoteId': quoteId,
631
634
  'settleId': None,
632
635
  'type': 'spot',
@@ -696,7 +699,8 @@ class hyperliquid(Exchange, ImplicitAPI):
696
699
  # }
697
700
  #
698
701
  quoteId = 'USDC'
699
- base = self.safe_string(market, 'name')
702
+ baseName = self.safe_string(market, 'name')
703
+ base = self.safe_currency_code(baseName)
700
704
  quote = self.safe_currency_code(quoteId)
701
705
  baseId = self.safe_string(market, 'baseId')
702
706
  settleId = 'USDC'
@@ -728,6 +732,7 @@ class hyperliquid(Exchange, ImplicitAPI):
728
732
  'quote': quote,
729
733
  'settle': settle,
730
734
  'baseId': baseId,
735
+ 'baseName': baseName,
731
736
  'quoteId': quoteId,
732
737
  'settleId': settleId,
733
738
  'type': 'swap',
@@ -784,6 +789,7 @@ class hyperliquid(Exchange, ImplicitAPI):
784
789
  :param str [params.user]: user address, will default to self.walletAddress if not provided
785
790
  :param str [params.type]: wallet type, ['spot', 'swap'], defaults to swap
786
791
  :param str [params.marginMode]: 'cross' or 'isolated', for margin trading, uses self.options.defaultMarginMode if not passed, defaults to None/None/None
792
+ :param str [params.subAccountAddress]: sub account user address
787
793
  :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
788
794
  """
789
795
  userAddress = None
@@ -793,9 +799,8 @@ class hyperliquid(Exchange, ImplicitAPI):
793
799
  marginMode = None
794
800
  marginMode, params = self.handle_margin_mode_and_params('fetchBalance', params)
795
801
  isSpot = (type == 'spot')
796
- reqType = 'spotClearinghouseState' if (isSpot) else 'clearinghouseState'
797
802
  request: dict = {
798
- 'type': reqType,
803
+ 'type': 'spotClearinghouseState' if (isSpot) else 'clearinghouseState',
799
804
  'user': userAddress,
800
805
  }
801
806
  response = await self.publicPostInfo(self.extend(request, params))
@@ -879,7 +884,7 @@ class hyperliquid(Exchange, ImplicitAPI):
879
884
  market = self.market(symbol)
880
885
  request: dict = {
881
886
  'type': 'l2Book',
882
- 'coin': market['base'] if market['swap'] else market['id'],
887
+ 'coin': market['baseName'] if market['swap'] else market['id'],
883
888
  }
884
889
  response = await self.publicPostInfo(self.extend(request, params))
885
890
  #
@@ -1112,7 +1117,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1112
1117
  request: dict = {
1113
1118
  'type': 'candleSnapshot',
1114
1119
  'req': {
1115
- 'coin': market['base'] if market['swap'] else market['id'],
1120
+ 'coin': market['baseName'] if market['swap'] else market['id'],
1116
1121
  'interval': self.safe_string(self.timeframes, timeframe, timeframe),
1117
1122
  'startTime': since,
1118
1123
  'endTime': until,
@@ -1175,6 +1180,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1175
1180
  :param int [params.until]: timestamp in ms of the latest trade
1176
1181
  :param str [params.address]: wallet address that made trades
1177
1182
  :param str [params.user]: wallet address that made trades
1183
+ :param str [params.subAccountAddress]: sub account user address
1178
1184
  :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
1179
1185
  """
1180
1186
  userAddress = None
@@ -1353,6 +1359,67 @@ class hyperliquid(Exchange, ImplicitAPI):
1353
1359
  }
1354
1360
  return self.sign_user_signed_action(messageTypes, message)
1355
1361
 
1362
+ def build_approve_builder_fee_sig(self, message):
1363
+ messageTypes: dict = {
1364
+ 'HyperliquidTransaction:ApproveBuilderFee': [
1365
+ {'name': 'hyperliquidChain', 'type': 'string'},
1366
+ {'name': 'maxFeeRate', 'type': 'string'},
1367
+ {'name': 'builder', 'type': 'address'},
1368
+ {'name': 'nonce', 'type': 'uint64'},
1369
+ ],
1370
+ }
1371
+ return self.sign_user_signed_action(messageTypes, message)
1372
+
1373
+ async def approve_builder_fee(self, builder: str, maxFeeRate: str):
1374
+ nonce = self.milliseconds()
1375
+ isSandboxMode = self.safe_bool(self.options, 'sandboxMode', False)
1376
+ payload: dict = {
1377
+ 'hyperliquidChain': 'Testnet' if isSandboxMode else 'Mainnet',
1378
+ 'maxFeeRate': maxFeeRate,
1379
+ 'builder': builder,
1380
+ 'nonce': nonce,
1381
+ }
1382
+ sig = self.build_approve_builder_fee_sig(payload)
1383
+ action = {
1384
+ 'hyperliquidChain': payload['hyperliquidChain'],
1385
+ 'signatureChainId': '0x66eee',
1386
+ 'maxFeeRate': payload['maxFeeRate'],
1387
+ 'builder': payload['builder'],
1388
+ 'nonce': nonce,
1389
+ 'type': 'approveBuilderFee',
1390
+ }
1391
+ request: dict = {
1392
+ 'action': action,
1393
+ 'nonce': nonce,
1394
+ 'signature': sig,
1395
+ 'vaultAddress': None,
1396
+ }
1397
+ #
1398
+ # {
1399
+ # "status": "ok",
1400
+ # "response": {
1401
+ # "type": "default"
1402
+ # }
1403
+ # }
1404
+ #
1405
+ return await self.privatePostExchange(request)
1406
+
1407
+ async def handle_builder_fee_approval(self):
1408
+ buildFee = self.safe_bool(self.options, 'builderFee', True)
1409
+ if not buildFee:
1410
+ return False # skip if builder fee is not enabled
1411
+ approvedBuilderFee = self.safe_bool(self.options, 'approvedBuilderFee', False)
1412
+ if approvedBuilderFee:
1413
+ return True # skip if builder fee is already approved
1414
+ try:
1415
+ builder = self.safe_string(self.options, 'builder', '0x6530512A6c89C7cfCEbC3BA7fcD9aDa5f30827a6')
1416
+ maxFeeRate = self.safe_string(self.options, 'feeRate', '0.01%')
1417
+ await self.approve_builder_fee(builder, maxFeeRate)
1418
+ self.options['approvedBuilderFee'] = True
1419
+ except Exception as e:
1420
+ self.options['builderFee'] = False # disable builder fee if an error occurs
1421
+ return True
1422
+
1356
1423
  async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
1357
1424
  """
1358
1425
  create a trade order
@@ -1372,6 +1439,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1372
1439
  :param str [params.clientOrderId]: client order id,(optional 128 bit hex string e.g. 0x1234567890abcdef1234567890abcdef)
1373
1440
  :param str [params.slippage]: the slippage for market order
1374
1441
  :param str [params.vaultAddress]: the vault address for order
1442
+ :param str [params.subAccountAddress]: sub account user address
1375
1443
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1376
1444
  """
1377
1445
  await self.load_markets()
@@ -1390,6 +1458,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1390
1458
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1391
1459
  """
1392
1460
  await self.load_markets()
1461
+ await self.handle_builder_fee_approval()
1393
1462
  request = self.create_orders_request(orders, params)
1394
1463
  response = await self.privatePostExchange(request)
1395
1464
  #
@@ -1553,10 +1622,10 @@ class hyperliquid(Exchange, ImplicitAPI):
1553
1622
  'type': 'order',
1554
1623
  'orders': orderReq,
1555
1624
  'grouping': grouping,
1556
- # 'brokerCode': 1, # cant
1557
1625
  }
1558
- if vaultAddress is None:
1559
- orderAction['brokerCode'] = 1
1626
+ if self.safe_bool(self.options, 'approvedBuilderFee', False):
1627
+ wallet = self.safe_string_lower(self.options, 'builder', '0x6530512A6c89C7cfCEbC3BA7fcD9aDa5f30827a6')
1628
+ orderAction['builder'] = {'b': wallet, 'f': self.safe_integer(self.options, 'feeInt', 10)}
1560
1629
  signature = self.sign_l1_action(orderAction, nonce, vaultAddress)
1561
1630
  request: dict = {
1562
1631
  'action': orderAction,
@@ -1581,6 +1650,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1581
1650
  :param dict [params]: extra parameters specific to the exchange API endpoint
1582
1651
  :param str [params.clientOrderId]: client order id,(optional 128 bit hex string e.g. 0x1234567890abcdef1234567890abcdef)
1583
1652
  :param str [params.vaultAddress]: the vault address for order
1653
+ :param str [params.subAccountAddress]: sub account user address
1584
1654
  :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1585
1655
  """
1586
1656
  orders = await self.cancel_orders([id], symbol, params)
@@ -1598,6 +1668,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1598
1668
  :param dict [params]: extra parameters specific to the exchange API endpoint
1599
1669
  :param string|str[] [params.clientOrderId]: client order ids,(optional 128 bit hex string e.g. 0x1234567890abcdef1234567890abcdef)
1600
1670
  :param str [params.vaultAddress]: the vault address
1671
+ :param str [params.subAccountAddress]: sub account user address
1601
1672
  :returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1602
1673
  """
1603
1674
  self.check_required_credentials()
@@ -1636,7 +1707,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1636
1707
  })
1637
1708
  cancelAction['cancels'] = cancelReq
1638
1709
  vaultAddress = None
1639
- vaultAddress, params = self.handle_option_and_params(params, 'cancelOrders', 'vaultAddress')
1710
+ vaultAddress, params = self.handle_option_and_params_2(params, 'cancelOrders', 'vaultAddress', 'subAccountAddress')
1640
1711
  vaultAddress = self.format_vault_address(vaultAddress)
1641
1712
  signature = self.sign_l1_action(cancelAction, nonce, vaultAddress)
1642
1713
  request['action'] = cancelAction
@@ -1680,6 +1751,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1680
1751
  :param CancellationRequest[] orders: each order should contain the parameters required by cancelOrder namely id and symbol, example [{"id": "a", "symbol": "BTC/USDT"}, {"id": "b", "symbol": "ETH/USDT"}]
1681
1752
  :param dict [params]: extra parameters specific to the exchange API endpoint
1682
1753
  :param str [params.vaultAddress]: the vault address
1754
+ :param str [params.subAccountAddress]: sub account user address
1683
1755
  :returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1684
1756
  """
1685
1757
  self.check_required_credentials()
@@ -1716,7 +1788,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1716
1788
  cancelAction['type'] = 'cancelByCloid' if cancelByCloid else 'cancel'
1717
1789
  cancelAction['cancels'] = cancelReq
1718
1790
  vaultAddress = None
1719
- vaultAddress, params = self.handle_option_and_params(params, 'cancelOrdersForSymbols', 'vaultAddress')
1791
+ vaultAddress, params = self.handle_option_and_params_2(params, 'cancelOrdersForSymbols', 'vaultAddress', 'subAccountAddress')
1720
1792
  vaultAddress = self.format_vault_address(vaultAddress)
1721
1793
  signature = self.sign_l1_action(cancelAction, nonce, vaultAddress)
1722
1794
  request['action'] = cancelAction
@@ -1746,6 +1818,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1746
1818
  :param number timeout: time in milliseconds, 0 represents cancel the timer
1747
1819
  :param dict [params]: extra parameters specific to the exchange API endpoint
1748
1820
  :param str [params.vaultAddress]: the vault address
1821
+ :param str [params.subAccountAddress]: sub account user address
1749
1822
  :returns dict: the api result
1750
1823
  """
1751
1824
  self.check_required_credentials()
@@ -1761,7 +1834,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1761
1834
  'time': nonce + timeout,
1762
1835
  }
1763
1836
  vaultAddress = None
1764
- vaultAddress, params = self.handle_option_and_params(params, 'cancelAllOrdersAfter', 'vaultAddress')
1837
+ vaultAddress, params = self.handle_option_and_params_2(params, 'cancelAllOrdersAfter', 'vaultAddress', 'subAccountAddress')
1765
1838
  vaultAddress = self.format_vault_address(vaultAddress)
1766
1839
  signature = self.sign_l1_action(cancelAction, nonce, vaultAddress)
1767
1840
  request['action'] = cancelAction
@@ -1904,6 +1977,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1904
1977
  :param float [params.triggerPrice]: The price at which a trigger order is triggered at
1905
1978
  :param str [params.clientOrderId]: client order id,(optional 128 bit hex string e.g. 0x1234567890abcdef1234567890abcdef)
1906
1979
  :param str [params.vaultAddress]: the vault address for order
1980
+ :param str [params.subAccountAddress]: sub account user address
1907
1981
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1908
1982
  """
1909
1983
  await self.load_markets()
@@ -2023,7 +2097,7 @@ class hyperliquid(Exchange, ImplicitAPI):
2023
2097
  market = self.market(symbol)
2024
2098
  request: dict = {
2025
2099
  'type': 'fundingHistory',
2026
- 'coin': market['base'],
2100
+ 'coin': market['baseName'],
2027
2101
  }
2028
2102
  if since is not None:
2029
2103
  request['startTime'] = since
@@ -2071,6 +2145,7 @@ class hyperliquid(Exchange, ImplicitAPI):
2071
2145
  :param dict [params]: extra parameters specific to the exchange API endpoint
2072
2146
  :param str [params.user]: user address, will default to self.walletAddress if not provided
2073
2147
  :param str [params.method]: 'openOrders' or 'frontendOpenOrders' default is 'frontendOpenOrders'
2148
+ :param str [params.subAccountAddress]: sub account user address
2074
2149
  :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2075
2150
  """
2076
2151
  userAddress = None
@@ -2159,6 +2234,7 @@ class hyperliquid(Exchange, ImplicitAPI):
2159
2234
  :param int [limit]: the maximum number of open orders structures to retrieve
2160
2235
  :param dict [params]: extra parameters specific to the exchange API endpoint
2161
2236
  :param str [params.user]: user address, will default to self.walletAddress if not provided
2237
+ :param str [params.subAccountAddress]: sub account user address
2162
2238
  :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2163
2239
  """
2164
2240
  userAddress = None
@@ -2195,6 +2271,7 @@ class hyperliquid(Exchange, ImplicitAPI):
2195
2271
  :param str symbol: unified symbol of the market the order was made in
2196
2272
  :param dict [params]: extra parameters specific to the exchange API endpoint
2197
2273
  :param str [params.user]: user address, will default to self.walletAddress if not provided
2274
+ :param str [params.subAccountAddress]: sub account user address
2198
2275
  :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2199
2276
  """
2200
2277
  userAddress = None
@@ -2420,6 +2497,7 @@ class hyperliquid(Exchange, ImplicitAPI):
2420
2497
  :param int [limit]: the maximum number of trades structures to retrieve
2421
2498
  :param dict [params]: extra parameters specific to the exchange API endpoint
2422
2499
  :param int [params.until]: timestamp in ms of the latest trade
2500
+ :param str [params.subAccountAddress]: sub account user address
2423
2501
  :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
2424
2502
  """
2425
2503
  userAddress = None
@@ -2540,6 +2618,7 @@ class hyperliquid(Exchange, ImplicitAPI):
2540
2618
  :param str[] [symbols]: list of unified market symbols
2541
2619
  :param dict [params]: extra parameters specific to the exchange API endpoint
2542
2620
  :param str [params.user]: user address, will default to self.walletAddress if not provided
2621
+ :param str [params.subAccountAddress]: sub account user address
2543
2622
  :returns dict[]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
2544
2623
  """
2545
2624
  await self.load_markets()
@@ -2680,6 +2759,8 @@ class hyperliquid(Exchange, ImplicitAPI):
2680
2759
  :param str symbol: unified market symbol of the market the position is held in, default is None
2681
2760
  :param dict [params]: extra parameters specific to the exchange API endpoint
2682
2761
  :param str [params.leverage]: the rate of leverage, is required if setting trade mode(symbol)
2762
+ :param str [params.vaultAddress]: the vault address
2763
+ :param str [params.subAccountAddress]: sub account user address
2683
2764
  :returns dict: response from the exchange
2684
2765
  """
2685
2766
  if symbol is None:
@@ -2700,7 +2781,7 @@ class hyperliquid(Exchange, ImplicitAPI):
2700
2781
  'leverage': leverage,
2701
2782
  }
2702
2783
  vaultAddress = None
2703
- vaultAddress, params = self.handle_option_and_params(params, 'setMarginMode', 'vaultAddress')
2784
+ vaultAddress, params = self.handle_option_and_params_2(params, 'setMarginMode', 'vaultAddress', 'subAccountAddress')
2704
2785
  if vaultAddress is not None:
2705
2786
  if vaultAddress.startswith('0x'):
2706
2787
  vaultAddress = vaultAddress.replace('0x', '')
@@ -2749,7 +2830,7 @@ class hyperliquid(Exchange, ImplicitAPI):
2749
2830
  'leverage': leverage,
2750
2831
  }
2751
2832
  vaultAddress = None
2752
- vaultAddress, params = self.handle_option_and_params(params, 'setLeverage', 'vaultAddress')
2833
+ vaultAddress, params = self.handle_option_and_params_2(params, 'setLeverage', 'vaultAddress', 'subAccountAddress')
2753
2834
  vaultAddress = self.format_vault_address(vaultAddress)
2754
2835
  signature = self.sign_l1_action(updateAction, nonce, vaultAddress)
2755
2836
  request: dict = {
@@ -2781,6 +2862,8 @@ class hyperliquid(Exchange, ImplicitAPI):
2781
2862
  :param str symbol: unified market symbol
2782
2863
  :param float amount: amount of margin to add
2783
2864
  :param dict [params]: extra parameters specific to the exchange API endpoint
2865
+ :param str [params.vaultAddress]: the vault address
2866
+ :param str [params.subAccountAddress]: sub account user address
2784
2867
  :returns dict: a `margin structure <https://docs.ccxt.com/#/?id=add-margin-structure>`
2785
2868
  """
2786
2869
  return await self.modify_margin_helper(symbol, amount, 'add', params)
@@ -2794,6 +2877,8 @@ class hyperliquid(Exchange, ImplicitAPI):
2794
2877
  :param str symbol: unified market symbol
2795
2878
  :param float amount: the amount of margin to remove
2796
2879
  :param dict [params]: extra parameters specific to the exchange API endpoint
2880
+ :param str [params.vaultAddress]: the vault address
2881
+ :param str [params.subAccountAddress]: sub account user address
2797
2882
  :returns dict: a `margin structure <https://docs.ccxt.com/#/?id=reduce-margin-structure>`
2798
2883
  """
2799
2884
  return await self.modify_margin_helper(symbol, amount, 'reduce', params)
@@ -2813,7 +2898,7 @@ class hyperliquid(Exchange, ImplicitAPI):
2813
2898
  'ntli': sz,
2814
2899
  }
2815
2900
  vaultAddress = None
2816
- vaultAddress, params = self.handle_option_and_params(params, 'modifyMargin', 'vaultAddress')
2901
+ vaultAddress, params = self.handle_option_and_params_2(params, 'modifyMargin', 'vaultAddress', 'subAccountAddress')
2817
2902
  vaultAddress = self.format_vault_address(vaultAddress)
2818
2903
  signature = self.sign_l1_action(updateAction, nonce, vaultAddress)
2819
2904
  request: dict = {
@@ -2908,28 +2993,31 @@ class hyperliquid(Exchange, ImplicitAPI):
2908
2993
  transferRequest['vaultAddress'] = vaultAddress
2909
2994
  transferResponse = await self.privatePostExchange(transferRequest)
2910
2995
  return transferResponse
2911
- # handle sub-account/different account transfer
2912
- self.check_address(toAccount)
2996
+ # transfer between main account and subaccount
2913
2997
  if code is not None:
2914
2998
  code = code.upper()
2915
2999
  if code != 'USDC':
2916
3000
  raise NotSupported(self.id + ' transfer() only support USDC')
2917
- payload: dict = {
2918
- 'hyperliquidChain': 'Testnet' if isSandboxMode else 'Mainnet',
2919
- 'destination': toAccount,
2920
- 'amount': self.number_to_string(amount),
2921
- 'time': nonce,
3001
+ isDeposit = False
3002
+ subAccountAddress = None
3003
+ if fromAccount == 'main':
3004
+ subAccountAddress = toAccount
3005
+ isDeposit = True
3006
+ elif toAccount == 'main':
3007
+ subAccountAddress = fromAccount
3008
+ else:
3009
+ raise NotSupported(self.id + ' transfer() only support main <> subaccount transfer')
3010
+ self.check_address(subAccountAddress)
3011
+ usd = self.parse_to_int(Precise.string_mul(self.number_to_string(amount), '1000000'))
3012
+ action = {
3013
+ 'type': 'subAccountTransfer',
3014
+ 'subAccountUser': subAccountAddress,
3015
+ 'isDeposit': isDeposit,
3016
+ 'usd': usd,
2922
3017
  }
2923
- sig = self.build_usd_send_sig(payload)
3018
+ sig = self.sign_l1_action(action, nonce)
2924
3019
  request: dict = {
2925
- 'action': {
2926
- 'hyperliquidChain': payload['hyperliquidChain'],
2927
- 'signatureChainId': '0x66eee', # check self out
2928
- 'destination': toAccount,
2929
- 'amount': str(amount),
2930
- 'time': nonce,
2931
- 'type': 'usdSend',
2932
- },
3020
+ 'action': action,
2933
3021
  'nonce': nonce,
2934
3022
  'signature': sig,
2935
3023
  }
@@ -3074,6 +3162,7 @@ class hyperliquid(Exchange, ImplicitAPI):
3074
3162
  :param str symbol: unified market symbol
3075
3163
  :param dict [params]: extra parameters specific to the exchange API endpoint
3076
3164
  :param str [params.user]: user address, will default to self.walletAddress if not provided
3165
+ :param str [params.subAccountAddress]: sub account user address
3077
3166
  :returns dict: a `fee structure <https://docs.ccxt.com/#/?id=fee-structure>`
3078
3167
  """
3079
3168
  await self.load_markets()
@@ -3180,6 +3269,7 @@ class hyperliquid(Exchange, ImplicitAPI):
3180
3269
  :param int [limit]: max number of ledger entries to return
3181
3270
  :param dict [params]: extra parameters specific to the exchange API endpoint
3182
3271
  :param int [params.until]: timestamp in ms of the latest ledger entry
3272
+ :param str [params.subAccountAddress]: sub account user address
3183
3273
  :returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger>`
3184
3274
  """
3185
3275
  await self.load_markets()
@@ -3267,6 +3357,7 @@ class hyperliquid(Exchange, ImplicitAPI):
3267
3357
  :param int [limit]: the maximum number of deposits structures to retrieve
3268
3358
  :param dict [params]: extra parameters specific to the exchange API endpoint
3269
3359
  :param int [params.until]: the latest time in ms to fetch withdrawals for
3360
+ :param str [params.subAccountAddress]: sub account user address
3270
3361
  :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
3271
3362
  """
3272
3363
  await self.load_markets()
@@ -3308,6 +3399,7 @@ class hyperliquid(Exchange, ImplicitAPI):
3308
3399
  :param int [limit]: the maximum number of withdrawals structures to retrieve
3309
3400
  :param dict [params]: extra parameters specific to the exchange API endpoint
3310
3401
  :param int [params.until]: the latest time in ms to fetch withdrawals for
3402
+ :param str [params.subAccountAddress]: sub account user address
3311
3403
  :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
3312
3404
  """
3313
3405
  await self.load_markets()
@@ -3405,6 +3497,7 @@ class hyperliquid(Exchange, ImplicitAPI):
3405
3497
  :param int [since]: the earliest time in ms to fetch funding history for
3406
3498
  :param int [limit]: the maximum number of funding history structures to retrieve
3407
3499
  :param dict [params]: extra parameters specific to the exchange API endpoint
3500
+ :param str [params.subAccountAddress]: sub account user address
3408
3501
  :returns dict: a `funding history structure <https://docs.ccxt.com/#/?id=funding-history-structure>`
3409
3502
  """
3410
3503
  await self.load_markets()
@@ -3495,7 +3588,7 @@ class hyperliquid(Exchange, ImplicitAPI):
3495
3588
 
3496
3589
  def handle_public_address(self, methodName: str, params: dict):
3497
3590
  userAux = None
3498
- userAux, params = self.handle_option_and_params(params, methodName, 'user')
3591
+ userAux, params = self.handle_option_and_params_2(params, methodName, 'user', 'subAccountAddress')
3499
3592
  user = userAux
3500
3593
  user, params = self.handle_option_and_params(params, methodName, 'address', userAux)
3501
3594
  if (user is not None) and (user != ''):
@@ -3562,7 +3655,7 @@ class hyperliquid(Exchange, ImplicitAPI):
3562
3655
  def parse_create_edit_order_args(self, id: Str, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
3563
3656
  market = self.market(symbol)
3564
3657
  vaultAddress = None
3565
- vaultAddress, params = self.handle_option_and_params(params, 'createOrder', 'vaultAddress')
3658
+ vaultAddress, params = self.handle_option_and_params_2(params, 'createOrder', 'vaultAddress', 'subAccountAddress')
3566
3659
  vaultAddress = self.format_vault_address(vaultAddress)
3567
3660
  symbol = market['symbol']
3568
3661
  order = {
@@ -1397,35 +1397,31 @@ class kucoin(Exchange, ImplicitAPI):
1397
1397
  # }
1398
1398
  #
1399
1399
  currenciesData = self.safe_list(response, 'data', [])
1400
+ brokenCurrencies = self.safe_list(self.options, 'brokenCurrencies', ['00', 'OPEN_ERROR', 'HUF', 'BDT'])
1401
+ otherFiats = self.safe_list(self.options, 'fiats', ['KWD', 'IRR', 'PKR'])
1400
1402
  result: dict = {}
1401
1403
  for i in range(0, len(currenciesData)):
1402
1404
  entry = currenciesData[i]
1403
1405
  id = self.safe_string(entry, 'currency')
1404
- name = self.safe_string(entry, 'fullName')
1406
+ if self.in_array(id, brokenCurrencies):
1407
+ continue # skip buggy entries: https://t.me/KuCoin_API/217798
1405
1408
  code = self.safe_currency_code(id)
1406
1409
  networks: dict = {}
1407
1410
  chains = self.safe_list(entry, 'chains', [])
1408
- rawPrecision = self.safe_string(entry, 'precision')
1409
- precision = self.parse_number(self.parse_precision(rawPrecision))
1410
1411
  chainsLength = len(chains)
1411
- if not chainsLength:
1412
- # one buggy coin, which doesn't contain info https://t.me/KuCoin_API/173118
1413
- continue
1414
1412
  for j in range(0, chainsLength):
1415
1413
  chain = chains[j]
1416
1414
  chainId = self.safe_string(chain, 'chainId')
1417
1415
  networkCode = self.network_id_to_code(chainId, code)
1418
- chainWithdrawEnabled = self.safe_bool(chain, 'isWithdrawEnabled', False)
1419
- chainDepositEnabled = self.safe_bool(chain, 'isDepositEnabled', False)
1420
1416
  networks[networkCode] = {
1421
1417
  'info': chain,
1422
1418
  'id': chainId,
1423
1419
  'name': self.safe_string(chain, 'chainName'),
1424
1420
  'code': networkCode,
1425
- 'active': chainWithdrawEnabled and chainDepositEnabled,
1421
+ 'active': None,
1426
1422
  'fee': self.safe_number(chain, 'withdrawalMinFee'),
1427
- 'deposit': chainDepositEnabled,
1428
- 'withdraw': chainWithdrawEnabled,
1423
+ 'deposit': self.safe_bool(chain, 'isDepositEnabled'),
1424
+ 'withdraw': self.safe_bool(chain, 'isWithdrawEnabled'),
1429
1425
  'precision': self.parse_number(self.parse_precision(self.safe_string(chain, 'withdrawPrecision'))),
1430
1426
  'limits': {
1431
1427
  'withdraw': {
@@ -1439,10 +1435,12 @@ class kucoin(Exchange, ImplicitAPI):
1439
1435
  },
1440
1436
  }
1441
1437
  # kucoin has determined 'fiat' currencies with below logic
1442
- isFiat = (rawPrecision == '2') and (chainsLength == 0)
1438
+ rawPrecision = self.safe_string(entry, 'precision')
1439
+ precision = self.parse_number(self.parse_precision(rawPrecision))
1440
+ isFiat = self.in_array(id, otherFiats) or ((rawPrecision == '2') and (chainsLength == 0))
1443
1441
  result[code] = self.safe_currency_structure({
1444
1442
  'id': id,
1445
- 'name': name,
1443
+ 'name': self.safe_string(entry, 'fullName'),
1446
1444
  'code': code,
1447
1445
  'type': 'fiat' if isFiat else 'crypto',
1448
1446
  'precision': precision,
@@ -2628,7 +2626,7 @@ class kucoin(Exchange, ImplicitAPI):
2628
2626
  """
2629
2627
  await self.load_markets()
2630
2628
  request: dict = {}
2631
- trigger = self.safe_bool(params, 'stop', False)
2629
+ trigger = self.safe_bool_2(params, 'trigger', 'stop', False)
2632
2630
  hf = None
2633
2631
  hf, params = self.handle_hf_and_params(params)
2634
2632
  params = self.omit(params, 'stop')
@@ -247,6 +247,8 @@ class latoken(Exchange, ImplicitAPI):
247
247
  'fetchTradingFee': {
248
248
  'method': 'fetchPrivateTradingFee', # or 'fetchPublicTradingFee'
249
249
  },
250
+ 'timeDifference': 0, # the difference between system clock and exchange clock
251
+ 'adjustForTimeDifference': True, # controls the adjustment logic upon instantiation
250
252
  },
251
253
  'features': {
252
254
  'spot': {
@@ -347,39 +349,6 @@ class latoken(Exchange, ImplicitAPI):
347
349
  :param dict [params]: extra parameters specific to the exchange API endpoint
348
350
  :returns dict[]: an array of objects representing market data
349
351
  """
350
- currencies = await self.fetch_currencies_from_cache(params)
351
- #
352
- # [
353
- # {
354
- # "id":"1a075819-9e0b-48fc-8784-4dab1d186d6d",
355
- # "status":"CURRENCY_STATUS_ACTIVE",
356
- # "type":"CURRENCY_TYPE_ALTERNATIVE", # CURRENCY_TYPE_CRYPTO, CURRENCY_TYPE_IEO
357
- # "name":"MyCryptoBank",
358
- # "tag":"MCB",
359
- # "description":"",
360
- # "logo":"",
361
- # "decimals":18,
362
- # "created":1572912000000,
363
- # "tier":1,
364
- # "assetClass":"ASSET_CLASS_UNKNOWN",
365
- # "minTransferAmount":0
366
- # },
367
- # {
368
- # "id":"db02758e-2507-46a5-a805-7bc60355b3eb",
369
- # "status":"CURRENCY_STATUS_ACTIVE",
370
- # "type":"CURRENCY_TYPE_FUTURES_CONTRACT",
371
- # "name":"BTC USDT Futures Contract",
372
- # "tag":"BTCUSDT",
373
- # "description":"",
374
- # "logo":"",
375
- # "decimals":8,
376
- # "created":1589459984395,
377
- # "tier":1,
378
- # "assetClass":"ASSET_CLASS_UNKNOWN",
379
- # "minTransferAmount":0
380
- # },
381
- # ]
382
- #
383
352
  response = await self.publicGetPair(params)
384
353
  #
385
354
  # [
@@ -401,8 +370,9 @@ class latoken(Exchange, ImplicitAPI):
401
370
  # }
402
371
  # ]
403
372
  #
404
- if self.safe_value(self.options, 'adjustForTimeDifference', True):
373
+ if self.safe_bool(self.options, 'adjustForTimeDifference', False):
405
374
  await self.load_time_difference()
375
+ currencies = self.safe_dict(self.options, 'cachedCurrencies', {})
406
376
  currenciesById = self.index_by(currencies, 'id')
407
377
  result = []
408
378
  for i in range(0, len(response)):
@@ -411,11 +381,13 @@ class latoken(Exchange, ImplicitAPI):
411
381
  # the exchange shows them inverted
412
382
  baseId = self.safe_string(market, 'baseCurrency')
413
383
  quoteId = self.safe_string(market, 'quoteCurrency')
414
- baseCurrency = self.safe_value(currenciesById, baseId)
415
- quoteCurrency = self.safe_value(currenciesById, quoteId)
416
- if baseCurrency is not None and quoteCurrency is not None:
417
- base = self.safe_currency_code(self.safe_string(baseCurrency, 'tag'))
418
- quote = self.safe_currency_code(self.safe_string(quoteCurrency, 'tag'))
384
+ baseCurrency = self.safe_dict(currenciesById, baseId)
385
+ quoteCurrency = self.safe_dict(currenciesById, quoteId)
386
+ baseCurrencyInfo = self.safe_dict(baseCurrency, 'info')
387
+ quoteCurrencyInfo = self.safe_dict(quoteCurrency, 'info')
388
+ if baseCurrencyInfo is not None and quoteCurrencyInfo is not None:
389
+ base = self.safe_currency_code(self.safe_string(baseCurrencyInfo, 'tag'))
390
+ quote = self.safe_currency_code(self.safe_string(quoteCurrencyInfo, 'tag'))
419
391
  lowercaseQuote = quote.lower()
420
392
  capitalizedQuote = self.capitalize(lowercaseQuote)
421
393
  status = self.safe_string(market, 'status')
@@ -470,28 +442,13 @@ class latoken(Exchange, ImplicitAPI):
470
442
  })
471
443
  return result
472
444
 
473
- async def fetch_currencies_from_cache(self, params={}):
474
- # self method is now redundant
475
- # currencies are now fetched before markets
476
- options = self.safe_value(self.options, 'fetchCurrencies', {})
477
- timestamp = self.safe_integer(options, 'timestamp')
478
- expires = self.safe_integer(options, 'expires', 1000)
479
- now = self.milliseconds()
480
- if (timestamp is None) or ((now - timestamp) > expires):
481
- response = await self.publicGetCurrency(params)
482
- self.options['fetchCurrencies'] = self.extend(options, {
483
- 'response': response,
484
- 'timestamp': now,
485
- })
486
- return self.safe_value(self.options['fetchCurrencies'], 'response')
487
-
488
445
  async def fetch_currencies(self, params={}) -> Currencies:
489
446
  """
490
447
  fetches all available currencies on an exchange
491
448
  :param dict [params]: extra parameters specific to the exchange API endpoint
492
449
  :returns dict: an associative dictionary of currencies
493
450
  """
494
- response = await self.fetch_currencies_from_cache(params)
451
+ response = await self.publicGetCurrency(params)
495
452
  #
496
453
  # [
497
454
  # {
@@ -530,27 +487,18 @@ class latoken(Exchange, ImplicitAPI):
530
487
  id = self.safe_string(currency, 'id')
531
488
  tag = self.safe_string(currency, 'tag')
532
489
  code = self.safe_currency_code(tag)
533
- fee = self.safe_number(currency, 'fee')
534
490
  currencyType = self.safe_string(currency, 'type')
535
- type = None
536
- if currencyType == 'CURRENCY_TYPE_ALTERNATIVE':
537
- type = 'other'
538
- else:
539
- # CURRENCY_TYPE_CRYPTO and CURRENCY_TYPE_IEO are all cryptos
540
- type = 'crypto'
541
- status = self.safe_string(currency, 'status')
542
- active = (status == 'CURRENCY_STATUS_ACTIVE')
543
- name = self.safe_string(currency, 'name')
544
- result[code] = {
491
+ isCrypto = (currencyType == 'CURRENCY_TYPE_CRYPTO' or currencyType == 'CURRENCY_TYPE_IEO')
492
+ result[code] = self.safe_currency_structure({
545
493
  'id': id,
546
494
  'code': code,
547
495
  'info': currency,
548
- 'name': name,
549
- 'type': type,
550
- 'active': active,
496
+ 'name': self.safe_string(currency, 'name'),
497
+ 'type': 'crypto' if isCrypto else 'other',
498
+ 'active': self.safe_string(currency, 'status') == 'CURRENCY_STATUS_ACTIVE',
551
499
  'deposit': None,
552
500
  'withdraw': None,
553
- 'fee': fee,
501
+ 'fee': self.safe_number(currency, 'fee'),
554
502
  'precision': self.parse_number(self.parse_precision(self.safe_string(currency, 'decimals'))),
555
503
  'limits': {
556
504
  'amount': {
@@ -563,7 +511,7 @@ class latoken(Exchange, ImplicitAPI):
563
511
  },
564
512
  },
565
513
  'networks': {},
566
- }
514
+ })
567
515
  return result
568
516
 
569
517
  async def fetch_balance(self, params={}) -> Balances: