ccxt 4.2.85__py2.py3-none-any.whl → 4.2.87__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 (84) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/abstract/coinex.py +232 -123
  3. ccxt/ascendex.py +16 -6
  4. ccxt/async_support/__init__.py +1 -1
  5. ccxt/async_support/ascendex.py +16 -6
  6. ccxt/async_support/base/exchange.py +1 -1
  7. ccxt/async_support/binance.py +18 -5
  8. ccxt/async_support/bingx.py +72 -22
  9. ccxt/async_support/bitbank.py +19 -21
  10. ccxt/async_support/bitfinex.py +2 -0
  11. ccxt/async_support/bitfinex2.py +18 -4
  12. ccxt/async_support/bitflyer.py +18 -0
  13. ccxt/async_support/bitget.py +20 -6
  14. ccxt/async_support/bitopro.py +2 -0
  15. ccxt/async_support/bitrue.py +16 -8
  16. ccxt/async_support/bitvavo.py +2 -0
  17. ccxt/async_support/btcmarkets.py +1 -1
  18. ccxt/async_support/btcturk.py +2 -1
  19. ccxt/async_support/coinex.py +572 -306
  20. ccxt/async_support/currencycom.py +1 -1
  21. ccxt/async_support/delta.py +8 -6
  22. ccxt/async_support/digifinex.py +9 -7
  23. ccxt/async_support/exmo.py +15 -15
  24. ccxt/async_support/gate.py +9 -6
  25. ccxt/async_support/hitbtc.py +31 -7
  26. ccxt/async_support/htx.py +2 -2
  27. ccxt/async_support/huobijp.py +1 -1
  28. ccxt/async_support/hyperliquid.py +242 -16
  29. ccxt/async_support/idex.py +11 -11
  30. ccxt/async_support/krakenfutures.py +2 -4
  31. ccxt/async_support/kucoinfutures.py +2 -2
  32. ccxt/async_support/lbank.py +2 -0
  33. ccxt/async_support/mexc.py +3 -3
  34. ccxt/async_support/oceanex.py +1 -1
  35. ccxt/async_support/okcoin.py +2 -1
  36. ccxt/async_support/okx.py +29 -15
  37. ccxt/async_support/phemex.py +6 -4
  38. ccxt/async_support/wazirx.py +1 -1
  39. ccxt/async_support/zonda.py +2 -0
  40. ccxt/base/exchange.py +1 -1
  41. ccxt/base/types.py +12 -0
  42. ccxt/binance.py +18 -5
  43. ccxt/bingx.py +72 -22
  44. ccxt/bitbank.py +19 -21
  45. ccxt/bitfinex.py +2 -0
  46. ccxt/bitfinex2.py +18 -4
  47. ccxt/bitflyer.py +18 -0
  48. ccxt/bitget.py +20 -6
  49. ccxt/bitopro.py +2 -0
  50. ccxt/bitrue.py +16 -8
  51. ccxt/bitvavo.py +2 -0
  52. ccxt/btcmarkets.py +1 -1
  53. ccxt/btcturk.py +2 -1
  54. ccxt/coinex.py +572 -306
  55. ccxt/currencycom.py +1 -1
  56. ccxt/delta.py +8 -6
  57. ccxt/digifinex.py +9 -7
  58. ccxt/exmo.py +15 -15
  59. ccxt/gate.py +9 -6
  60. ccxt/hitbtc.py +31 -7
  61. ccxt/htx.py +2 -2
  62. ccxt/huobijp.py +1 -1
  63. ccxt/hyperliquid.py +241 -16
  64. ccxt/idex.py +11 -11
  65. ccxt/krakenfutures.py +2 -4
  66. ccxt/kucoinfutures.py +2 -2
  67. ccxt/lbank.py +2 -0
  68. ccxt/mexc.py +3 -3
  69. ccxt/oceanex.py +1 -1
  70. ccxt/okcoin.py +2 -1
  71. ccxt/okx.py +29 -15
  72. ccxt/phemex.py +6 -4
  73. ccxt/pro/__init__.py +1 -1
  74. ccxt/pro/bitget.py +1 -0
  75. ccxt/pro/kucoin.py +10 -6
  76. ccxt/test/base/test_last_price.py +0 -1
  77. ccxt/test/base/test_shared_methods.py +1 -2
  78. ccxt/test/base/test_status.py +1 -1
  79. ccxt/wazirx.py +1 -1
  80. ccxt/zonda.py +2 -0
  81. {ccxt-4.2.85.dist-info → ccxt-4.2.87.dist-info}/METADATA +6 -6
  82. {ccxt-4.2.85.dist-info → ccxt-4.2.87.dist-info}/RECORD +84 -84
  83. {ccxt-4.2.85.dist-info → ccxt-4.2.87.dist-info}/WHEEL +0 -0
  84. {ccxt-4.2.85.dist-info → ccxt-4.2.87.dist-info}/top_level.txt +0 -0
@@ -5,7 +5,8 @@
5
5
 
6
6
  from ccxt.async_support.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
+ import asyncio
9
+ from ccxt.base.types import Balances, Int, MarginModification, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Trade, TransferEntry
9
10
  from typing import List
10
11
  from ccxt.base.errors import ExchangeError
11
12
  from ccxt.base.errors import ArgumentsRequired
@@ -32,7 +33,7 @@ class hyperliquid(Exchange, ImplicitAPI):
32
33
  'pro': True,
33
34
  'has': {
34
35
  'CORS': None,
35
- 'spot': False,
36
+ 'spot': True,
36
37
  'margin': False,
37
38
  'swap': True,
38
39
  'future': True,
@@ -165,6 +166,10 @@ class hyperliquid(Exchange, ImplicitAPI):
165
166
  'taker': self.parse_number('0.00035'),
166
167
  'maker': self.parse_number('0.0001'),
167
168
  },
169
+ 'spot': {
170
+ 'taker': self.parse_number('0.00035'),
171
+ 'maker': self.parse_number('0.0001'),
172
+ },
168
173
  },
169
174
  'requiredCredentials': {
170
175
  'apiKey': False,
@@ -192,6 +197,7 @@ class hyperliquid(Exchange, ImplicitAPI):
192
197
  'commonCurrencies': {
193
198
  },
194
199
  'options': {
200
+ 'defaultType': 'swap',
195
201
  'sandboxMode': False,
196
202
  'defaultSlippage': 0.05,
197
203
  'zeroAddress': '0x0000000000000000000000000000000000000000',
@@ -257,6 +263,22 @@ class hyperliquid(Exchange, ImplicitAPI):
257
263
  :param dict [params]: extra parameters specific to the exchange API endpoint
258
264
  :returns dict[]: an array of objects representing market data
259
265
  """
266
+ rawPromises = [
267
+ self.fetch_swap_markets(params),
268
+ self.fetch_spot_markets(params),
269
+ ]
270
+ promises = await asyncio.gather(*rawPromises)
271
+ swapMarkets = promises[0]
272
+ spotMarkets = promises[1]
273
+ return self.array_concat(swapMarkets, spotMarkets)
274
+
275
+ async def fetch_swap_markets(self, params={}) -> List[Market]:
276
+ """
277
+ retrieves data on all swap markets for hyperliquid
278
+ :see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-asset-contexts-includes-mark-price-current-funding-open-interest-etc
279
+ :param dict [params]: extra parameters specific to the exchange API endpoint
280
+ :returns dict[]: an array of objects representing market data
281
+ """
260
282
  request = {
261
283
  'type': 'metaAndAssetCtxs',
262
284
  }
@@ -304,6 +326,129 @@ class hyperliquid(Exchange, ImplicitAPI):
304
326
  result.append(data)
305
327
  return self.parse_markets(result)
306
328
 
329
+ async def fetch_spot_markets(self, params={}) -> List[Market]:
330
+ """
331
+ retrieves data on all spot markets for hyperliquid
332
+ :see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-asset-contexts-includes-mark-price-current-funding-open-interest-etc
333
+ :param dict [params]: extra parameters specific to the exchange API endpoint
334
+ :returns dict[]: an array of objects representing market data
335
+ """
336
+ request = {
337
+ 'type': 'spotMetaAndAssetCtxs',
338
+ }
339
+ response = await self.publicPostInfo(self.extend(request, params))
340
+ #
341
+ # [
342
+ # {
343
+ # 'tokens': [
344
+ # {
345
+ # 'name': 'USDC',
346
+ # 'szDecimals': '8',
347
+ # 'weiDecimals': '8',
348
+ # },
349
+ # {
350
+ # 'name': 'PURR',
351
+ # 'szDecimals': '0',
352
+ # 'weiDecimals': '5',
353
+ # },
354
+ # ],
355
+ # 'universe': [
356
+ # {
357
+ # 'name': 'PURR/USDC',
358
+ # 'tokens': [
359
+ # 1,
360
+ # 0,
361
+ # ],
362
+ # },
363
+ # ],
364
+ # },
365
+ # [
366
+ # {
367
+ # 'dayNtlVlm': '264250385.14640012',
368
+ # 'markPx': '0.018314',
369
+ # 'midPx': '0.0182235',
370
+ # 'prevDayPx': '0.017427',
371
+ # },
372
+ # ],
373
+ # ]
374
+ #
375
+ first = self.safe_dict(response, 0, {})
376
+ meta = self.safe_list(first, 'universe', [])
377
+ tokens = self.safe_list(first, 'tokens', [])
378
+ markets = []
379
+ for i in range(0, len(meta)):
380
+ market = self.safe_dict(meta, i, {})
381
+ marketName = self.safe_string(market, 'name')
382
+ marketParts = marketName.split('/')
383
+ baseName = self.safe_string(marketParts, 0)
384
+ quoteId = self.safe_string(marketParts, 1)
385
+ base = self.safe_currency_code(baseName)
386
+ quote = self.safe_currency_code(quoteId)
387
+ symbol = base + '/' + quote
388
+ fees = self.safe_dict(self.fees, 'spot', {})
389
+ taker = self.safe_number(fees, 'taker')
390
+ maker = self.safe_number(fees, 'maker')
391
+ tokensPos = self.safe_list(market, 'tokens', [])
392
+ baseTokenPos = self.safe_integer(tokensPos, 0)
393
+ quoteTokenPos = self.safe_integer(tokensPos, 1)
394
+ baseTokenInfo = self.safe_dict(tokens, baseTokenPos, {})
395
+ quoteTokenInfo = self.safe_dict(tokens, quoteTokenPos, {})
396
+ baseDecimals = self.safe_string(baseTokenInfo, 'szDecimals')
397
+ quoteDecimals = self.safe_integer(quoteTokenInfo, 'szDecimals')
398
+ baseId = self.number_to_string(i + 10000)
399
+ markets.append(self.safe_market_structure({
400
+ 'id': baseId,
401
+ 'symbol': symbol,
402
+ 'base': base,
403
+ 'quote': quote,
404
+ 'settle': None,
405
+ 'baseId': baseId,
406
+ 'quoteId': quoteId,
407
+ 'settleId': None,
408
+ 'type': 'spot',
409
+ 'spot': True,
410
+ 'margin': None,
411
+ 'swap': False,
412
+ 'future': False,
413
+ 'option': False,
414
+ 'active': True,
415
+ 'contract': False,
416
+ 'linear': True,
417
+ 'inverse': False,
418
+ 'taker': taker,
419
+ 'maker': maker,
420
+ 'contractSize': None,
421
+ 'expiry': None,
422
+ 'expiryDatetime': None,
423
+ 'strike': None,
424
+ 'optionType': None,
425
+ 'precision': {
426
+ 'amount': self.parse_number(self.parse_precision(baseDecimals)), # decimal places
427
+ 'price': quoteDecimals, # significant digits
428
+ },
429
+ 'limits': {
430
+ 'leverage': {
431
+ 'min': None,
432
+ 'max': None,
433
+ },
434
+ 'amount': {
435
+ 'min': None,
436
+ 'max': None,
437
+ },
438
+ 'price': {
439
+ 'min': None,
440
+ 'max': None,
441
+ },
442
+ 'cost': {
443
+ 'min': None,
444
+ 'max': None,
445
+ },
446
+ },
447
+ 'created': None,
448
+ 'info': market,
449
+ }))
450
+ return markets
451
+
307
452
  def parse_market(self, market) -> Market:
308
453
  #
309
454
  # {
@@ -398,12 +543,17 @@ class hyperliquid(Exchange, ImplicitAPI):
398
543
  :see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-a-users-state
399
544
  :param dict [params]: extra parameters specific to the exchange API endpoint
400
545
  :param str [params.user]: user address, will default to self.walletAddress if not provided
546
+ :param str [params.type]: wallet type, ['spot', 'swap'], defaults to swap
401
547
  :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
402
548
  """
403
549
  userAddress = None
404
550
  userAddress, params = self.handle_public_address('fetchBalance', params)
551
+ type = None
552
+ type, params = self.handle_market_type_and_params('fetchBalance', None, params)
553
+ isSpot = (type == 'spot')
554
+ reqType = 'spotClearinghouseState' if (isSpot) else 'clearinghouseState'
405
555
  request = {
406
- 'type': 'clearinghouseState',
556
+ 'type': reqType,
407
557
  'user': userAddress,
408
558
  }
409
559
  response = await self.publicPostInfo(self.extend(request, params))
@@ -426,7 +576,35 @@ class hyperliquid(Exchange, ImplicitAPI):
426
576
  # "time": "1704261007014",
427
577
  # "withdrawable": "100.0"
428
578
  # }
579
+ # spot
580
+ #
581
+ # {
582
+ # "balances":[
583
+ # {
584
+ # "coin":"USDC",
585
+ # "hold":"0.0",
586
+ # "total":"1481.844"
587
+ # },
588
+ # {
589
+ # "coin":"PURR",
590
+ # "hold":"0.0",
591
+ # "total":"999.65004"
592
+ # }
593
+ # }
429
594
  #
595
+ balances = self.safe_list(response, 'balances')
596
+ if balances is not None:
597
+ spotBalances = {'info': response}
598
+ for i in range(0, len(balances)):
599
+ balance = balances[i]
600
+ code = self.safe_currency_code(self.safe_string(balance, 'coin'))
601
+ account = self.account()
602
+ total = self.safe_string(balance, 'total')
603
+ free = self.safe_string(balance, 'hold')
604
+ account['total'] = total
605
+ account['free'] = free
606
+ spotBalances[code] = account
607
+ return self.safe_balance(spotBalances)
430
608
  data = self.safe_dict(response, 'marginSummary', {})
431
609
  result = {
432
610
  'info': response,
@@ -915,6 +1093,7 @@ class hyperliquid(Exchange, ImplicitAPI):
915
1093
  :param str symbol: unified symbol of the market the order was made in
916
1094
  :param dict [params]: extra parameters specific to the exchange API endpoint
917
1095
  :param str [params.clientOrderId]: client order id,(optional 128 bit hex string e.g. 0x1234567890abcdef1234567890abcdef)
1096
+ :param str [params.vaultAddress]: the vault address for order
918
1097
  :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
919
1098
  """
920
1099
  return await self.cancel_orders([id], symbol, params)
@@ -928,6 +1107,7 @@ class hyperliquid(Exchange, ImplicitAPI):
928
1107
  :param str [symbol]: unified market symbol
929
1108
  :param dict [params]: extra parameters specific to the exchange API endpoint
930
1109
  :param string|str[] [params.clientOrderId]: client order ids,(optional 128 bit hex string e.g. 0x1234567890abcdef1234567890abcdef)
1110
+ :param str [params.vaultAddress]: the vault address
931
1111
  :returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
932
1112
  """
933
1113
  self.check_required_credentials()
@@ -1377,7 +1557,10 @@ class hyperliquid(Exchange, ImplicitAPI):
1377
1557
  coin = self.safe_string(entry, 'coin')
1378
1558
  marketId = None
1379
1559
  if coin is not None:
1380
- marketId = coin + '/USDC:USDC'
1560
+ if coin.find('/') > -1:
1561
+ marketId = coin
1562
+ else:
1563
+ marketId = coin + '/USDC:USDC'
1381
1564
  if self.safe_string(entry, 'id') is None:
1382
1565
  market = self.safe_market(marketId, None)
1383
1566
  else:
@@ -1772,7 +1955,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1772
1955
  #
1773
1956
  return response
1774
1957
 
1775
- async def add_margin(self, symbol: str, amount, params={}):
1958
+ async def add_margin(self, symbol: str, amount, params={}) -> MarginModification:
1776
1959
  """
1777
1960
  add margin
1778
1961
  :see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#update-isolated-margin
@@ -1783,7 +1966,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1783
1966
  """
1784
1967
  return await self.modify_margin_helper(symbol, amount, 'add', params)
1785
1968
 
1786
- async def reduce_margin(self, symbol: str, amount, params={}):
1969
+ async def reduce_margin(self, symbol: str, amount, params={}) -> MarginModification:
1787
1970
  """
1788
1971
  :see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#update-isolated-margin
1789
1972
  remove margin from a position
@@ -1794,7 +1977,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1794
1977
  """
1795
1978
  return await self.modify_margin_helper(symbol, amount, 'reduce', params)
1796
1979
 
1797
- async def modify_margin_helper(self, symbol: str, amount, type, params={}):
1980
+ async def modify_margin_helper(self, symbol: str, amount, type, params={}) -> MarginModification:
1798
1981
  await self.load_markets()
1799
1982
  market = self.market(symbol)
1800
1983
  asset = self.parse_to_int(market['baseId'])
@@ -1828,10 +2011,27 @@ class hyperliquid(Exchange, ImplicitAPI):
1828
2011
  # 'status': 'ok'
1829
2012
  # }
1830
2013
  #
1831
- return response
1832
- # return self.extend(self.parse_margin_modification(response, market), {
1833
- # 'code': code,
1834
- # })
2014
+ return self.extend(self.parse_margin_modification(response, market), {
2015
+ 'code': self.safe_string(response, 'status'),
2016
+ })
2017
+
2018
+ def parse_margin_modification(self, data, market: Market = None) -> MarginModification:
2019
+ #
2020
+ # {
2021
+ # 'type': 'default'
2022
+ # }
2023
+ #
2024
+ return {
2025
+ 'info': data,
2026
+ 'symbol': self.safe_symbol(None, market),
2027
+ 'type': None,
2028
+ 'amount': None,
2029
+ 'total': None,
2030
+ 'code': self.safe_string(market, 'settle'),
2031
+ 'status': None,
2032
+ 'timestamp': None,
2033
+ 'datetime': None,
2034
+ }
1835
2035
 
1836
2036
  async def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
1837
2037
  """
@@ -1839,23 +2039,49 @@ class hyperliquid(Exchange, ImplicitAPI):
1839
2039
  :see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#l1-usdc-transfer
1840
2040
  :param str code: unified currency code
1841
2041
  :param float amount: amount to transfer
1842
- :param str fromAccount: account to transfer from
1843
- :param str toAccount: account to transfer to
2042
+ :param str fromAccount: account to transfer from *spot, swap*
2043
+ :param str toAccount: account to transfer to *swap, spot or address*
1844
2044
  :param dict [params]: extra parameters specific to the exchange API endpoint
2045
+ :param str [params.vaultAddress]: the vault address for order
1845
2046
  :returns dict: a `transfer structure <https://docs.ccxt.com/#/?id=transfer-structure>`
1846
2047
  """
1847
2048
  self.check_required_credentials()
1848
2049
  await self.load_markets()
2050
+ isSandboxMode = self.safe_bool(self.options, 'sandboxMode')
2051
+ nonce = self.milliseconds()
2052
+ if self.in_array(fromAccount, ['spot', 'swap', 'perp']):
2053
+ # handle swap <> spot account transfer
2054
+ if not self.in_array(toAccount, ['spot', 'swap', 'perp']):
2055
+ raise NotSupported(self.id + 'transfer() only support spot <> swap transfer')
2056
+ vaultAddress = self.format_vault_address(self.safe_string(params, 'vaultAddress'))
2057
+ params = self.omit(params, 'vaultAddress')
2058
+ toPerp = (toAccount == 'perp') or (toAccount == 'swap')
2059
+ action = {
2060
+ 'type': 'spotUser',
2061
+ 'classTransfer': {
2062
+ 'usdc': amount,
2063
+ 'toPerp': toPerp,
2064
+ },
2065
+ }
2066
+ signature = self.sign_l1_action(action, nonce, vaultAddress)
2067
+ innerRequest = {
2068
+ 'action': self.extend(action, params),
2069
+ 'nonce': nonce,
2070
+ 'signature': signature,
2071
+ }
2072
+ if vaultAddress is not None:
2073
+ innerRequest['vaultAddress'] = vaultAddress
2074
+ transferResponse = await self.privatePostExchange(innerRequest)
2075
+ return transferResponse
2076
+ # handle sub-account/different account transfer
1849
2077
  self.check_address(toAccount)
1850
2078
  if code is not None:
1851
2079
  code = code.upper()
1852
2080
  if code != 'USDC':
1853
2081
  raise NotSupported(self.id + 'withdraw() only support USDC')
1854
- isSandboxMode = self.safe_bool(self.options, 'sandboxMode')
1855
- nonce = self.milliseconds()
1856
2082
  payload = {
1857
2083
  'destination': toAccount,
1858
- 'amount': str(amount),
2084
+ 'amount': self.number_to_string(amount),
1859
2085
  'time': nonce,
1860
2086
  }
1861
2087
  sig = self.build_transfer_sig(payload)
@@ -173,13 +173,15 @@ class idex(Exchange, ImplicitAPI):
173
173
  'network': 'MATIC',
174
174
  },
175
175
  'exceptions': {
176
- 'INVALID_ORDER_QUANTITY': InvalidOrder,
177
- 'INSUFFICIENT_FUNDS': InsufficientFunds,
178
- 'SERVICE_UNAVAILABLE': ExchangeNotAvailable,
179
- 'EXCEEDED_RATE_LIMIT': DDoSProtection,
180
- 'INVALID_PARAMETER': BadRequest,
181
- 'WALLET_NOT_ASSOCIATED': InvalidAddress,
182
- 'INVALID_WALLET_SIGNATURE': AuthenticationError,
176
+ 'exact': {
177
+ 'INVALID_ORDER_QUANTITY': InvalidOrder,
178
+ 'INSUFFICIENT_FUNDS': InsufficientFunds,
179
+ 'SERVICE_UNAVAILABLE': ExchangeNotAvailable,
180
+ 'EXCEEDED_RATE_LIMIT': DDoSProtection,
181
+ 'INVALID_PARAMETER': BadRequest,
182
+ 'WALLET_NOT_ASSOCIATED': InvalidAddress,
183
+ 'INVALID_WALLET_SIGNATURE': AuthenticationError,
184
+ },
183
185
  },
184
186
  'requiredCredentials': {
185
187
  'walletAddress': True,
@@ -461,7 +463,7 @@ class idex(Exchange, ImplicitAPI):
461
463
  if since is not None:
462
464
  request['start'] = since
463
465
  if limit is not None:
464
- request['limit'] = limit
466
+ request['limit'] = min(limit, 1000)
465
467
  response = await self.publicGetCandles(self.extend(request, params))
466
468
  if isinstance(response, list):
467
469
  # [
@@ -1413,10 +1415,8 @@ class idex(Exchange, ImplicitAPI):
1413
1415
  def handle_errors(self, code, reason, url, method, headers, body, response, requestHeaders, requestBody):
1414
1416
  errorCode = self.safe_string(response, 'code')
1415
1417
  message = self.safe_string(response, 'message')
1416
- if errorCode in self.exceptions:
1417
- Exception = self.exceptions[errorCode]
1418
- raise Exception(self.id + ' ' + message)
1419
1418
  if errorCode is not None:
1419
+ self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, message)
1420
1420
  raise ExchangeError(self.id + ' ' + message)
1421
1421
  return None
1422
1422
 
@@ -635,14 +635,12 @@ class krakenfutures(Exchange, ImplicitAPI):
635
635
  request['from'] = self.parse_to_int(since / 1000)
636
636
  if limit is None:
637
637
  limit = 5000
638
- elif limit > 5000:
639
- raise BadRequest(self.id + ' fetchOHLCV() limit cannot exceed 5000')
638
+ limit = min(limit, 5000)
640
639
  toTimestamp = self.sum(request['from'], limit * duration - 1)
641
640
  currentTimestamp = self.seconds()
642
641
  request['to'] = min(toTimestamp, currentTimestamp)
643
642
  elif limit is not None:
644
- if limit > 5000:
645
- raise BadRequest(self.id + ' fetchOHLCV() limit cannot exceed 5000')
643
+ limit = min(limit, 5000)
646
644
  duration = self.parse_timeframe(timeframe)
647
645
  request['to'] = self.seconds()
648
646
  request['from'] = self.parse_to_int(request['to'] - (duration * limit))
@@ -5,7 +5,7 @@
5
5
 
6
6
  from ccxt.async_support.kucoin import kucoin
7
7
  from ccxt.abstract.kucoinfutures import ImplicitAPI
8
- from ccxt.base.types import Balances, Currency, Int, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction, TransferEntry
8
+ from ccxt.base.types import Balances, Currency, Int, MarginModification, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction, TransferEntry
9
9
  from typing import List
10
10
  from ccxt.base.errors import PermissionDenied
11
11
  from ccxt.base.errors import AccountSuspended
@@ -1424,7 +1424,7 @@ class kucoinfutures(kucoin, ImplicitAPI):
1424
1424
  #
1425
1425
  return self.safe_value(response, 'data')
1426
1426
 
1427
- async def add_margin(self, symbol: str, amount, params={}):
1427
+ async def add_margin(self, symbol: str, amount, params={}) -> MarginModification:
1428
1428
  """
1429
1429
  add margin
1430
1430
  :see: https://www.kucoin.com/docs/rest/futures-trading/positions/add-margin-manually
@@ -970,6 +970,8 @@ class lbank(Exchange, ImplicitAPI):
970
970
  market = self.market(symbol)
971
971
  if limit is None:
972
972
  limit = 100
973
+ else:
974
+ limit = min(limit, 2000)
973
975
  if since is None:
974
976
  duration = self.parse_timeframe(timeframe)
975
977
  since = self.milliseconds() - duration * 1000 * limit
@@ -6,7 +6,7 @@
6
6
  from ccxt.async_support.base.exchange import Exchange
7
7
  from ccxt.abstract.mexc import ImplicitAPI
8
8
  import hashlib
9
- from ccxt.base.types import Account, Balances, Currency, IndexType, Int, Leverage, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction, TransferEntry
9
+ from ccxt.base.types import Account, Balances, Currency, IndexType, Int, Leverage, MarginModification, Market, Num, 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
@@ -3778,7 +3778,7 @@ class mexc(Exchange, ImplicitAPI):
3778
3778
  # }
3779
3779
  return response
3780
3780
 
3781
- async def reduce_margin(self, symbol: str, amount, params={}):
3781
+ async def reduce_margin(self, symbol: str, amount, params={}) -> MarginModification:
3782
3782
  """
3783
3783
  remove margin from a position
3784
3784
  :param str symbol: unified market symbol
@@ -3788,7 +3788,7 @@ class mexc(Exchange, ImplicitAPI):
3788
3788
  """
3789
3789
  return await self.modify_margin_helper(symbol, amount, 'SUB', params)
3790
3790
 
3791
- async def add_margin(self, symbol: str, amount, params={}):
3791
+ async def add_margin(self, symbol: str, amount, params={}) -> MarginModification:
3792
3792
  """
3793
3793
  add margin
3794
3794
  :param str symbol: unified market symbol
@@ -750,7 +750,7 @@ class oceanex(Exchange, ImplicitAPI):
750
750
  if since is not None:
751
751
  request['timestamp'] = since
752
752
  if limit is not None:
753
- request['limit'] = limit
753
+ request['limit'] = min(limit, 10000)
754
754
  response = await self.publicPostK(self.extend(request, params))
755
755
  ohlcvs = self.safe_list(response, 'data', [])
756
756
  return self.parse_ohlcvs(ohlcvs, market, timeframe, since, limit)
@@ -1121,8 +1121,9 @@ class okcoin(Exchange, ImplicitAPI):
1121
1121
  request = {
1122
1122
  'instId': market['id'],
1123
1123
  'bar': bar,
1124
- 'limit': limit,
1125
1124
  }
1125
+ if limit is not None:
1126
+ request['limit'] = limit # default 100, max 100
1126
1127
  method = None
1127
1128
  method, params = self.handle_option_and_params(params, 'fetchOHLCV', 'method', 'publicGetMarketCandles')
1128
1129
  response = None
ccxt/async_support/okx.py CHANGED
@@ -7,7 +7,7 @@ from ccxt.async_support.base.exchange import Exchange
7
7
  from ccxt.abstract.okx import ImplicitAPI
8
8
  import asyncio
9
9
  import hashlib
10
- from ccxt.base.types import Account, Balances, Currency, Greeks, Int, Leverage, Market, MarketInterface, Num, Option, OptionChain, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction, TransferEntry
10
+ from ccxt.base.types import Account, Balances, Currency, Greeks, Int, Leverage, MarginModification, Market, MarketInterface, Num, Option, OptionChain, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction, TransferEntry
11
11
  from typing import List
12
12
  from ccxt.base.errors import ExchangeError
13
13
  from ccxt.base.errors import PermissionDenied
@@ -6007,7 +6007,7 @@ class okx(Exchange, ImplicitAPI):
6007
6007
  data = self.safe_value(response, 'data')
6008
6008
  return self.parse_borrow_rate_history(data, code, since, limit)
6009
6009
 
6010
- async def modify_margin_helper(self, symbol: str, amount, type, params={}):
6010
+ async def modify_margin_helper(self, symbol: str, amount, type, params={}) -> MarginModification:
6011
6011
  await self.load_markets()
6012
6012
  market = self.market(symbol)
6013
6013
  posSide = self.safe_string(params, 'posSide', 'net')
@@ -6033,29 +6033,43 @@ class okx(Exchange, ImplicitAPI):
6033
6033
  # "msg": ""
6034
6034
  # }
6035
6035
  #
6036
- return self.parse_margin_modification(response, market)
6036
+ data = self.safe_list(response, 'data', [])
6037
+ errorCode = self.safe_string(response, 'code')
6038
+ item = self.safe_dict(data, 0, {})
6039
+ return self.extend(self.parse_margin_modification(item, market), {
6040
+ 'status': 'ok' if (errorCode == '0') else 'failed',
6041
+ })
6037
6042
 
6038
- def parse_margin_modification(self, data, market: Market = None):
6039
- innerData = self.safe_value(data, 'data', [])
6040
- entry = self.safe_value(innerData, 0, {})
6041
- errorCode = self.safe_string(data, 'code')
6042
- status = 'ok' if (errorCode == '0') else 'failed'
6043
- amountRaw = self.safe_number(entry, 'amt')
6044
- typeRaw = self.safe_string(entry, 'type')
6043
+ def parse_margin_modification(self, data, market: Market = None) -> MarginModification:
6044
+ #
6045
+ # addMargin/reduceMargin
6046
+ #
6047
+ # {
6048
+ # "amt": "0.01",
6049
+ # "instId": "ETH-USD-SWAP",
6050
+ # "posSide": "net",
6051
+ # "type": "reduce"
6052
+ # }
6053
+ #
6054
+ amountRaw = self.safe_number(data, 'amt')
6055
+ typeRaw = self.safe_string(data, 'type')
6045
6056
  type = 'reduce' if (typeRaw == 'reduce') else 'add'
6046
- marketId = self.safe_string(entry, 'instId')
6057
+ marketId = self.safe_string(data, 'instId')
6047
6058
  responseMarket = self.safe_market(marketId, market)
6048
6059
  code = responseMarket['base'] if responseMarket['inverse'] else responseMarket['quote']
6049
6060
  return {
6050
6061
  'info': data,
6062
+ 'symbol': responseMarket['symbol'],
6051
6063
  'type': type,
6052
6064
  'amount': amountRaw,
6065
+ 'total': None,
6053
6066
  'code': code,
6054
- 'symbol': responseMarket['symbol'],
6055
- 'status': status,
6067
+ 'status': None,
6068
+ 'timestamp': None,
6069
+ 'datetime': None,
6056
6070
  }
6057
6071
 
6058
- async def reduce_margin(self, symbol: str, amount, params={}):
6072
+ async def reduce_margin(self, symbol: str, amount, params={}) -> MarginModification:
6059
6073
  """
6060
6074
  remove margin from a position
6061
6075
  :see: https://www.okx.com/docs-v5/en/#trading-account-rest-api-increase-decrease-margin
@@ -6066,7 +6080,7 @@ class okx(Exchange, ImplicitAPI):
6066
6080
  """
6067
6081
  return await self.modify_margin_helper(symbol, amount, 'reduce', params)
6068
6082
 
6069
- async def add_margin(self, symbol: str, amount, params={}):
6083
+ async def add_margin(self, symbol: str, amount, params={}) -> MarginModification:
6070
6084
  """
6071
6085
  add margin
6072
6086
  :see: https://www.okx.com/docs-v5/en/#trading-account-rest-api-increase-decrease-margin
@@ -7,7 +7,7 @@ from ccxt.async_support.base.exchange import Exchange
7
7
  from ccxt.abstract.phemex import ImplicitAPI
8
8
  import hashlib
9
9
  import numbers
10
- from ccxt.base.types import Balances, Currency, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction, TransferEntry
10
+ from ccxt.base.types import Balances, Currency, Int, MarginModification, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction, TransferEntry
11
11
  from typing import List
12
12
  from ccxt.base.errors import ExchangeError
13
13
  from ccxt.base.errors import PermissionDenied
@@ -3744,7 +3744,7 @@ class phemex(Exchange, ImplicitAPI):
3744
3744
  'previousFundingDatetime': None,
3745
3745
  }
3746
3746
 
3747
- async def set_margin(self, symbol: str, amount: float, params={}):
3747
+ async def set_margin(self, symbol: str, amount: float, params={}) -> MarginModification:
3748
3748
  """
3749
3749
  Either adds or reduces margin in an isolated position in order to set the margin to a specific value
3750
3750
  :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Contract-API-en.md#assign-position-balance-in-isolated-marign-mode
@@ -3777,7 +3777,7 @@ class phemex(Exchange, ImplicitAPI):
3777
3777
  }
3778
3778
  return self.safe_string(statuses, status, status)
3779
3779
 
3780
- def parse_margin_modification(self, data, market: Market = None):
3780
+ def parse_margin_modification(self, data, market: Market = None) -> MarginModification:
3781
3781
  #
3782
3782
  # {
3783
3783
  # "code": 0,
@@ -3790,12 +3790,14 @@ class phemex(Exchange, ImplicitAPI):
3790
3790
  codeCurrency = 'base' if inverse else 'quote'
3791
3791
  return {
3792
3792
  'info': data,
3793
+ 'symbol': self.safe_symbol(None, market),
3793
3794
  'type': 'set',
3794
3795
  'amount': None,
3795
3796
  'total': None,
3796
3797
  'code': market[codeCurrency],
3797
- 'symbol': self.safe_symbol(None, market),
3798
3798
  'status': self.parse_margin_status(self.safe_string(data, 'code')),
3799
+ 'timestamp': None,
3800
+ 'datetime': None,
3799
3801
  }
3800
3802
 
3801
3803
  async def set_margin_mode(self, marginMode: str, symbol: Str = None, params={}):
@@ -324,7 +324,7 @@ class wazirx(Exchange, ImplicitAPI):
324
324
  'interval': self.safe_string(self.timeframes, timeframe, timeframe),
325
325
  }
326
326
  if limit is not None:
327
- request['limit'] = limit
327
+ request['limit'] = min(limit, 2000)
328
328
  until = self.safe_integer(params, 'until')
329
329
  params = self.omit(params, ['until'])
330
330
  if since is not None: