ccxt 4.4.93__py2.py3-none-any.whl → 4.4.95__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 (52) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/abstract/bingx.py +3 -0
  3. ccxt/abstract/hyperliquid.py +1 -1
  4. ccxt/abstract/woo.py +59 -4
  5. ccxt/async_support/__init__.py +1 -1
  6. ccxt/async_support/base/exchange.py +1 -1
  7. ccxt/async_support/base/ws/future.py +2 -0
  8. ccxt/async_support/bingx.py +129 -92
  9. ccxt/async_support/bitget.py +1 -1
  10. ccxt/async_support/bitstamp.py +2 -0
  11. ccxt/async_support/blofin.py +6 -1
  12. ccxt/async_support/bybit.py +3 -3
  13. ccxt/async_support/coinbase.py +40 -1
  14. ccxt/async_support/coinmate.py +34 -0
  15. ccxt/async_support/coinmetro.py +15 -3
  16. ccxt/async_support/coinone.py +34 -0
  17. ccxt/async_support/coinsph.py +29 -0
  18. ccxt/async_support/gate.py +1 -1
  19. ccxt/async_support/htx.py +5 -1
  20. ccxt/async_support/hyperliquid.py +126 -33
  21. ccxt/async_support/okx.py +10 -3
  22. ccxt/async_support/wavesexchange.py +12 -2
  23. ccxt/async_support/woo.py +1251 -875
  24. ccxt/base/errors.py +0 -6
  25. ccxt/base/exchange.py +44 -22
  26. ccxt/bingx.py +129 -92
  27. ccxt/bitget.py +1 -1
  28. ccxt/bitstamp.py +2 -0
  29. ccxt/blofin.py +6 -1
  30. ccxt/bybit.py +3 -3
  31. ccxt/coinbase.py +40 -1
  32. ccxt/coinmate.py +34 -0
  33. ccxt/coinmetro.py +14 -3
  34. ccxt/coinone.py +34 -0
  35. ccxt/coinsph.py +29 -0
  36. ccxt/gate.py +1 -1
  37. ccxt/htx.py +5 -1
  38. ccxt/hyperliquid.py +126 -33
  39. ccxt/okx.py +10 -3
  40. ccxt/pro/__init__.py +1 -1
  41. ccxt/pro/hyperliquid.py +6 -6
  42. ccxt/pro/kraken.py +17 -16
  43. ccxt/pro/mexc.py +10 -10
  44. ccxt/test/tests_async.py +19 -17
  45. ccxt/test/tests_sync.py +19 -17
  46. ccxt/wavesexchange.py +12 -2
  47. ccxt/woo.py +1251 -875
  48. {ccxt-4.4.93.dist-info → ccxt-4.4.95.dist-info}/METADATA +4 -4
  49. {ccxt-4.4.93.dist-info → ccxt-4.4.95.dist-info}/RECORD +52 -52
  50. {ccxt-4.4.93.dist-info → ccxt-4.4.95.dist-info}/LICENSE.txt +0 -0
  51. {ccxt-4.4.93.dist-info → ccxt-4.4.95.dist-info}/WHEEL +0 -0
  52. {ccxt-4.4.93.dist-info → ccxt-4.4.95.dist-info}/top_level.txt +0 -0
@@ -174,6 +174,7 @@ class hyperliquid(Exchange, ImplicitAPI):
174
174
  'orderStatus': 2,
175
175
  'spotClearinghouseState': 2,
176
176
  'exchangeStatus': 2,
177
+ 'candleSnapshot': 3,
177
178
  },
178
179
  },
179
180
  },
@@ -354,6 +355,8 @@ class hyperliquid(Exchange, ImplicitAPI):
354
355
  :param dict [params]: extra parameters specific to the exchange API endpoint
355
356
  :returns dict: an associative dictionary of currencies
356
357
  """
358
+ if self.check_required_credentials(False):
359
+ await self.handle_builder_fee_approval()
357
360
  request: dict = {
358
361
  'type': 'meta',
359
362
  }
@@ -627,6 +630,7 @@ class hyperliquid(Exchange, ImplicitAPI):
627
630
  'quote': quote,
628
631
  'settle': None,
629
632
  'baseId': baseId,
633
+ 'baseName': baseName,
630
634
  'quoteId': quoteId,
631
635
  'settleId': None,
632
636
  'type': 'spot',
@@ -729,6 +733,7 @@ class hyperliquid(Exchange, ImplicitAPI):
729
733
  'quote': quote,
730
734
  'settle': settle,
731
735
  'baseId': baseId,
736
+ 'baseName': baseName,
732
737
  'quoteId': quoteId,
733
738
  'settleId': settleId,
734
739
  'type': 'swap',
@@ -785,6 +790,7 @@ class hyperliquid(Exchange, ImplicitAPI):
785
790
  :param str [params.user]: user address, will default to self.walletAddress if not provided
786
791
  :param str [params.type]: wallet type, ['spot', 'swap'], defaults to swap
787
792
  :param str [params.marginMode]: 'cross' or 'isolated', for margin trading, uses self.options.defaultMarginMode if not passed, defaults to None/None/None
793
+ :param str [params.subAccountAddress]: sub account user address
788
794
  :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
789
795
  """
790
796
  userAddress = None
@@ -794,9 +800,8 @@ class hyperliquid(Exchange, ImplicitAPI):
794
800
  marginMode = None
795
801
  marginMode, params = self.handle_margin_mode_and_params('fetchBalance', params)
796
802
  isSpot = (type == 'spot')
797
- reqType = 'spotClearinghouseState' if (isSpot) else 'clearinghouseState'
798
803
  request: dict = {
799
- 'type': reqType,
804
+ 'type': 'spotClearinghouseState' if (isSpot) else 'clearinghouseState',
800
805
  'user': userAddress,
801
806
  }
802
807
  response = await self.publicPostInfo(self.extend(request, params))
@@ -880,7 +885,7 @@ class hyperliquid(Exchange, ImplicitAPI):
880
885
  market = self.market(symbol)
881
886
  request: dict = {
882
887
  'type': 'l2Book',
883
- 'coin': market['base'] if market['swap'] else market['id'],
888
+ 'coin': market['baseName'] if market['swap'] else market['id'],
884
889
  }
885
890
  response = await self.publicPostInfo(self.extend(request, params))
886
891
  #
@@ -1113,7 +1118,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1113
1118
  request: dict = {
1114
1119
  'type': 'candleSnapshot',
1115
1120
  'req': {
1116
- 'coin': market['base'] if market['swap'] else market['id'],
1121
+ 'coin': market['baseName'] if market['swap'] else market['id'],
1117
1122
  'interval': self.safe_string(self.timeframes, timeframe, timeframe),
1118
1123
  'startTime': since,
1119
1124
  'endTime': until,
@@ -1176,6 +1181,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1176
1181
  :param int [params.until]: timestamp in ms of the latest trade
1177
1182
  :param str [params.address]: wallet address that made trades
1178
1183
  :param str [params.user]: wallet address that made trades
1184
+ :param str [params.subAccountAddress]: sub account user address
1179
1185
  :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
1180
1186
  """
1181
1187
  userAddress = None
@@ -1354,6 +1360,67 @@ class hyperliquid(Exchange, ImplicitAPI):
1354
1360
  }
1355
1361
  return self.sign_user_signed_action(messageTypes, message)
1356
1362
 
1363
+ def build_approve_builder_fee_sig(self, message):
1364
+ messageTypes: dict = {
1365
+ 'HyperliquidTransaction:ApproveBuilderFee': [
1366
+ {'name': 'hyperliquidChain', 'type': 'string'},
1367
+ {'name': 'maxFeeRate', 'type': 'string'},
1368
+ {'name': 'builder', 'type': 'address'},
1369
+ {'name': 'nonce', 'type': 'uint64'},
1370
+ ],
1371
+ }
1372
+ return self.sign_user_signed_action(messageTypes, message)
1373
+
1374
+ async def approve_builder_fee(self, builder: str, maxFeeRate: str):
1375
+ nonce = self.milliseconds()
1376
+ isSandboxMode = self.safe_bool(self.options, 'sandboxMode', False)
1377
+ payload: dict = {
1378
+ 'hyperliquidChain': 'Testnet' if isSandboxMode else 'Mainnet',
1379
+ 'maxFeeRate': maxFeeRate,
1380
+ 'builder': builder,
1381
+ 'nonce': nonce,
1382
+ }
1383
+ sig = self.build_approve_builder_fee_sig(payload)
1384
+ action = {
1385
+ 'hyperliquidChain': payload['hyperliquidChain'],
1386
+ 'signatureChainId': '0x66eee',
1387
+ 'maxFeeRate': payload['maxFeeRate'],
1388
+ 'builder': payload['builder'],
1389
+ 'nonce': nonce,
1390
+ 'type': 'approveBuilderFee',
1391
+ }
1392
+ request: dict = {
1393
+ 'action': action,
1394
+ 'nonce': nonce,
1395
+ 'signature': sig,
1396
+ 'vaultAddress': None,
1397
+ }
1398
+ #
1399
+ # {
1400
+ # "status": "ok",
1401
+ # "response": {
1402
+ # "type": "default"
1403
+ # }
1404
+ # }
1405
+ #
1406
+ return await self.privatePostExchange(request)
1407
+
1408
+ async def handle_builder_fee_approval(self):
1409
+ buildFee = self.safe_bool(self.options, 'builderFee', True)
1410
+ if not buildFee:
1411
+ return False # skip if builder fee is not enabled
1412
+ approvedBuilderFee = self.safe_bool(self.options, 'approvedBuilderFee', False)
1413
+ if approvedBuilderFee:
1414
+ return True # skip if builder fee is already approved
1415
+ try:
1416
+ builder = self.safe_string(self.options, 'builder', '0x6530512A6c89C7cfCEbC3BA7fcD9aDa5f30827a6')
1417
+ maxFeeRate = self.safe_string(self.options, 'feeRate', '0.01%')
1418
+ await self.approve_builder_fee(builder, maxFeeRate)
1419
+ self.options['approvedBuilderFee'] = True
1420
+ except Exception as e:
1421
+ self.options['builderFee'] = False # disable builder fee if an error occurs
1422
+ return True
1423
+
1357
1424
  async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
1358
1425
  """
1359
1426
  create a trade order
@@ -1373,6 +1440,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1373
1440
  :param str [params.clientOrderId]: client order id,(optional 128 bit hex string e.g. 0x1234567890abcdef1234567890abcdef)
1374
1441
  :param str [params.slippage]: the slippage for market order
1375
1442
  :param str [params.vaultAddress]: the vault address for order
1443
+ :param str [params.subAccountAddress]: sub account user address
1376
1444
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1377
1445
  """
1378
1446
  await self.load_markets()
@@ -1391,6 +1459,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1391
1459
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1392
1460
  """
1393
1461
  await self.load_markets()
1462
+ await self.handle_builder_fee_approval()
1394
1463
  request = self.create_orders_request(orders, params)
1395
1464
  response = await self.privatePostExchange(request)
1396
1465
  #
@@ -1554,10 +1623,10 @@ class hyperliquid(Exchange, ImplicitAPI):
1554
1623
  'type': 'order',
1555
1624
  'orders': orderReq,
1556
1625
  'grouping': grouping,
1557
- # 'brokerCode': 1, # cant
1558
1626
  }
1559
- if vaultAddress is None:
1560
- orderAction['brokerCode'] = 1
1627
+ if self.safe_bool(self.options, 'approvedBuilderFee', False):
1628
+ wallet = self.safe_string_lower(self.options, 'builder', '0x6530512A6c89C7cfCEbC3BA7fcD9aDa5f30827a6')
1629
+ orderAction['builder'] = {'b': wallet, 'f': self.safe_integer(self.options, 'feeInt', 10)}
1561
1630
  signature = self.sign_l1_action(orderAction, nonce, vaultAddress)
1562
1631
  request: dict = {
1563
1632
  'action': orderAction,
@@ -1582,6 +1651,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1582
1651
  :param dict [params]: extra parameters specific to the exchange API endpoint
1583
1652
  :param str [params.clientOrderId]: client order id,(optional 128 bit hex string e.g. 0x1234567890abcdef1234567890abcdef)
1584
1653
  :param str [params.vaultAddress]: the vault address for order
1654
+ :param str [params.subAccountAddress]: sub account user address
1585
1655
  :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1586
1656
  """
1587
1657
  orders = await self.cancel_orders([id], symbol, params)
@@ -1599,6 +1669,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1599
1669
  :param dict [params]: extra parameters specific to the exchange API endpoint
1600
1670
  :param string|str[] [params.clientOrderId]: client order ids,(optional 128 bit hex string e.g. 0x1234567890abcdef1234567890abcdef)
1601
1671
  :param str [params.vaultAddress]: the vault address
1672
+ :param str [params.subAccountAddress]: sub account user address
1602
1673
  :returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1603
1674
  """
1604
1675
  self.check_required_credentials()
@@ -1637,7 +1708,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1637
1708
  })
1638
1709
  cancelAction['cancels'] = cancelReq
1639
1710
  vaultAddress = None
1640
- vaultAddress, params = self.handle_option_and_params(params, 'cancelOrders', 'vaultAddress')
1711
+ vaultAddress, params = self.handle_option_and_params_2(params, 'cancelOrders', 'vaultAddress', 'subAccountAddress')
1641
1712
  vaultAddress = self.format_vault_address(vaultAddress)
1642
1713
  signature = self.sign_l1_action(cancelAction, nonce, vaultAddress)
1643
1714
  request['action'] = cancelAction
@@ -1681,6 +1752,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1681
1752
  :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"}]
1682
1753
  :param dict [params]: extra parameters specific to the exchange API endpoint
1683
1754
  :param str [params.vaultAddress]: the vault address
1755
+ :param str [params.subAccountAddress]: sub account user address
1684
1756
  :returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1685
1757
  """
1686
1758
  self.check_required_credentials()
@@ -1717,7 +1789,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1717
1789
  cancelAction['type'] = 'cancelByCloid' if cancelByCloid else 'cancel'
1718
1790
  cancelAction['cancels'] = cancelReq
1719
1791
  vaultAddress = None
1720
- vaultAddress, params = self.handle_option_and_params(params, 'cancelOrdersForSymbols', 'vaultAddress')
1792
+ vaultAddress, params = self.handle_option_and_params_2(params, 'cancelOrdersForSymbols', 'vaultAddress', 'subAccountAddress')
1721
1793
  vaultAddress = self.format_vault_address(vaultAddress)
1722
1794
  signature = self.sign_l1_action(cancelAction, nonce, vaultAddress)
1723
1795
  request['action'] = cancelAction
@@ -1747,6 +1819,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1747
1819
  :param number timeout: time in milliseconds, 0 represents cancel the timer
1748
1820
  :param dict [params]: extra parameters specific to the exchange API endpoint
1749
1821
  :param str [params.vaultAddress]: the vault address
1822
+ :param str [params.subAccountAddress]: sub account user address
1750
1823
  :returns dict: the api result
1751
1824
  """
1752
1825
  self.check_required_credentials()
@@ -1762,7 +1835,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1762
1835
  'time': nonce + timeout,
1763
1836
  }
1764
1837
  vaultAddress = None
1765
- vaultAddress, params = self.handle_option_and_params(params, 'cancelAllOrdersAfter', 'vaultAddress')
1838
+ vaultAddress, params = self.handle_option_and_params_2(params, 'cancelAllOrdersAfter', 'vaultAddress', 'subAccountAddress')
1766
1839
  vaultAddress = self.format_vault_address(vaultAddress)
1767
1840
  signature = self.sign_l1_action(cancelAction, nonce, vaultAddress)
1768
1841
  request['action'] = cancelAction
@@ -1905,6 +1978,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1905
1978
  :param float [params.triggerPrice]: The price at which a trigger order is triggered at
1906
1979
  :param str [params.clientOrderId]: client order id,(optional 128 bit hex string e.g. 0x1234567890abcdef1234567890abcdef)
1907
1980
  :param str [params.vaultAddress]: the vault address for order
1981
+ :param str [params.subAccountAddress]: sub account user address
1908
1982
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1909
1983
  """
1910
1984
  await self.load_markets()
@@ -2024,7 +2098,7 @@ class hyperliquid(Exchange, ImplicitAPI):
2024
2098
  market = self.market(symbol)
2025
2099
  request: dict = {
2026
2100
  'type': 'fundingHistory',
2027
- 'coin': market['base'],
2101
+ 'coin': market['baseName'],
2028
2102
  }
2029
2103
  if since is not None:
2030
2104
  request['startTime'] = since
@@ -2072,6 +2146,7 @@ class hyperliquid(Exchange, ImplicitAPI):
2072
2146
  :param dict [params]: extra parameters specific to the exchange API endpoint
2073
2147
  :param str [params.user]: user address, will default to self.walletAddress if not provided
2074
2148
  :param str [params.method]: 'openOrders' or 'frontendOpenOrders' default is 'frontendOpenOrders'
2149
+ :param str [params.subAccountAddress]: sub account user address
2075
2150
  :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2076
2151
  """
2077
2152
  userAddress = None
@@ -2160,6 +2235,7 @@ class hyperliquid(Exchange, ImplicitAPI):
2160
2235
  :param int [limit]: the maximum number of open orders structures to retrieve
2161
2236
  :param dict [params]: extra parameters specific to the exchange API endpoint
2162
2237
  :param str [params.user]: user address, will default to self.walletAddress if not provided
2238
+ :param str [params.subAccountAddress]: sub account user address
2163
2239
  :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2164
2240
  """
2165
2241
  userAddress = None
@@ -2196,6 +2272,7 @@ class hyperliquid(Exchange, ImplicitAPI):
2196
2272
  :param str symbol: unified symbol of the market the order was made in
2197
2273
  :param dict [params]: extra parameters specific to the exchange API endpoint
2198
2274
  :param str [params.user]: user address, will default to self.walletAddress if not provided
2275
+ :param str [params.subAccountAddress]: sub account user address
2199
2276
  :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2200
2277
  """
2201
2278
  userAddress = None
@@ -2421,6 +2498,7 @@ class hyperliquid(Exchange, ImplicitAPI):
2421
2498
  :param int [limit]: the maximum number of trades structures to retrieve
2422
2499
  :param dict [params]: extra parameters specific to the exchange API endpoint
2423
2500
  :param int [params.until]: timestamp in ms of the latest trade
2501
+ :param str [params.subAccountAddress]: sub account user address
2424
2502
  :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
2425
2503
  """
2426
2504
  userAddress = None
@@ -2541,6 +2619,7 @@ class hyperliquid(Exchange, ImplicitAPI):
2541
2619
  :param str[] [symbols]: list of unified market symbols
2542
2620
  :param dict [params]: extra parameters specific to the exchange API endpoint
2543
2621
  :param str [params.user]: user address, will default to self.walletAddress if not provided
2622
+ :param str [params.subAccountAddress]: sub account user address
2544
2623
  :returns dict[]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
2545
2624
  """
2546
2625
  await self.load_markets()
@@ -2681,6 +2760,8 @@ class hyperliquid(Exchange, ImplicitAPI):
2681
2760
  :param str symbol: unified market symbol of the market the position is held in, default is None
2682
2761
  :param dict [params]: extra parameters specific to the exchange API endpoint
2683
2762
  :param str [params.leverage]: the rate of leverage, is required if setting trade mode(symbol)
2763
+ :param str [params.vaultAddress]: the vault address
2764
+ :param str [params.subAccountAddress]: sub account user address
2684
2765
  :returns dict: response from the exchange
2685
2766
  """
2686
2767
  if symbol is None:
@@ -2701,7 +2782,7 @@ class hyperliquid(Exchange, ImplicitAPI):
2701
2782
  'leverage': leverage,
2702
2783
  }
2703
2784
  vaultAddress = None
2704
- vaultAddress, params = self.handle_option_and_params(params, 'setMarginMode', 'vaultAddress')
2785
+ vaultAddress, params = self.handle_option_and_params_2(params, 'setMarginMode', 'vaultAddress', 'subAccountAddress')
2705
2786
  if vaultAddress is not None:
2706
2787
  if vaultAddress.startswith('0x'):
2707
2788
  vaultAddress = vaultAddress.replace('0x', '')
@@ -2750,7 +2831,7 @@ class hyperliquid(Exchange, ImplicitAPI):
2750
2831
  'leverage': leverage,
2751
2832
  }
2752
2833
  vaultAddress = None
2753
- vaultAddress, params = self.handle_option_and_params(params, 'setLeverage', 'vaultAddress')
2834
+ vaultAddress, params = self.handle_option_and_params_2(params, 'setLeverage', 'vaultAddress', 'subAccountAddress')
2754
2835
  vaultAddress = self.format_vault_address(vaultAddress)
2755
2836
  signature = self.sign_l1_action(updateAction, nonce, vaultAddress)
2756
2837
  request: dict = {
@@ -2782,6 +2863,8 @@ class hyperliquid(Exchange, ImplicitAPI):
2782
2863
  :param str symbol: unified market symbol
2783
2864
  :param float amount: amount of margin to add
2784
2865
  :param dict [params]: extra parameters specific to the exchange API endpoint
2866
+ :param str [params.vaultAddress]: the vault address
2867
+ :param str [params.subAccountAddress]: sub account user address
2785
2868
  :returns dict: a `margin structure <https://docs.ccxt.com/#/?id=add-margin-structure>`
2786
2869
  """
2787
2870
  return await self.modify_margin_helper(symbol, amount, 'add', params)
@@ -2795,6 +2878,8 @@ class hyperliquid(Exchange, ImplicitAPI):
2795
2878
  :param str symbol: unified market symbol
2796
2879
  :param float amount: the amount of margin to remove
2797
2880
  :param dict [params]: extra parameters specific to the exchange API endpoint
2881
+ :param str [params.vaultAddress]: the vault address
2882
+ :param str [params.subAccountAddress]: sub account user address
2798
2883
  :returns dict: a `margin structure <https://docs.ccxt.com/#/?id=reduce-margin-structure>`
2799
2884
  """
2800
2885
  return await self.modify_margin_helper(symbol, amount, 'reduce', params)
@@ -2814,7 +2899,7 @@ class hyperliquid(Exchange, ImplicitAPI):
2814
2899
  'ntli': sz,
2815
2900
  }
2816
2901
  vaultAddress = None
2817
- vaultAddress, params = self.handle_option_and_params(params, 'modifyMargin', 'vaultAddress')
2902
+ vaultAddress, params = self.handle_option_and_params_2(params, 'modifyMargin', 'vaultAddress', 'subAccountAddress')
2818
2903
  vaultAddress = self.format_vault_address(vaultAddress)
2819
2904
  signature = self.sign_l1_action(updateAction, nonce, vaultAddress)
2820
2905
  request: dict = {
@@ -2909,28 +2994,31 @@ class hyperliquid(Exchange, ImplicitAPI):
2909
2994
  transferRequest['vaultAddress'] = vaultAddress
2910
2995
  transferResponse = await self.privatePostExchange(transferRequest)
2911
2996
  return transferResponse
2912
- # handle sub-account/different account transfer
2913
- self.check_address(toAccount)
2997
+ # transfer between main account and subaccount
2914
2998
  if code is not None:
2915
2999
  code = code.upper()
2916
3000
  if code != 'USDC':
2917
3001
  raise NotSupported(self.id + ' transfer() only support USDC')
2918
- payload: dict = {
2919
- 'hyperliquidChain': 'Testnet' if isSandboxMode else 'Mainnet',
2920
- 'destination': toAccount,
2921
- 'amount': self.number_to_string(amount),
2922
- 'time': nonce,
3002
+ isDeposit = False
3003
+ subAccountAddress = None
3004
+ if fromAccount == 'main':
3005
+ subAccountAddress = toAccount
3006
+ isDeposit = True
3007
+ elif toAccount == 'main':
3008
+ subAccountAddress = fromAccount
3009
+ else:
3010
+ raise NotSupported(self.id + ' transfer() only support main <> subaccount transfer')
3011
+ self.check_address(subAccountAddress)
3012
+ usd = self.parse_to_int(Precise.string_mul(self.number_to_string(amount), '1000000'))
3013
+ action = {
3014
+ 'type': 'subAccountTransfer',
3015
+ 'subAccountUser': subAccountAddress,
3016
+ 'isDeposit': isDeposit,
3017
+ 'usd': usd,
2923
3018
  }
2924
- sig = self.build_usd_send_sig(payload)
3019
+ sig = self.sign_l1_action(action, nonce)
2925
3020
  request: dict = {
2926
- 'action': {
2927
- 'hyperliquidChain': payload['hyperliquidChain'],
2928
- 'signatureChainId': '0x66eee', # check self out
2929
- 'destination': toAccount,
2930
- 'amount': str(amount),
2931
- 'time': nonce,
2932
- 'type': 'usdSend',
2933
- },
3021
+ 'action': action,
2934
3022
  'nonce': nonce,
2935
3023
  'signature': sig,
2936
3024
  }
@@ -3075,6 +3163,7 @@ class hyperliquid(Exchange, ImplicitAPI):
3075
3163
  :param str symbol: unified market symbol
3076
3164
  :param dict [params]: extra parameters specific to the exchange API endpoint
3077
3165
  :param str [params.user]: user address, will default to self.walletAddress if not provided
3166
+ :param str [params.subAccountAddress]: sub account user address
3078
3167
  :returns dict: a `fee structure <https://docs.ccxt.com/#/?id=fee-structure>`
3079
3168
  """
3080
3169
  await self.load_markets()
@@ -3181,6 +3270,7 @@ class hyperliquid(Exchange, ImplicitAPI):
3181
3270
  :param int [limit]: max number of ledger entries to return
3182
3271
  :param dict [params]: extra parameters specific to the exchange API endpoint
3183
3272
  :param int [params.until]: timestamp in ms of the latest ledger entry
3273
+ :param str [params.subAccountAddress]: sub account user address
3184
3274
  :returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger>`
3185
3275
  """
3186
3276
  await self.load_markets()
@@ -3268,6 +3358,7 @@ class hyperliquid(Exchange, ImplicitAPI):
3268
3358
  :param int [limit]: the maximum number of deposits structures to retrieve
3269
3359
  :param dict [params]: extra parameters specific to the exchange API endpoint
3270
3360
  :param int [params.until]: the latest time in ms to fetch withdrawals for
3361
+ :param str [params.subAccountAddress]: sub account user address
3271
3362
  :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
3272
3363
  """
3273
3364
  await self.load_markets()
@@ -3309,6 +3400,7 @@ class hyperliquid(Exchange, ImplicitAPI):
3309
3400
  :param int [limit]: the maximum number of withdrawals structures to retrieve
3310
3401
  :param dict [params]: extra parameters specific to the exchange API endpoint
3311
3402
  :param int [params.until]: the latest time in ms to fetch withdrawals for
3403
+ :param str [params.subAccountAddress]: sub account user address
3312
3404
  :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
3313
3405
  """
3314
3406
  await self.load_markets()
@@ -3406,6 +3498,7 @@ class hyperliquid(Exchange, ImplicitAPI):
3406
3498
  :param int [since]: the earliest time in ms to fetch funding history for
3407
3499
  :param int [limit]: the maximum number of funding history structures to retrieve
3408
3500
  :param dict [params]: extra parameters specific to the exchange API endpoint
3501
+ :param str [params.subAccountAddress]: sub account user address
3409
3502
  :returns dict: a `funding history structure <https://docs.ccxt.com/#/?id=funding-history-structure>`
3410
3503
  """
3411
3504
  await self.load_markets()
@@ -3496,7 +3589,7 @@ class hyperliquid(Exchange, ImplicitAPI):
3496
3589
 
3497
3590
  def handle_public_address(self, methodName: str, params: dict):
3498
3591
  userAux = None
3499
- userAux, params = self.handle_option_and_params(params, methodName, 'user')
3592
+ userAux, params = self.handle_option_and_params_2(params, methodName, 'user', 'subAccountAddress')
3500
3593
  user = userAux
3501
3594
  user, params = self.handle_option_and_params(params, methodName, 'address', userAux)
3502
3595
  if (user is not None) and (user != ''):
@@ -3508,7 +3601,7 @@ class hyperliquid(Exchange, ImplicitAPI):
3508
3601
  def coin_to_market_id(self, coin: Str):
3509
3602
  if coin.find('/') > -1 or coin.find('@') > -1:
3510
3603
  return coin # spot
3511
- return coin + '/USDC:USDC'
3604
+ return self.safe_currency_code(coin) + '/USDC:USDC'
3512
3605
 
3513
3606
  def handle_errors(self, code: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
3514
3607
  if not response:
@@ -3563,7 +3656,7 @@ class hyperliquid(Exchange, ImplicitAPI):
3563
3656
  def parse_create_edit_order_args(self, id: Str, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
3564
3657
  market = self.market(symbol)
3565
3658
  vaultAddress = None
3566
- vaultAddress, params = self.handle_option_and_params(params, 'createOrder', 'vaultAddress')
3659
+ vaultAddress, params = self.handle_option_and_params_2(params, 'createOrder', 'vaultAddress', 'subAccountAddress')
3567
3660
  vaultAddress = self.format_vault_address(vaultAddress)
3568
3661
  symbol = market['symbol']
3569
3662
  order = {
ccxt/async_support/okx.py CHANGED
@@ -2557,11 +2557,11 @@ class okx(Exchange, ImplicitAPI):
2557
2557
  # it may be incorrect to use total, free and used for swap accounts
2558
2558
  eq = self.safe_string(balance, 'eq')
2559
2559
  availEq = self.safe_string(balance, 'availEq')
2560
- if (eq is None) or (availEq is None):
2560
+ account['total'] = eq
2561
+ if availEq is None:
2561
2562
  account['free'] = self.safe_string(balance, 'availBal')
2562
2563
  account['used'] = self.safe_string(balance, 'frozenBal')
2563
2564
  else:
2564
- account['total'] = eq
2565
2565
  account['free'] = availEq
2566
2566
  result[code] = account
2567
2567
  result['timestamp'] = timestamp
@@ -2959,7 +2959,8 @@ class okx(Exchange, ImplicitAPI):
2959
2959
  stopLossTriggerPrice = self.safe_value_n(stopLoss, ['triggerPrice', 'stopPrice', 'slTriggerPx'])
2960
2960
  if stopLossTriggerPrice is None:
2961
2961
  raise InvalidOrder(self.id + ' createOrder() requires a trigger price in params["stopLoss"]["triggerPrice"], or params["stopLoss"]["stopPrice"], or params["stopLoss"]["slTriggerPx"] for a stop loss order')
2962
- request['slTriggerPx'] = self.price_to_precision(symbol, stopLossTriggerPrice)
2962
+ slTriggerPx = self.price_to_precision(symbol, stopLossTriggerPrice)
2963
+ request['slTriggerPx'] = slTriggerPx
2963
2964
  stopLossLimitPrice = self.safe_value_n(stopLoss, ['price', 'stopLossPrice', 'slOrdPx'])
2964
2965
  stopLossOrderType = self.safe_string(stopLoss, 'type')
2965
2966
  if stopLossOrderType is not None:
@@ -3025,6 +3026,12 @@ class okx(Exchange, ImplicitAPI):
3025
3026
  # tpOrdKind is 'condition' which is the default
3026
3027
  if twoWayCondition:
3027
3028
  request['ordType'] = 'oco'
3029
+ if side == 'sell':
3030
+ request = self.omit(request, 'tgtCcy')
3031
+ if self.safe_string(request, 'tdMode') == 'cash':
3032
+ # for some reason tdMode = cash throws
3033
+ # {"code":"1","data":[{"algoClOrdId":"","algoId":"","clOrdId":"","sCode":"51000","sMsg":"Parameter tdMode error ","tag":""}],"msg":""}
3034
+ request['tdMode'] = marginMode
3028
3035
  if takeProfitPrice is not None:
3029
3036
  request['tpTriggerPx'] = self.price_to_precision(symbol, takeProfitPrice)
3030
3037
  tpOrdPxReq = '-1'
@@ -2215,11 +2215,21 @@ class wavesexchange(Exchange, ImplicitAPI):
2215
2215
  order1 = self.safe_value(data, 'order1')
2216
2216
  order2 = self.safe_value(data, 'order2')
2217
2217
  order = None
2218
- # order2 arrived after order1
2218
+ # at first, detect if response is from `fetch_my_trades`
2219
2219
  if self.safe_string(order1, 'senderPublicKey') == self.apiKey:
2220
2220
  order = order1
2221
- else:
2221
+ elif self.safe_string(order2, 'senderPublicKey') == self.apiKey:
2222
2222
  order = order2
2223
+ else:
2224
+ # response is from `fetch_trades`, so find only taker order
2225
+ date1 = self.safe_string(order1, 'timestamp')
2226
+ date2 = self.safe_string(order2, 'timestamp')
2227
+ ts1 = self.parse8601(date1)
2228
+ ts2 = self.parse8601(date2)
2229
+ if ts1 > ts2:
2230
+ order = order1
2231
+ else:
2232
+ order = order2
2223
2233
  symbol = None
2224
2234
  assetPair = self.safe_value(order, 'assetPair')
2225
2235
  if assetPair is not None: