ccxt 4.2.86__py2.py3-none-any.whl → 4.2.88__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.

Potentially problematic release.


This version of ccxt might be problematic. Click here for more details.

Files changed (82) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/ascendex.py +16 -6
  3. ccxt/async_support/__init__.py +1 -1
  4. ccxt/async_support/ascendex.py +16 -6
  5. ccxt/async_support/base/exchange.py +1 -1
  6. ccxt/async_support/binance.py +28 -11
  7. ccxt/async_support/bingx.py +39 -3
  8. ccxt/async_support/bitfinex.py +2 -0
  9. ccxt/async_support/bitfinex2.py +18 -4
  10. ccxt/async_support/bitflyer.py +18 -0
  11. ccxt/async_support/bitget.py +37 -22
  12. ccxt/async_support/bitopro.py +2 -0
  13. ccxt/async_support/bitrue.py +16 -8
  14. ccxt/async_support/bitvavo.py +2 -0
  15. ccxt/async_support/btcmarkets.py +1 -1
  16. ccxt/async_support/btcturk.py +2 -1
  17. ccxt/async_support/coinex.py +182 -58
  18. ccxt/async_support/cryptocom.py +1 -1
  19. ccxt/async_support/currencycom.py +1 -1
  20. ccxt/async_support/delta.py +8 -6
  21. ccxt/async_support/digifinex.py +9 -7
  22. ccxt/async_support/exmo.py +15 -15
  23. ccxt/async_support/gate.py +23 -20
  24. ccxt/async_support/hitbtc.py +31 -7
  25. ccxt/async_support/htx.py +2 -2
  26. ccxt/async_support/huobijp.py +1 -1
  27. ccxt/async_support/hyperliquid.py +242 -16
  28. ccxt/async_support/idex.py +1 -1
  29. ccxt/async_support/krakenfutures.py +4 -5
  30. ccxt/async_support/kucoin.py +7 -4
  31. ccxt/async_support/kucoinfutures.py +2 -2
  32. ccxt/async_support/lbank.py +2 -0
  33. ccxt/async_support/mexc.py +4 -4
  34. ccxt/async_support/oceanex.py +1 -1
  35. ccxt/async_support/okx.py +29 -15
  36. ccxt/async_support/phemex.py +6 -4
  37. ccxt/async_support/wazirx.py +1 -1
  38. ccxt/async_support/zonda.py +2 -0
  39. ccxt/base/exchange.py +22 -3
  40. ccxt/base/types.py +12 -0
  41. ccxt/binance.py +28 -11
  42. ccxt/bingx.py +39 -3
  43. ccxt/bitfinex.py +2 -0
  44. ccxt/bitfinex2.py +18 -4
  45. ccxt/bitflyer.py +18 -0
  46. ccxt/bitget.py +37 -22
  47. ccxt/bitopro.py +2 -0
  48. ccxt/bitrue.py +16 -8
  49. ccxt/bitvavo.py +2 -0
  50. ccxt/btcmarkets.py +1 -1
  51. ccxt/btcturk.py +2 -1
  52. ccxt/coinex.py +182 -58
  53. ccxt/cryptocom.py +1 -1
  54. ccxt/currencycom.py +1 -1
  55. ccxt/delta.py +8 -6
  56. ccxt/digifinex.py +9 -7
  57. ccxt/exmo.py +15 -15
  58. ccxt/gate.py +23 -20
  59. ccxt/hitbtc.py +31 -7
  60. ccxt/htx.py +2 -2
  61. ccxt/huobijp.py +1 -1
  62. ccxt/hyperliquid.py +241 -16
  63. ccxt/idex.py +1 -1
  64. ccxt/krakenfutures.py +4 -5
  65. ccxt/kucoin.py +7 -4
  66. ccxt/kucoinfutures.py +2 -2
  67. ccxt/lbank.py +2 -0
  68. ccxt/mexc.py +4 -4
  69. ccxt/oceanex.py +1 -1
  70. ccxt/okx.py +29 -15
  71. ccxt/phemex.py +6 -4
  72. ccxt/pro/__init__.py +1 -1
  73. ccxt/pro/kucoin.py +10 -6
  74. ccxt/test/base/test_last_price.py +0 -1
  75. ccxt/test/base/test_shared_methods.py +1 -2
  76. ccxt/test/base/test_status.py +1 -1
  77. ccxt/wazirx.py +1 -1
  78. ccxt/zonda.py +2 -0
  79. {ccxt-4.2.86.dist-info → ccxt-4.2.88.dist-info}/METADATA +5 -6
  80. {ccxt-4.2.86.dist-info → ccxt-4.2.88.dist-info}/RECORD +82 -82
  81. {ccxt-4.2.86.dist-info → ccxt-4.2.88.dist-info}/WHEEL +0 -0
  82. {ccxt-4.2.86.dist-info → ccxt-4.2.88.dist-info}/top_level.txt +0 -0
ccxt/gate.py CHANGED
@@ -6,7 +6,7 @@
6
6
  from ccxt.base.exchange import Exchange
7
7
  from ccxt.abstract.gate import ImplicitAPI
8
8
  import hashlib
9
- from ccxt.base.types import Balances, Currency, FundingHistory, Greeks, Int, Leverage, Leverages, Market, MarketInterface, Num, Option, OptionChain, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction, TransferEntry
9
+ from ccxt.base.types import Balances, Currency, FundingHistory, Greeks, Int, Leverage, Leverages, MarginModification, Market, MarketInterface, Num, Option, OptionChain, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction, TransferEntry
10
10
  from typing import List
11
11
  from ccxt.base.errors import ExchangeError
12
12
  from ccxt.base.errors import PermissionDenied
@@ -1823,7 +1823,7 @@ class gate(Exchange, ImplicitAPI):
1823
1823
  self.load_markets()
1824
1824
  currency = self.currency(code)
1825
1825
  request = {
1826
- 'currency': currency['id'],
1826
+ 'currency': currency['id'], # todo: currencies have network-junctions
1827
1827
  }
1828
1828
  response = self.privateWalletGetDepositAddress(self.extend(request, params))
1829
1829
  addresses = self.safe_value(response, 'multichain_addresses')
@@ -1870,7 +1870,7 @@ class gate(Exchange, ImplicitAPI):
1870
1870
  rawNetwork = self.safe_string_upper(params, 'network')
1871
1871
  params = self.omit(params, 'network')
1872
1872
  request = {
1873
- 'currency': currency['id'],
1873
+ 'currency': currency['id'], # todo: currencies have network-junctions
1874
1874
  }
1875
1875
  response = self.privateWalletGetDepositAddress(self.extend(request, params))
1876
1876
  #
@@ -3345,7 +3345,7 @@ class gate(Exchange, ImplicitAPI):
3345
3345
  currency = None
3346
3346
  if code is not None:
3347
3347
  currency = self.currency(code)
3348
- request['currency'] = currency['id']
3348
+ request['currency'] = currency['id'] # todo: currencies have network-junctions
3349
3349
  if limit is not None:
3350
3350
  request['limit'] = limit
3351
3351
  if since is not None:
@@ -3377,7 +3377,7 @@ class gate(Exchange, ImplicitAPI):
3377
3377
  currency = None
3378
3378
  if code is not None:
3379
3379
  currency = self.currency(code)
3380
- request['currency'] = currency['id']
3380
+ request['currency'] = currency['id'] # todo: currencies have network-junctions
3381
3381
  if limit is not None:
3382
3382
  request['limit'] = limit
3383
3383
  if since is not None:
@@ -3404,7 +3404,7 @@ class gate(Exchange, ImplicitAPI):
3404
3404
  self.load_markets()
3405
3405
  currency = self.currency(code)
3406
3406
  request = {
3407
- 'currency': currency['id'],
3407
+ 'currency': currency['id'], # todo: currencies have network-junctions
3408
3408
  'address': address,
3409
3409
  'amount': self.currency_to_precision(code, amount),
3410
3410
  }
@@ -3417,7 +3417,7 @@ class gate(Exchange, ImplicitAPI):
3417
3417
  request['chain'] = network
3418
3418
  params = self.omit(params, 'network')
3419
3419
  else:
3420
- request['chain'] = currency['id']
3420
+ request['chain'] = currency['id'] # todo: currencies have network-junctions
3421
3421
  response = self.privateWithdrawalsPostWithdrawals(self.extend(request, params))
3422
3422
  #
3423
3423
  # {
@@ -4761,7 +4761,7 @@ class gate(Exchange, ImplicitAPI):
4761
4761
  toId = self.convert_type_to_account(toAccount)
4762
4762
  truncated = self.currency_to_precision(code, amount)
4763
4763
  request = {
4764
- 'currency': currency['id'],
4764
+ 'currency': currency['id'], # todo: currencies have network-junctions
4765
4765
  'amount': truncated,
4766
4766
  }
4767
4767
  if not (fromId in self.options['accountsByType']):
@@ -4782,7 +4782,7 @@ class gate(Exchange, ImplicitAPI):
4782
4782
  request['currency_pair'] = market['id']
4783
4783
  params = self.omit(params, 'symbol')
4784
4784
  if (toId == 'futures') or (toId == 'delivery') or (fromId == 'futures') or (fromId == 'delivery'):
4785
- request['settle'] = currency['id']
4785
+ request['settle'] = currency['id'] # todo: currencies have network-junctions
4786
4786
  response = self.privateWalletPostTransfers(self.extend(request, params))
4787
4787
  #
4788
4788
  # according to the docs(however actual response seems to be an empty string '')
@@ -5395,7 +5395,7 @@ class gate(Exchange, ImplicitAPI):
5395
5395
  self.load_markets()
5396
5396
  currency = self.currency(code)
5397
5397
  request = {
5398
- 'currency': currency['id'].upper(),
5398
+ 'currency': currency['id'].upper(), # todo: currencies have network-junctions
5399
5399
  'amount': self.currency_to_precision(code, amount),
5400
5400
  }
5401
5401
  market = self.market(symbol)
@@ -5422,7 +5422,7 @@ class gate(Exchange, ImplicitAPI):
5422
5422
  self.load_markets()
5423
5423
  currency = self.currency(code)
5424
5424
  request = {
5425
- 'currency': currency['id'].upper(),
5425
+ 'currency': currency['id'].upper(), # todo: currencies have network-junctions
5426
5426
  'amount': self.currency_to_precision(code, amount),
5427
5427
  }
5428
5428
  response = self.privateMarginPostCrossRepayments(self.extend(request, params))
@@ -5459,7 +5459,7 @@ class gate(Exchange, ImplicitAPI):
5459
5459
  self.load_markets()
5460
5460
  currency = self.currency(code)
5461
5461
  request = {
5462
- 'currency': currency['id'].upper(),
5462
+ 'currency': currency['id'].upper(), # todo: currencies have network-junctions
5463
5463
  'amount': self.currency_to_precision(code, amount),
5464
5464
  }
5465
5465
  response = None
@@ -5502,7 +5502,7 @@ class gate(Exchange, ImplicitAPI):
5502
5502
  self.load_markets()
5503
5503
  currency = self.currency(code)
5504
5504
  request = {
5505
- 'currency': currency['id'].upper(),
5505
+ 'currency': currency['id'].upper(), # todo: currencies have network-junctions
5506
5506
  'amount': self.currency_to_precision(code, amount),
5507
5507
  }
5508
5508
  response = self.privateMarginPostCrossLoans(self.extend(request, params))
@@ -5650,7 +5650,7 @@ class gate(Exchange, ImplicitAPI):
5650
5650
  raise NotSupported(self.id + ' modifyMarginHelper() not support self market type')
5651
5651
  return self.parse_margin_modification(response, market)
5652
5652
 
5653
- def parse_margin_modification(self, data, market: Market = None):
5653
+ def parse_margin_modification(self, data, market: Market = None) -> MarginModification:
5654
5654
  #
5655
5655
  # {
5656
5656
  # "value": "11.9257",
@@ -5683,14 +5683,17 @@ class gate(Exchange, ImplicitAPI):
5683
5683
  total = self.safe_number(data, 'margin')
5684
5684
  return {
5685
5685
  'info': data,
5686
- 'amount': None,
5687
- 'code': self.safe_value(market, 'quote'),
5688
5686
  'symbol': market['symbol'],
5687
+ 'type': None,
5688
+ 'amount': None,
5689
5689
  'total': total,
5690
+ 'code': self.safe_value(market, 'quote'),
5690
5691
  'status': 'ok',
5692
+ 'timestamp': None,
5693
+ 'datetime': None,
5691
5694
  }
5692
5695
 
5693
- def reduce_margin(self, symbol: str, amount, params={}):
5696
+ def reduce_margin(self, symbol: str, amount, params={}) -> MarginModification:
5694
5697
  """
5695
5698
  remove margin from a position
5696
5699
  :see: https://www.gate.io/docs/developers/apiv4/en/#update-position-margin
@@ -5702,7 +5705,7 @@ class gate(Exchange, ImplicitAPI):
5702
5705
  """
5703
5706
  return self.modify_margin_helper(symbol, -amount, params)
5704
5707
 
5705
- def add_margin(self, symbol: str, amount, params={}):
5708
+ def add_margin(self, symbol: str, amount, params={}) -> MarginModification:
5706
5709
  """
5707
5710
  add margin
5708
5711
  :see: https://www.gate.io/docs/developers/apiv4/en/#update-position-margin
@@ -5992,7 +5995,7 @@ class gate(Exchange, ImplicitAPI):
5992
5995
  if (type == 'spot') or (type == 'margin'):
5993
5996
  if code is not None:
5994
5997
  currency = self.currency(code)
5995
- request['currency'] = currency['id']
5998
+ request['currency'] = currency['id'] # todo: currencies have network-junctions
5996
5999
  if (type == 'swap') or (type == 'future'):
5997
6000
  defaultSettle = 'usdt' if (type == 'swap') else 'btc'
5998
6001
  settle = self.safe_string_lower(params, 'settle', defaultSettle)
@@ -6750,7 +6753,7 @@ class gate(Exchange, ImplicitAPI):
6750
6753
  self.load_markets()
6751
6754
  currency = self.currency(code)
6752
6755
  request = {
6753
- 'underlying': currency['code'] + '_USDT',
6756
+ 'underlying': currency['code'] + '_USDT', # todo: currency['id'].upper() & network junctions
6754
6757
  }
6755
6758
  response = self.publicOptionsGetContracts(self.extend(request, params))
6756
6759
  #
ccxt/hitbtc.py CHANGED
@@ -6,7 +6,7 @@
6
6
  from ccxt.base.exchange import Exchange
7
7
  from ccxt.abstract.hitbtc import ImplicitAPI
8
8
  import hashlib
9
- from ccxt.base.types import Balances, Currency, Int, Leverage, MarginMode, MarginModes, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction, TransferEntry
9
+ from ccxt.base.types import Balances, Currency, Int, Leverage, MarginMode, MarginModes, MarginModification, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction, TransferEntry
10
10
  from typing import List
11
11
  from ccxt.base.errors import ExchangeError
12
12
  from ccxt.base.errors import PermissionDenied
@@ -1658,7 +1658,7 @@ class hitbtc(Exchange, ImplicitAPI):
1658
1658
  request['from'] = self.iso8601(since)
1659
1659
  request, params = self.handle_until_option('till', request, params)
1660
1660
  if limit is not None:
1661
- request['limit'] = limit
1661
+ request['limit'] = min(limit, 1000)
1662
1662
  price = self.safe_string(params, 'price')
1663
1663
  params = self.omit(params, 'price')
1664
1664
  response = None
@@ -2999,7 +2999,7 @@ class hitbtc(Exchange, ImplicitAPI):
2999
2999
  'previousFundingDatetime': None,
3000
3000
  }
3001
3001
 
3002
- def modify_margin_helper(self, symbol: str, amount, type, params={}):
3002
+ def modify_margin_helper(self, symbol: str, amount, type, params={}) -> MarginModification:
3003
3003
  self.load_markets()
3004
3004
  market = self.market(symbol)
3005
3005
  leverage = self.safe_string(params, 'leverage')
@@ -3052,19 +3052,43 @@ class hitbtc(Exchange, ImplicitAPI):
3052
3052
  'type': type,
3053
3053
  })
3054
3054
 
3055
- def parse_margin_modification(self, data, market: Market = None):
3055
+ def parse_margin_modification(self, data, market: Market = None) -> MarginModification:
3056
+ #
3057
+ # addMargin/reduceMargin
3058
+ #
3059
+ # {
3060
+ # "symbol": "BTCUSDT_PERP",
3061
+ # "type": "isolated",
3062
+ # "leverage": "8.00",
3063
+ # "created_at": "2022-03-30T23:34:27.161Z",
3064
+ # "updated_at": "2022-03-30T23:34:27.161Z",
3065
+ # "currencies": [
3066
+ # {
3067
+ # "code": "USDT",
3068
+ # "margin_balance": "7.000000000000",
3069
+ # "reserved_orders": "0",
3070
+ # "reserved_positions": "0"
3071
+ # }
3072
+ # ],
3073
+ # "positions": null
3074
+ # }
3075
+ #
3056
3076
  currencies = self.safe_value(data, 'currencies', [])
3057
3077
  currencyInfo = self.safe_value(currencies, 0)
3078
+ datetime = self.safe_string(data, 'updated_at')
3058
3079
  return {
3059
3080
  'info': data,
3081
+ 'symbol': market['symbol'],
3060
3082
  'type': None,
3061
3083
  'amount': None,
3084
+ 'total': None,
3062
3085
  'code': self.safe_string(currencyInfo, 'code'),
3063
- 'symbol': market['symbol'],
3064
3086
  'status': None,
3087
+ 'timestamp': self.parse8601(datetime),
3088
+ 'datetime': datetime,
3065
3089
  }
3066
3090
 
3067
- def reduce_margin(self, symbol: str, amount, params={}):
3091
+ def reduce_margin(self, symbol: str, amount, params={}) -> MarginModification:
3068
3092
  """
3069
3093
  remove margin from a position
3070
3094
  :see: https://api.hitbtc.com/#create-update-margin-account-2
@@ -3080,7 +3104,7 @@ class hitbtc(Exchange, ImplicitAPI):
3080
3104
  raise BadRequest(self.id + ' reduceMargin() on hitbtc requires the amount to be 0 and that will remove the entire margin amount')
3081
3105
  return self.modify_margin_helper(symbol, amount, 'reduce', params)
3082
3106
 
3083
- def add_margin(self, symbol: str, amount, params={}):
3107
+ def add_margin(self, symbol: str, amount, params={}) -> MarginModification:
3084
3108
  """
3085
3109
  add margin
3086
3110
  :see: https://api.hitbtc.com/#create-update-margin-account-2
ccxt/htx.py CHANGED
@@ -2833,7 +2833,7 @@ class htx(Exchange, ImplicitAPI):
2833
2833
  untilSeconds = self.parse_to_int(until / 1000) if (until is not None) else None
2834
2834
  if market['contract']:
2835
2835
  if limit is not None:
2836
- request['size'] = limit # when using limit: from & to are ignored
2836
+ request['size'] = min(limit, 2000) # when using limit: from & to are ignored
2837
2837
  # https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-get-kline-data
2838
2838
  else:
2839
2839
  limit = 2000 # only used for from/to calculation
@@ -2897,7 +2897,7 @@ class htx(Exchange, ImplicitAPI):
2897
2897
  useHistorical, params = self.handle_option_and_params(params, 'fetchOHLCV', 'useHistoricalEndpointForSpot', True)
2898
2898
  if not useHistorical:
2899
2899
  if limit is not None:
2900
- request['size'] = min(2000, limit) # max 2000
2900
+ request['size'] = min(limit, 2000) # max 2000
2901
2901
  response = self.spotPublicGetMarketHistoryKline(self.extend(request, params))
2902
2902
  else:
2903
2903
  # "from & to" only available for the self endpoint
ccxt/huobijp.py CHANGED
@@ -927,7 +927,7 @@ class huobijp(Exchange, ImplicitAPI):
927
927
  'period': self.safe_string(self.timeframes, timeframe, timeframe),
928
928
  }
929
929
  if limit is not None:
930
- request['size'] = limit
930
+ request['size'] = min(limit, 2000)
931
931
  response = self.marketGetHistoryKline(self.extend(request, params))
932
932
  #
933
933
  # {
ccxt/hyperliquid.py CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  from ccxt.base.exchange import Exchange
7
7
  from ccxt.abstract.hyperliquid import ImplicitAPI
8
- from ccxt.base.types import Balances, Int, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Trade, TransferEntry
8
+ from ccxt.base.types import Balances, Int, MarginModification, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Trade, TransferEntry
9
9
  from typing import List
10
10
  from ccxt.base.errors import ExchangeError
11
11
  from ccxt.base.errors import ArgumentsRequired
@@ -32,7 +32,7 @@ class hyperliquid(Exchange, ImplicitAPI):
32
32
  'pro': True,
33
33
  'has': {
34
34
  'CORS': None,
35
- 'spot': False,
35
+ 'spot': True,
36
36
  'margin': False,
37
37
  'swap': True,
38
38
  'future': True,
@@ -165,6 +165,10 @@ class hyperliquid(Exchange, ImplicitAPI):
165
165
  'taker': self.parse_number('0.00035'),
166
166
  'maker': self.parse_number('0.0001'),
167
167
  },
168
+ 'spot': {
169
+ 'taker': self.parse_number('0.00035'),
170
+ 'maker': self.parse_number('0.0001'),
171
+ },
168
172
  },
169
173
  'requiredCredentials': {
170
174
  'apiKey': False,
@@ -192,6 +196,7 @@ class hyperliquid(Exchange, ImplicitAPI):
192
196
  'commonCurrencies': {
193
197
  },
194
198
  'options': {
199
+ 'defaultType': 'swap',
195
200
  'sandboxMode': False,
196
201
  'defaultSlippage': 0.05,
197
202
  'zeroAddress': '0x0000000000000000000000000000000000000000',
@@ -257,6 +262,22 @@ class hyperliquid(Exchange, ImplicitAPI):
257
262
  :param dict [params]: extra parameters specific to the exchange API endpoint
258
263
  :returns dict[]: an array of objects representing market data
259
264
  """
265
+ rawPromises = [
266
+ self.fetch_swap_markets(params),
267
+ self.fetch_spot_markets(params),
268
+ ]
269
+ promises = rawPromises
270
+ swapMarkets = promises[0]
271
+ spotMarkets = promises[1]
272
+ return self.array_concat(swapMarkets, spotMarkets)
273
+
274
+ def fetch_swap_markets(self, params={}) -> List[Market]:
275
+ """
276
+ retrieves data on all swap markets for hyperliquid
277
+ :see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-asset-contexts-includes-mark-price-current-funding-open-interest-etc
278
+ :param dict [params]: extra parameters specific to the exchange API endpoint
279
+ :returns dict[]: an array of objects representing market data
280
+ """
260
281
  request = {
261
282
  'type': 'metaAndAssetCtxs',
262
283
  }
@@ -304,6 +325,129 @@ class hyperliquid(Exchange, ImplicitAPI):
304
325
  result.append(data)
305
326
  return self.parse_markets(result)
306
327
 
328
+ def fetch_spot_markets(self, params={}) -> List[Market]:
329
+ """
330
+ retrieves data on all spot markets for hyperliquid
331
+ :see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-asset-contexts-includes-mark-price-current-funding-open-interest-etc
332
+ :param dict [params]: extra parameters specific to the exchange API endpoint
333
+ :returns dict[]: an array of objects representing market data
334
+ """
335
+ request = {
336
+ 'type': 'spotMetaAndAssetCtxs',
337
+ }
338
+ response = self.publicPostInfo(self.extend(request, params))
339
+ #
340
+ # [
341
+ # {
342
+ # 'tokens': [
343
+ # {
344
+ # 'name': 'USDC',
345
+ # 'szDecimals': '8',
346
+ # 'weiDecimals': '8',
347
+ # },
348
+ # {
349
+ # 'name': 'PURR',
350
+ # 'szDecimals': '0',
351
+ # 'weiDecimals': '5',
352
+ # },
353
+ # ],
354
+ # 'universe': [
355
+ # {
356
+ # 'name': 'PURR/USDC',
357
+ # 'tokens': [
358
+ # 1,
359
+ # 0,
360
+ # ],
361
+ # },
362
+ # ],
363
+ # },
364
+ # [
365
+ # {
366
+ # 'dayNtlVlm': '264250385.14640012',
367
+ # 'markPx': '0.018314',
368
+ # 'midPx': '0.0182235',
369
+ # 'prevDayPx': '0.017427',
370
+ # },
371
+ # ],
372
+ # ]
373
+ #
374
+ first = self.safe_dict(response, 0, {})
375
+ meta = self.safe_list(first, 'universe', [])
376
+ tokens = self.safe_list(first, 'tokens', [])
377
+ markets = []
378
+ for i in range(0, len(meta)):
379
+ market = self.safe_dict(meta, i, {})
380
+ marketName = self.safe_string(market, 'name')
381
+ marketParts = marketName.split('/')
382
+ baseName = self.safe_string(marketParts, 0)
383
+ quoteId = self.safe_string(marketParts, 1)
384
+ base = self.safe_currency_code(baseName)
385
+ quote = self.safe_currency_code(quoteId)
386
+ symbol = base + '/' + quote
387
+ fees = self.safe_dict(self.fees, 'spot', {})
388
+ taker = self.safe_number(fees, 'taker')
389
+ maker = self.safe_number(fees, 'maker')
390
+ tokensPos = self.safe_list(market, 'tokens', [])
391
+ baseTokenPos = self.safe_integer(tokensPos, 0)
392
+ quoteTokenPos = self.safe_integer(tokensPos, 1)
393
+ baseTokenInfo = self.safe_dict(tokens, baseTokenPos, {})
394
+ quoteTokenInfo = self.safe_dict(tokens, quoteTokenPos, {})
395
+ baseDecimals = self.safe_string(baseTokenInfo, 'szDecimals')
396
+ quoteDecimals = self.safe_integer(quoteTokenInfo, 'szDecimals')
397
+ baseId = self.number_to_string(i + 10000)
398
+ markets.append(self.safe_market_structure({
399
+ 'id': baseId,
400
+ 'symbol': symbol,
401
+ 'base': base,
402
+ 'quote': quote,
403
+ 'settle': None,
404
+ 'baseId': baseId,
405
+ 'quoteId': quoteId,
406
+ 'settleId': None,
407
+ 'type': 'spot',
408
+ 'spot': True,
409
+ 'margin': None,
410
+ 'swap': False,
411
+ 'future': False,
412
+ 'option': False,
413
+ 'active': True,
414
+ 'contract': False,
415
+ 'linear': True,
416
+ 'inverse': False,
417
+ 'taker': taker,
418
+ 'maker': maker,
419
+ 'contractSize': None,
420
+ 'expiry': None,
421
+ 'expiryDatetime': None,
422
+ 'strike': None,
423
+ 'optionType': None,
424
+ 'precision': {
425
+ 'amount': self.parse_number(self.parse_precision(baseDecimals)), # decimal places
426
+ 'price': quoteDecimals, # significant digits
427
+ },
428
+ 'limits': {
429
+ 'leverage': {
430
+ 'min': None,
431
+ 'max': None,
432
+ },
433
+ 'amount': {
434
+ 'min': None,
435
+ 'max': None,
436
+ },
437
+ 'price': {
438
+ 'min': None,
439
+ 'max': None,
440
+ },
441
+ 'cost': {
442
+ 'min': None,
443
+ 'max': None,
444
+ },
445
+ },
446
+ 'created': None,
447
+ 'info': market,
448
+ }))
449
+ return markets
450
+
307
451
  def parse_market(self, market) -> Market:
308
452
  #
309
453
  # {
@@ -398,12 +542,17 @@ class hyperliquid(Exchange, ImplicitAPI):
398
542
  :see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-a-users-state
399
543
  :param dict [params]: extra parameters specific to the exchange API endpoint
400
544
  :param str [params.user]: user address, will default to self.walletAddress if not provided
545
+ :param str [params.type]: wallet type, ['spot', 'swap'], defaults to swap
401
546
  :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
402
547
  """
403
548
  userAddress = None
404
549
  userAddress, params = self.handle_public_address('fetchBalance', params)
550
+ type = None
551
+ type, params = self.handle_market_type_and_params('fetchBalance', None, params)
552
+ isSpot = (type == 'spot')
553
+ reqType = 'spotClearinghouseState' if (isSpot) else 'clearinghouseState'
405
554
  request = {
406
- 'type': 'clearinghouseState',
555
+ 'type': reqType,
407
556
  'user': userAddress,
408
557
  }
409
558
  response = self.publicPostInfo(self.extend(request, params))
@@ -426,7 +575,35 @@ class hyperliquid(Exchange, ImplicitAPI):
426
575
  # "time": "1704261007014",
427
576
  # "withdrawable": "100.0"
428
577
  # }
578
+ # spot
579
+ #
580
+ # {
581
+ # "balances":[
582
+ # {
583
+ # "coin":"USDC",
584
+ # "hold":"0.0",
585
+ # "total":"1481.844"
586
+ # },
587
+ # {
588
+ # "coin":"PURR",
589
+ # "hold":"0.0",
590
+ # "total":"999.65004"
591
+ # }
592
+ # }
429
593
  #
594
+ balances = self.safe_list(response, 'balances')
595
+ if balances is not None:
596
+ spotBalances = {'info': response}
597
+ for i in range(0, len(balances)):
598
+ balance = balances[i]
599
+ code = self.safe_currency_code(self.safe_string(balance, 'coin'))
600
+ account = self.account()
601
+ total = self.safe_string(balance, 'total')
602
+ free = self.safe_string(balance, 'hold')
603
+ account['total'] = total
604
+ account['free'] = free
605
+ spotBalances[code] = account
606
+ return self.safe_balance(spotBalances)
430
607
  data = self.safe_dict(response, 'marginSummary', {})
431
608
  result = {
432
609
  'info': response,
@@ -915,6 +1092,7 @@ class hyperliquid(Exchange, ImplicitAPI):
915
1092
  :param str symbol: unified symbol of the market the order was made in
916
1093
  :param dict [params]: extra parameters specific to the exchange API endpoint
917
1094
  :param str [params.clientOrderId]: client order id,(optional 128 bit hex string e.g. 0x1234567890abcdef1234567890abcdef)
1095
+ :param str [params.vaultAddress]: the vault address for order
918
1096
  :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
919
1097
  """
920
1098
  return self.cancel_orders([id], symbol, params)
@@ -928,6 +1106,7 @@ class hyperliquid(Exchange, ImplicitAPI):
928
1106
  :param str [symbol]: unified market symbol
929
1107
  :param dict [params]: extra parameters specific to the exchange API endpoint
930
1108
  :param string|str[] [params.clientOrderId]: client order ids,(optional 128 bit hex string e.g. 0x1234567890abcdef1234567890abcdef)
1109
+ :param str [params.vaultAddress]: the vault address
931
1110
  :returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
932
1111
  """
933
1112
  self.check_required_credentials()
@@ -1377,7 +1556,10 @@ class hyperliquid(Exchange, ImplicitAPI):
1377
1556
  coin = self.safe_string(entry, 'coin')
1378
1557
  marketId = None
1379
1558
  if coin is not None:
1380
- marketId = coin + '/USDC:USDC'
1559
+ if coin.find('/') > -1:
1560
+ marketId = coin
1561
+ else:
1562
+ marketId = coin + '/USDC:USDC'
1381
1563
  if self.safe_string(entry, 'id') is None:
1382
1564
  market = self.safe_market(marketId, None)
1383
1565
  else:
@@ -1772,7 +1954,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1772
1954
  #
1773
1955
  return response
1774
1956
 
1775
- def add_margin(self, symbol: str, amount, params={}):
1957
+ def add_margin(self, symbol: str, amount, params={}) -> MarginModification:
1776
1958
  """
1777
1959
  add margin
1778
1960
  :see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#update-isolated-margin
@@ -1783,7 +1965,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1783
1965
  """
1784
1966
  return self.modify_margin_helper(symbol, amount, 'add', params)
1785
1967
 
1786
- def reduce_margin(self, symbol: str, amount, params={}):
1968
+ def reduce_margin(self, symbol: str, amount, params={}) -> MarginModification:
1787
1969
  """
1788
1970
  :see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#update-isolated-margin
1789
1971
  remove margin from a position
@@ -1794,7 +1976,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1794
1976
  """
1795
1977
  return self.modify_margin_helper(symbol, amount, 'reduce', params)
1796
1978
 
1797
- def modify_margin_helper(self, symbol: str, amount, type, params={}):
1979
+ def modify_margin_helper(self, symbol: str, amount, type, params={}) -> MarginModification:
1798
1980
  self.load_markets()
1799
1981
  market = self.market(symbol)
1800
1982
  asset = self.parse_to_int(market['baseId'])
@@ -1828,10 +2010,27 @@ class hyperliquid(Exchange, ImplicitAPI):
1828
2010
  # 'status': 'ok'
1829
2011
  # }
1830
2012
  #
1831
- return response
1832
- # return self.extend(self.parse_margin_modification(response, market), {
1833
- # 'code': code,
1834
- # })
2013
+ return self.extend(self.parse_margin_modification(response, market), {
2014
+ 'code': self.safe_string(response, 'status'),
2015
+ })
2016
+
2017
+ def parse_margin_modification(self, data, market: Market = None) -> MarginModification:
2018
+ #
2019
+ # {
2020
+ # 'type': 'default'
2021
+ # }
2022
+ #
2023
+ return {
2024
+ 'info': data,
2025
+ 'symbol': self.safe_symbol(None, market),
2026
+ 'type': None,
2027
+ 'amount': None,
2028
+ 'total': None,
2029
+ 'code': self.safe_string(market, 'settle'),
2030
+ 'status': None,
2031
+ 'timestamp': None,
2032
+ 'datetime': None,
2033
+ }
1835
2034
 
1836
2035
  def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
1837
2036
  """
@@ -1839,23 +2038,49 @@ class hyperliquid(Exchange, ImplicitAPI):
1839
2038
  :see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#l1-usdc-transfer
1840
2039
  :param str code: unified currency code
1841
2040
  :param float amount: amount to transfer
1842
- :param str fromAccount: account to transfer from
1843
- :param str toAccount: account to transfer to
2041
+ :param str fromAccount: account to transfer from *spot, swap*
2042
+ :param str toAccount: account to transfer to *swap, spot or address*
1844
2043
  :param dict [params]: extra parameters specific to the exchange API endpoint
2044
+ :param str [params.vaultAddress]: the vault address for order
1845
2045
  :returns dict: a `transfer structure <https://docs.ccxt.com/#/?id=transfer-structure>`
1846
2046
  """
1847
2047
  self.check_required_credentials()
1848
2048
  self.load_markets()
2049
+ isSandboxMode = self.safe_bool(self.options, 'sandboxMode')
2050
+ nonce = self.milliseconds()
2051
+ if self.in_array(fromAccount, ['spot', 'swap', 'perp']):
2052
+ # handle swap <> spot account transfer
2053
+ if not self.in_array(toAccount, ['spot', 'swap', 'perp']):
2054
+ raise NotSupported(self.id + 'transfer() only support spot <> swap transfer')
2055
+ vaultAddress = self.format_vault_address(self.safe_string(params, 'vaultAddress'))
2056
+ params = self.omit(params, 'vaultAddress')
2057
+ toPerp = (toAccount == 'perp') or (toAccount == 'swap')
2058
+ action = {
2059
+ 'type': 'spotUser',
2060
+ 'classTransfer': {
2061
+ 'usdc': amount,
2062
+ 'toPerp': toPerp,
2063
+ },
2064
+ }
2065
+ signature = self.sign_l1_action(action, nonce, vaultAddress)
2066
+ innerRequest = {
2067
+ 'action': self.extend(action, params),
2068
+ 'nonce': nonce,
2069
+ 'signature': signature,
2070
+ }
2071
+ if vaultAddress is not None:
2072
+ innerRequest['vaultAddress'] = vaultAddress
2073
+ transferResponse = self.privatePostExchange(innerRequest)
2074
+ return transferResponse
2075
+ # handle sub-account/different account transfer
1849
2076
  self.check_address(toAccount)
1850
2077
  if code is not None:
1851
2078
  code = code.upper()
1852
2079
  if code != 'USDC':
1853
2080
  raise NotSupported(self.id + 'withdraw() only support USDC')
1854
- isSandboxMode = self.safe_bool(self.options, 'sandboxMode')
1855
- nonce = self.milliseconds()
1856
2081
  payload = {
1857
2082
  'destination': toAccount,
1858
- 'amount': str(amount),
2083
+ 'amount': self.number_to_string(amount),
1859
2084
  'time': nonce,
1860
2085
  }
1861
2086
  sig = self.build_transfer_sig(payload)
ccxt/idex.py CHANGED
@@ -463,7 +463,7 @@ class idex(Exchange, ImplicitAPI):
463
463
  if since is not None:
464
464
  request['start'] = since
465
465
  if limit is not None:
466
- request['limit'] = limit
466
+ request['limit'] = min(limit, 1000)
467
467
  response = self.publicGetCandles(self.extend(request, params))
468
468
  if isinstance(response, list):
469
469
  # [