ccxt 4.3.14__py2.py3-none-any.whl → 4.3.16__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 (70) hide show
  1. ccxt/__init__.py +2 -1
  2. ccxt/abstract/luno.py +2 -0
  3. ccxt/alpaca.py +1 -0
  4. ccxt/ascendex.py +1 -0
  5. ccxt/async_support/__init__.py +2 -1
  6. ccxt/async_support/alpaca.py +1 -0
  7. ccxt/async_support/ascendex.py +1 -0
  8. ccxt/async_support/base/exchange.py +18 -13
  9. ccxt/async_support/binance.py +5 -3
  10. ccxt/async_support/bingx.py +2 -0
  11. ccxt/async_support/bitmex.py +1 -0
  12. ccxt/async_support/bybit.py +7 -6
  13. ccxt/async_support/coinbaseinternational.py +1 -0
  14. ccxt/async_support/coinex.py +35 -33
  15. ccxt/async_support/coinmetro.py +1 -0
  16. ccxt/async_support/cryptocom.py +3 -1
  17. ccxt/async_support/currencycom.py +1 -0
  18. ccxt/async_support/deribit.py +1 -0
  19. ccxt/async_support/gate.py +1 -0
  20. ccxt/async_support/gemini.py +1 -0
  21. ccxt/async_support/hitbtc.py +2 -0
  22. ccxt/async_support/hollaex.py +1 -0
  23. ccxt/async_support/hyperliquid.py +4 -0
  24. ccxt/async_support/idex.py +1 -0
  25. ccxt/async_support/krakenfutures.py +1 -0
  26. ccxt/async_support/luno.py +2 -0
  27. ccxt/async_support/ndax.py +1 -0
  28. ccxt/async_support/okx.py +1 -0
  29. ccxt/async_support/phemex.py +2 -1
  30. ccxt/async_support/poloniex.py +1 -0
  31. ccxt/async_support/probit.py +1 -0
  32. ccxt/async_support/wavesexchange.py +1 -0
  33. ccxt/async_support/woo.py +1 -0
  34. ccxt/async_support/zaif.py +1 -1
  35. ccxt/base/errors.py +6 -0
  36. ccxt/base/exchange.py +24 -19
  37. ccxt/binance.py +5 -3
  38. ccxt/bingx.py +2 -0
  39. ccxt/bitmex.py +1 -0
  40. ccxt/bybit.py +7 -6
  41. ccxt/coinbaseinternational.py +1 -0
  42. ccxt/coinex.py +35 -33
  43. ccxt/coinmetro.py +1 -0
  44. ccxt/cryptocom.py +3 -1
  45. ccxt/currencycom.py +1 -0
  46. ccxt/deribit.py +1 -0
  47. ccxt/gate.py +1 -0
  48. ccxt/gemini.py +1 -0
  49. ccxt/hitbtc.py +2 -0
  50. ccxt/hollaex.py +1 -0
  51. ccxt/hyperliquid.py +4 -0
  52. ccxt/idex.py +1 -0
  53. ccxt/krakenfutures.py +1 -0
  54. ccxt/luno.py +2 -0
  55. ccxt/ndax.py +1 -0
  56. ccxt/okx.py +1 -0
  57. ccxt/phemex.py +2 -1
  58. ccxt/poloniex.py +1 -0
  59. ccxt/pro/__init__.py +1 -1
  60. ccxt/pro/hitbtc.py +1 -1
  61. ccxt/pro/independentreserve.py +3 -3
  62. ccxt/pro/poloniex.py +3 -3
  63. ccxt/probit.py +1 -0
  64. ccxt/wavesexchange.py +1 -0
  65. ccxt/woo.py +1 -0
  66. ccxt/zaif.py +1 -1
  67. {ccxt-4.3.14.dist-info → ccxt-4.3.16.dist-info}/METADATA +4 -4
  68. {ccxt-4.3.14.dist-info → ccxt-4.3.16.dist-info}/RECORD +70 -70
  69. {ccxt-4.3.14.dist-info → ccxt-4.3.16.dist-info}/WHEEL +0 -0
  70. {ccxt-4.3.14.dist-info → ccxt-4.3.16.dist-info}/top_level.txt +0 -0
ccxt/__init__.py CHANGED
@@ -22,7 +22,7 @@
22
22
 
23
23
  # ----------------------------------------------------------------------------
24
24
 
25
- __version__ = '4.3.14'
25
+ __version__ = '4.3.16'
26
26
 
27
27
  # ----------------------------------------------------------------------------
28
28
 
@@ -53,6 +53,7 @@ from ccxt.base.errors import BadSymbol # noqa: F4
53
53
  from ccxt.base.errors import OperationRejected # noqa: F401
54
54
  from ccxt.base.errors import NoChange # noqa: F401
55
55
  from ccxt.base.errors import MarginModeAlreadySet # noqa: F401
56
+ from ccxt.base.errors import MarketClosed # noqa: F401
56
57
  from ccxt.base.errors import BadResponse # noqa: F401
57
58
  from ccxt.base.errors import NullResponse # noqa: F401
58
59
  from ccxt.base.errors import InsufficientFunds # noqa: F401
ccxt/abstract/luno.py CHANGED
@@ -31,5 +31,7 @@ class ImplicitAPI:
31
31
  private_post_withdrawals = privatePostWithdrawals = Entry('withdrawals', 'private', 'POST', {'cost': 1})
32
32
  private_post_send = privatePostSend = Entry('send', 'private', 'POST', {'cost': 1})
33
33
  private_post_oauth2_grant = privatePostOauth2Grant = Entry('oauth2/grant', 'private', 'POST', {'cost': 1})
34
+ private_post_beneficiaries = privatePostBeneficiaries = Entry('beneficiaries', 'private', 'POST', {'cost': 1})
34
35
  private_put_accounts_id_name = privatePutAccountsIdName = Entry('accounts/{id}/name', 'private', 'PUT', {'cost': 1})
35
36
  private_delete_withdrawals_id = privateDeleteWithdrawalsId = Entry('withdrawals/{id}', 'private', 'DELETE', {'cost': 1})
37
+ private_delete_beneficiaries_id = privateDeleteBeneficiariesId = Entry('beneficiaries/{id}', 'private', 'DELETE', {'cost': 1})
ccxt/alpaca.py CHANGED
@@ -98,6 +98,7 @@ class alpaca(Exchange, ImplicitAPI):
98
98
  'fetchTransactions': False,
99
99
  'fetchTransfers': False,
100
100
  'fetchWithdrawals': False,
101
+ 'sandbox': True,
101
102
  'setLeverage': False,
102
103
  'setMarginMode': False,
103
104
  'transfer': False,
ccxt/ascendex.py CHANGED
@@ -102,6 +102,7 @@ class ascendex(Exchange, ImplicitAPI):
102
102
  'fetchWithdrawal': False,
103
103
  'fetchWithdrawals': True,
104
104
  'reduceMargin': True,
105
+ 'sandbox': True,
105
106
  'setLeverage': True,
106
107
  'setMarginMode': True,
107
108
  'setPositionMode': False,
@@ -4,7 +4,7 @@
4
4
 
5
5
  # -----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.3.14'
7
+ __version__ = '4.3.16'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
 
@@ -32,6 +32,7 @@ from ccxt.base.errors import BadSymbol # noqa: F4
32
32
  from ccxt.base.errors import OperationRejected # noqa: F401
33
33
  from ccxt.base.errors import NoChange # noqa: F401
34
34
  from ccxt.base.errors import MarginModeAlreadySet # noqa: F401
35
+ from ccxt.base.errors import MarketClosed # noqa: F401
35
36
  from ccxt.base.errors import BadResponse # noqa: F401
36
37
  from ccxt.base.errors import NullResponse # noqa: F401
37
38
  from ccxt.base.errors import InsufficientFunds # noqa: F401
@@ -98,6 +98,7 @@ class alpaca(Exchange, ImplicitAPI):
98
98
  'fetchTransactions': False,
99
99
  'fetchTransfers': False,
100
100
  'fetchWithdrawals': False,
101
+ 'sandbox': True,
101
102
  'setLeverage': False,
102
103
  'setMarginMode': False,
103
104
  'transfer': False,
@@ -102,6 +102,7 @@ class ascendex(Exchange, ImplicitAPI):
102
102
  'fetchWithdrawal': False,
103
103
  'fetchWithdrawals': True,
104
104
  'reduceMargin': True,
105
+ 'sandbox': True,
105
106
  'setLeverage': True,
106
107
  'setMarginMode': True,
107
108
  'setPositionMode': False,
@@ -2,7 +2,7 @@
2
2
 
3
3
  # -----------------------------------------------------------------------------
4
4
 
5
- __version__ = '4.3.14'
5
+ __version__ = '4.3.16'
6
6
 
7
7
  # -----------------------------------------------------------------------------
8
8
 
@@ -1775,18 +1775,19 @@ class Exchange(BaseExchange):
1775
1775
  maxRetries = None
1776
1776
  maxRetries, params = self.handle_option_and_params(params, method, 'maxRetries', 3)
1777
1777
  errors = 0
1778
- try:
1779
- if timeframe and method != 'fetchFundingRateHistory':
1780
- return await getattr(self, method)(symbol, timeframe, since, limit, params)
1781
- else:
1782
- return await getattr(self, method)(symbol, since, limit, params)
1783
- except Exception as e:
1784
- if isinstance(e, RateLimitExceeded):
1785
- raise e # if we are rate limited, we should not retry and fail fast
1786
- errors += 1
1787
- if errors > maxRetries:
1788
- raise e
1789
- return None
1778
+ while(errors <= maxRetries):
1779
+ try:
1780
+ if timeframe and method != 'fetchFundingRateHistory':
1781
+ return await getattr(self, method)(symbol, timeframe, since, limit, params)
1782
+ else:
1783
+ return await getattr(self, method)(symbol, since, limit, params)
1784
+ except Exception as e:
1785
+ if isinstance(e, RateLimitExceeded):
1786
+ raise e # if we are rate limited, we should not retry and fail fast
1787
+ errors += 1
1788
+ if errors > maxRetries:
1789
+ raise e
1790
+ return []
1790
1791
 
1791
1792
  async def fetch_paginated_call_deterministic(self, method: str, symbol: Str = None, since: Int = None, limit: Int = None, timeframe: Str = None, params={}, maxEntriesPerRequest=None):
1792
1793
  maxCalls = None
@@ -1799,6 +1800,8 @@ class Exchange(BaseExchange):
1799
1800
  currentSince = current - (maxCalls * step) - 1
1800
1801
  if since is not None:
1801
1802
  currentSince = max(currentSince, since)
1803
+ else:
1804
+ currentSince = max(currentSince, 1241440531000) # avoid timestamps older than 2009
1802
1805
  until = self.safe_integer_2(params, 'until', 'till') # do not omit it here
1803
1806
  if until is not None:
1804
1807
  requiredCalls = int(math.ceil((until - since)) / step)
@@ -1807,6 +1810,8 @@ class Exchange(BaseExchange):
1807
1810
  for i in range(0, maxCalls):
1808
1811
  if (until is not None) and (currentSince >= until):
1809
1812
  break
1813
+ if currentSince >= current:
1814
+ break
1810
1815
  tasks.append(self.safe_deterministic_call(method, symbol, currentSince, maxEntriesPerRequest, timeframe, params))
1811
1816
  currentSince = self.sum(currentSince, step) - 1
1812
1817
  results = await asyncio.gather(*tasks)
@@ -19,6 +19,7 @@ from ccxt.base.errors import BadRequest
19
19
  from ccxt.base.errors import BadSymbol
20
20
  from ccxt.base.errors import OperationRejected
21
21
  from ccxt.base.errors import MarginModeAlreadySet
22
+ from ccxt.base.errors import MarketClosed
22
23
  from ccxt.base.errors import BadResponse
23
24
  from ccxt.base.errors import InsufficientFunds
24
25
  from ccxt.base.errors import InvalidOrder
@@ -177,6 +178,7 @@ class binance(Exchange, ImplicitAPI):
177
178
  'reduceMargin': True,
178
179
  'repayCrossMargin': True,
179
180
  'repayIsolatedMargin': True,
181
+ 'sandbox': True,
180
182
  'setLeverage': True,
181
183
  'setMargin': False,
182
184
  'setMarginMode': True,
@@ -2419,7 +2421,7 @@ class binance(Exchange, ImplicitAPI):
2419
2421
  'Rest API trading is not enabled.': PermissionDenied,
2420
2422
  'This account may not place or cancel orders.': PermissionDenied,
2421
2423
  "You don't have permission.": PermissionDenied, # {"msg":"You don't have permission.","success":false}
2422
- 'Market is closed.': OperationRejected, # {"code":-1013,"msg":"Market is closed."}
2424
+ 'Market is closed.': MarketClosed, # {"code":-1013,"msg":"Market is closed."}
2423
2425
  'Too many requests. Please try again later.': RateLimitExceeded, # {"msg":"Too many requests. Please try again later.","success":false}
2424
2426
  'This action is disabled on self account.': AccountSuspended, # {"code":-2011,"msg":"This action is disabled on self account."}
2425
2427
  'Limit orders require GTC for self phase.': BadRequest,
@@ -3886,8 +3888,8 @@ class binance(Exchange, ImplicitAPI):
3886
3888
  """
3887
3889
  fetches the last price for multiple markets
3888
3890
  :see: https://binance-docs.github.io/apidocs/spot/en/#symbol-price-ticker # spot
3889
- :see: https://binance-docs.github.io/apidocs/future/en/#symbol-price-ticker # swap
3890
- :see: https://binance-docs.github.io/apidocs/delivery/en/#symbol-price-ticker # future
3891
+ :see: https://binance-docs.github.io/apidocs/futures/en/#symbol-price-ticker # swap
3892
+ :see: https://binance-docs.github.io/apidocs/delivery/en/#symbol-price-tickers # future
3891
3893
  :param str[]|None symbols: unified symbols of the markets to fetch the last prices
3892
3894
  :param dict [params]: extra parameters specific to the exchange API endpoint
3893
3895
  :param str [params.subType]: "linear" or "inverse"
@@ -98,6 +98,7 @@ class bingx(Exchange, ImplicitAPI):
98
98
  'fetchTransfers': True,
99
99
  'fetchWithdrawals': True,
100
100
  'reduceMargin': True,
101
+ 'sandbox': True,
101
102
  'setLeverage': True,
102
103
  'setMargin': True,
103
104
  'setMarginMode': True,
@@ -401,6 +402,7 @@ class bingx(Exchange, ImplicitAPI):
401
402
  '100202': InsufficientFunds,
402
403
  '100204': BadRequest,
403
404
  '100400': BadRequest,
405
+ '100410': OperationFailed, # {"code":100410,"msg":"The current system is busy, please try again later"}
404
406
  '100421': BadSymbol, # {"code":100421,"msg":"This pair is currently restricted from API trading","debugMsg":""}
405
407
  '100440': ExchangeError,
406
408
  '100500': OperationFailed, # {"code":100500,"msg":"The current system is busy, please try again later","debugMsg":""}
@@ -100,6 +100,7 @@ class bitmex(Exchange, ImplicitAPI):
100
100
  'fetchTransfer': False,
101
101
  'fetchTransfers': False,
102
102
  'reduceMargin': None,
103
+ 'sandbox': True,
103
104
  'setLeverage': True,
104
105
  'setMargin': None,
105
106
  'setMarginMode': True,
@@ -134,6 +134,7 @@ class bybit(Exchange, ImplicitAPI):
134
134
  'fetchVolatilityHistory': True,
135
135
  'fetchWithdrawals': True,
136
136
  'repayCrossMargin': True,
137
+ 'sandbox': True,
137
138
  'setLeverage': True,
138
139
  'setMarginMode': True,
139
140
  'setPositionMode': True,
@@ -6268,19 +6269,19 @@ class bybit(Exchange, ImplicitAPI):
6268
6269
  isUsdcSettled = market['settle'] == 'USDC'
6269
6270
  # engage in leverage setting
6270
6271
  # we reuse the code here instead of having two methods
6271
- leverage = self.number_to_string(leverage)
6272
+ leverageString = self.number_to_string(leverage)
6272
6273
  request = {
6273
6274
  'symbol': market['id'],
6274
- 'buyLeverage': leverage,
6275
- 'sellLeverage': leverage,
6275
+ 'buyLeverage': leverageString,
6276
+ 'sellLeverage': leverageString,
6276
6277
  }
6277
6278
  response = None
6278
6279
  if isUsdcSettled and not isUnifiedAccount:
6279
- request['leverage'] = leverage
6280
+ request['leverage'] = leverageString
6280
6281
  response = await self.privatePostPerpetualUsdcOpenapiPrivateV1PositionLeverageSave(self.extend(request, params))
6281
6282
  else:
6282
- request['buyLeverage'] = leverage
6283
- request['sellLeverage'] = leverage
6283
+ request['buyLeverage'] = leverageString
6284
+ request['sellLeverage'] = leverageString
6284
6285
  if market['linear']:
6285
6286
  request['category'] = 'linear'
6286
6287
  elif market['inverse']:
@@ -113,6 +113,7 @@ class coinbaseinternational(Exchange, ImplicitAPI):
113
113
  'fetchTradingFees': False,
114
114
  'fetchWithdrawals': True,
115
115
  'reduceMargin': False,
116
+ 'sandbox': True,
116
117
  'setLeverage': False,
117
118
  'setMargin': True,
118
119
  'setMarginMode': False,
@@ -3488,48 +3488,49 @@ class coinex(Exchange, ImplicitAPI):
3488
3488
  async def create_deposit_address(self, code: str, params={}):
3489
3489
  """
3490
3490
  create a currency deposit address
3491
- :see: https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot002_account019_update_deposit_address
3491
+ :see: https://docs.coinex.com/api/v2/assets/deposit-withdrawal/http/update-deposit-address
3492
3492
  :param str code: unified currency code of the currency for the deposit address
3493
3493
  :param dict [params]: extra parameters specific to the exchange API endpoint
3494
+ :param str [params.network]: the blockchain network to create a deposit address on
3494
3495
  :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
3495
3496
  """
3496
3497
  await self.load_markets()
3497
3498
  currency = self.currency(code)
3499
+ network = self.safe_string_2(params, 'chain', 'network')
3500
+ if network is None:
3501
+ raise ArgumentsRequired(self.id + ' createDepositAddress() requires a network parameter')
3502
+ params = self.omit(params, 'network')
3498
3503
  request = {
3499
- 'coin_type': currency['id'],
3504
+ 'ccy': currency['id'],
3505
+ 'chain': self.network_code_to_id(network, currency['code']),
3500
3506
  }
3501
- if 'network' in params:
3502
- network = self.safe_string(params, 'network')
3503
- params = self.omit(params, 'network')
3504
- request['smart_contract_name'] = network
3505
- response = await self.v1PrivatePutBalanceDepositAddressCoinType(self.extend(request, params))
3507
+ response = await self.v2PrivatePostAssetsRenewalDepositAddress(self.extend(request, params))
3506
3508
  #
3507
3509
  # {
3508
3510
  # "code": 0,
3509
3511
  # "data": {
3510
- # "coin_address": "TV639dSpb9iGRtoFYkCp4AoaaDYKrK1pw5",
3511
- # "is_bitcoin_cash": False
3512
+ # "address": "0x321bd6479355142334f45653ad5d8b76105a1234",
3513
+ # "memo": ""
3512
3514
  # },
3513
- # "message": "Success"
3515
+ # "message": "OK"
3514
3516
  # }
3517
+ #
3515
3518
  data = self.safe_dict(response, 'data', {})
3516
3519
  return self.parse_deposit_address(data, currency)
3517
3520
 
3518
3521
  async def fetch_deposit_address(self, code: str, params={}):
3519
3522
  """
3520
3523
  fetch the deposit address for a currency associated with self account
3521
- :see: https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot002_account020_query_deposit_address
3524
+ :see: https://docs.coinex.com/api/v2/assets/deposit-withdrawal/http/get-deposit-address
3522
3525
  :param str code: unified currency code
3523
3526
  :param dict [params]: extra parameters specific to the exchange API endpoint
3527
+ :param str [params.network]: the blockchain network to create a deposit address on
3524
3528
  :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
3525
3529
  """
3526
3530
  await self.load_markets()
3527
3531
  currency = self.currency(code)
3528
- request = {
3529
- 'coin_type': currency['id'],
3530
- }
3531
- networks = self.safe_value(currency, 'networks', {})
3532
- network = self.safe_string(params, 'network')
3532
+ networks = self.safe_dict(currency, 'networks', {})
3533
+ network = self.safe_string_2(params, 'network', 'chain')
3533
3534
  params = self.omit(params, 'network')
3534
3535
  networksKeys = list(networks.keys())
3535
3536
  numOfNetworks = len(networksKeys)
@@ -3538,23 +3539,24 @@ class coinex(Exchange, ImplicitAPI):
3538
3539
  raise ArgumentsRequired(self.id + ' fetchDepositAddress() ' + code + ' requires a network parameter')
3539
3540
  if not (network in networks):
3540
3541
  raise ExchangeError(self.id + ' fetchDepositAddress() ' + network + ' network not supported for ' + code)
3541
- if network is not None:
3542
- request['smart_contract_name'] = network
3543
- response = await self.v1PrivateGetBalanceDepositAddressCoinType(self.extend(request, params))
3542
+ request = {
3543
+ 'ccy': currency['id'],
3544
+ 'chain': network,
3545
+ }
3546
+ response = await self.v2PrivateGetAssetsDepositAddress(self.extend(request, params))
3544
3547
  #
3545
- # {
3546
- # "code": 0,
3547
- # "data": {
3548
- # "coin_address": "1P1JqozxioQwaqPwgMAQdNDYNyaVSqgARq",
3549
- # # coin_address: "xxxxxxxxxxxxxx:yyyyyyyyy", # with embedded tag/memo
3550
- # "is_bitcoin_cash": False
3551
- # },
3552
- # "message": "Success"
3553
- # }
3548
+ # {
3549
+ # "code": 0,
3550
+ # "data": {
3551
+ # "address": "0x321bd6479355142334f45653ad5d8b76105a1234",
3552
+ # "memo": ""
3553
+ # },
3554
+ # "message": "OK"
3555
+ # }
3554
3556
  #
3555
- data = self.safe_value(response, 'data', {})
3557
+ data = self.safe_dict(response, 'data', {})
3556
3558
  depositAddress = self.parse_deposit_address(data, currency)
3557
- options = self.safe_value(self.options, 'fetchDepositAddress', {})
3559
+ options = self.safe_dict(self.options, 'fetchDepositAddress', {})
3558
3560
  fillResponseFromRequest = self.safe_bool(options, 'fillResponseFromRequest', True)
3559
3561
  if fillResponseFromRequest:
3560
3562
  depositAddress['network'] = self.safe_network_code(network, currency)
@@ -3578,11 +3580,11 @@ class coinex(Exchange, ImplicitAPI):
3578
3580
  def parse_deposit_address(self, depositAddress, currency: Currency = None):
3579
3581
  #
3580
3582
  # {
3581
- # "coin_address": "1P1JqozxioQwaqPwgMAQdNDYNyaVSqgARq",
3582
- # "is_bitcoin_cash": False
3583
+ # "address": "1P1JqozxioQwaqPwgMAQdNDYNyaVSqgARq",
3584
+ # "memo": ""
3583
3585
  # }
3584
3586
  #
3585
- coinAddress = self.safe_string(depositAddress, 'coin_address')
3587
+ coinAddress = self.safe_string(depositAddress, 'address')
3586
3588
  parts = coinAddress.split(':')
3587
3589
  address = None
3588
3590
  tag = None
@@ -122,6 +122,7 @@ class coinmetro(Exchange, ImplicitAPI):
122
122
  'reduceMargin': False,
123
123
  'repayCrossMargin': False,
124
124
  'repayIsolatedMargin': False,
125
+ 'sandbox': True,
125
126
  'setLeverage': False,
126
127
  'setMargin': False,
127
128
  'setMarginMode': False,
@@ -117,6 +117,7 @@ class cryptocom(Exchange, ImplicitAPI):
117
117
  'reduceMargin': False,
118
118
  'repayCrossMargin': False,
119
119
  'repayIsolatedMargin': False,
120
+ 'sandbox': True,
120
121
  'setLeverage': False,
121
122
  'setMarginMode': False,
122
123
  'setPositionMode': False,
@@ -509,7 +510,8 @@ class cryptocom(Exchange, ImplicitAPI):
509
510
  strike = self.safe_string(market, 'strike')
510
511
  marginBuyEnabled = self.safe_value(market, 'margin_buy_enabled')
511
512
  marginSellEnabled = self.safe_value(market, 'margin_sell_enabled')
512
- expiry = self.omit_zero(self.safe_integer(market, 'expiry_timestamp_ms'))
513
+ expiryString = self.omit_zero(self.safe_string(market, 'expiry_timestamp_ms'))
514
+ expiry = int(expiryString) if (expiryString is not None) else None
513
515
  symbol = base + '/' + quote
514
516
  type = None
515
517
  contract = None
@@ -114,6 +114,7 @@ class currencycom(Exchange, ImplicitAPI):
114
114
  'fetchWithdrawal': None,
115
115
  'fetchWithdrawals': True,
116
116
  'reduceMargin': None,
117
+ 'sandbox': True,
117
118
  'setLeverage': None,
118
119
  'setMarginMode': None,
119
120
  'setPositionMode': None,
@@ -107,6 +107,7 @@ class deribit(Exchange, ImplicitAPI):
107
107
  'fetchVolatilityHistory': True,
108
108
  'fetchWithdrawal': False,
109
109
  'fetchWithdrawals': True,
110
+ 'sandbox': True,
110
111
  'transfer': True,
111
112
  'withdraw': True,
112
113
  },
@@ -176,6 +176,7 @@ class gate(Exchange, ImplicitAPI):
176
176
  'reduceMargin': True,
177
177
  'repayCrossMargin': True,
178
178
  'repayIsolatedMargin': True,
179
+ 'sandbox': True,
179
180
  'setLeverage': True,
180
181
  'setMarginMode': False,
181
182
  'setPositionMode': True,
@@ -96,6 +96,7 @@ class gemini(Exchange, ImplicitAPI):
96
96
  'fetchTransactions': 'emulated',
97
97
  'postOnly': True,
98
98
  'reduceMargin': False,
99
+ 'sandbox': True,
99
100
  'setLeverage': False,
100
101
  'setMarginMode': False,
101
102
  'setPositionMode': False,
@@ -108,6 +108,7 @@ class hitbtc(Exchange, ImplicitAPI):
108
108
  'fetchTransactions': 'emulated',
109
109
  'fetchWithdrawals': True,
110
110
  'reduceMargin': True,
111
+ 'sandbox': True,
111
112
  'setLeverage': True,
112
113
  'setMargin': False,
113
114
  'setMarginMode': False,
@@ -632,6 +633,7 @@ class hitbtc(Exchange, ImplicitAPI):
632
633
  'accountsByType': {
633
634
  'spot': 'spot',
634
635
  'funding': 'wallet',
636
+ 'swap': 'derivatives',
635
637
  'future': 'derivatives',
636
638
  },
637
639
  'withdraw': {
@@ -96,6 +96,7 @@ class hollaex(Exchange, ImplicitAPI):
96
96
  'fetchWithdrawal': True,
97
97
  'fetchWithdrawals': True,
98
98
  'reduceMargin': False,
99
+ 'sandbox': True,
99
100
  'setLeverage': False,
100
101
  'setMarginMode': False,
101
102
  'setPositionMode': False,
@@ -114,6 +114,7 @@ class hyperliquid(Exchange, ImplicitAPI):
114
114
  'reduceMargin': True,
115
115
  'repayCrossMargin': False,
116
116
  'repayIsolatedMargin': False,
117
+ 'sandbox': True,
117
118
  'setLeverage': True,
118
119
  'setMarginMode': True,
119
120
  'setPositionMode': False,
@@ -443,6 +444,9 @@ class hyperliquid(Exchange, ImplicitAPI):
443
444
  for i in range(0, len(meta)):
444
445
  market = self.safe_dict(meta, i, {})
445
446
  marketName = self.safe_string(market, 'name')
447
+ if marketName.find('/') < 0:
448
+ # there are some weird spot markets in testnet, eg @2
449
+ continue
446
450
  marketParts = marketName.split('/')
447
451
  baseName = self.safe_string(marketParts, 0)
448
452
  quoteId = self.safe_string(marketParts, 1)
@@ -106,6 +106,7 @@ class idex(Exchange, ImplicitAPI):
106
106
  'fetchWithdrawal': True,
107
107
  'fetchWithdrawals': True,
108
108
  'reduceMargin': False,
109
+ 'sandbox': True,
109
110
  'setLeverage': False,
110
111
  'setMarginMode': False,
111
112
  'setPositionMode': False,
@@ -86,6 +86,7 @@ class krakenfutures(Exchange, ImplicitAPI):
86
86
  'fetchPremiumIndexOHLCV': False,
87
87
  'fetchTickers': True,
88
88
  'fetchTrades': True,
89
+ 'sandbox': True,
89
90
  'setLeverage': True,
90
91
  'setMarginMode': False,
91
92
  'transfer': True,
@@ -150,6 +150,7 @@ class luno(Exchange, ImplicitAPI):
150
150
  'withdrawals': 1,
151
151
  'send': 1,
152
152
  'oauth2/grant': 1,
153
+ 'beneficiaries': 1,
153
154
  # POST /api/exchange/1/move
154
155
  },
155
156
  'put': {
@@ -157,6 +158,7 @@ class luno(Exchange, ImplicitAPI):
157
158
  },
158
159
  'delete': {
159
160
  'withdrawals/{id}': 1,
161
+ 'beneficiaries/{id}': 1,
160
162
  },
161
163
  },
162
164
  },
@@ -91,6 +91,7 @@ class ndax(Exchange, ImplicitAPI):
91
91
  'fetchTradingFees': False,
92
92
  'fetchWithdrawals': True,
93
93
  'reduceMargin': False,
94
+ 'sandbox': True,
94
95
  'setLeverage': False,
95
96
  'setMarginMode': False,
96
97
  'setPositionMode': False,
ccxt/async_support/okx.py CHANGED
@@ -162,6 +162,7 @@ class okx(Exchange, ImplicitAPI):
162
162
  'fetchWithdrawalWhitelist': False,
163
163
  'reduceMargin': True,
164
164
  'repayCrossMargin': True,
165
+ 'sandbox': True,
165
166
  'setLeverage': True,
166
167
  'setMargin': False,
167
168
  'setMarginMode': True,
@@ -96,6 +96,7 @@ class phemex(Exchange, ImplicitAPI):
96
96
  'fetchTransfers': True,
97
97
  'fetchWithdrawals': True,
98
98
  'reduceMargin': False,
99
+ 'sandbox': True,
99
100
  'setLeverage': True,
100
101
  'setMargin': True,
101
102
  'setMarginMode': True,
@@ -2299,7 +2300,7 @@ class phemex(Exchange, ImplicitAPI):
2299
2300
  if lastTradeTimestamp == 0:
2300
2301
  lastTradeTimestamp = None
2301
2302
  timeInForce = self.parse_time_in_force(self.safe_string(order, 'timeInForce'))
2302
- stopPrice = self.omit_zero(self.safe_number_2(order, 'stopPx', 'stopPxRp'))
2303
+ stopPrice = self.omit_zero(self.safe_string_2(order, 'stopPx', 'stopPxRp'))
2303
2304
  postOnly = (timeInForce == 'PO')
2304
2305
  reduceOnly = self.safe_value(order, 'reduceOnly')
2305
2306
  execInst = self.safe_string(order, 'execInst')
@@ -84,6 +84,7 @@ class poloniex(Exchange, ImplicitAPI):
84
84
  'fetchTransfer': False,
85
85
  'fetchTransfers': False,
86
86
  'fetchWithdrawals': True,
87
+ 'sandbox': True,
87
88
  'transfer': True,
88
89
  'withdraw': True,
89
90
  },
@@ -101,6 +101,7 @@ class probit(Exchange, ImplicitAPI):
101
101
  'fetchWithdrawal': False,
102
102
  'fetchWithdrawals': True,
103
103
  'reduceMargin': False,
104
+ 'sandbox': True,
104
105
  'setLeverage': False,
105
106
  'setMarginMode': False,
106
107
  'setPositionMode': False,
@@ -93,6 +93,7 @@ class wavesexchange(Exchange, ImplicitAPI):
93
93
  'fetchTransfer': False,
94
94
  'fetchTransfers': False,
95
95
  'reduceMargin': False,
96
+ 'sandbox': True,
96
97
  'setLeverage': False,
97
98
  'setMarginMode': False,
98
99
  'setPositionMode': False,
ccxt/async_support/woo.py CHANGED
@@ -113,6 +113,7 @@ class woo(Exchange, ImplicitAPI):
113
113
  'fetchTransfers': True,
114
114
  'fetchWithdrawals': True,
115
115
  'reduceMargin': False,
116
+ 'sandbox': True,
116
117
  'setLeverage': True,
117
118
  'setMargin': False,
118
119
  'setPositionMode': True,
@@ -649,7 +649,7 @@ class zaif(Exchange, ImplicitAPI):
649
649
  }
650
650
 
651
651
  def custom_nonce(self):
652
- num = (self.milliseconds() / str(1000))
652
+ num = self.number_to_string(self.milliseconds() / 1000)
653
653
  nonce = float(num)
654
654
  return format(nonce, '.8f')
655
655
 
ccxt/base/errors.py CHANGED
@@ -15,6 +15,7 @@ error_hierarchy = {
15
15
  'NoChange': {
16
16
  'MarginModeAlreadySet': {},
17
17
  },
18
+ 'MarketClosed': {},
18
19
  },
19
20
  'BadResponse': {
20
21
  'NullResponse': {},
@@ -99,6 +100,10 @@ class MarginModeAlreadySet(NoChange):
99
100
  pass
100
101
 
101
102
 
103
+ class MarketClosed(OperationRejected):
104
+ pass
105
+
106
+
102
107
  class BadResponse(ExchangeError):
103
108
  pass
104
109
 
@@ -209,6 +214,7 @@ __all__ = [
209
214
  'OperationRejected',
210
215
  'NoChange',
211
216
  'MarginModeAlreadySet',
217
+ 'MarketClosed',
212
218
  'BadResponse',
213
219
  'NullResponse',
214
220
  'InsufficientFunds',