ccxt 4.2.73__py2.py3-none-any.whl → 4.2.75__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 (65) hide show
  1. ccxt/__init__.py +3 -1
  2. ccxt/abstract/tradeogre.py +16 -0
  3. ccxt/ascendex.py +5 -4
  4. ccxt/async_support/__init__.py +3 -1
  5. ccxt/async_support/ascendex.py +5 -4
  6. ccxt/async_support/base/exchange.py +1 -1
  7. ccxt/async_support/bitget.py +53 -43
  8. ccxt/async_support/bitmart.py +2 -0
  9. ccxt/async_support/bybit.py +84 -29
  10. ccxt/async_support/coinbase.py +4 -4
  11. ccxt/async_support/coinbaseinternational.py +1 -1
  12. ccxt/async_support/coinbasepro.py +2 -2
  13. ccxt/async_support/coinex.py +4 -3
  14. ccxt/async_support/coinlist.py +2 -2
  15. ccxt/async_support/cryptocom.py +2 -2
  16. ccxt/async_support/currencycom.py +2 -2
  17. ccxt/async_support/deribit.py +2 -2
  18. ccxt/async_support/gate.py +1 -0
  19. ccxt/async_support/htx.py +16 -9
  20. ccxt/async_support/huobijp.py +2 -2
  21. ccxt/async_support/hyperliquid.py +2 -1
  22. ccxt/async_support/kraken.py +3 -3
  23. ccxt/async_support/kucoin.py +3 -3
  24. ccxt/async_support/luno.py +2 -2
  25. ccxt/async_support/mexc.py +2 -2
  26. ccxt/async_support/ndax.py +2 -2
  27. ccxt/async_support/novadax.py +2 -2
  28. ccxt/async_support/okx.py +2 -2
  29. ccxt/async_support/tradeogre.py +598 -0
  30. ccxt/async_support/woo.py +2 -2
  31. ccxt/base/exchange.py +3 -3
  32. ccxt/base/types.py +8 -1
  33. ccxt/bitget.py +53 -43
  34. ccxt/bitmart.py +2 -0
  35. ccxt/bybit.py +84 -29
  36. ccxt/coinbase.py +4 -4
  37. ccxt/coinbaseinternational.py +1 -1
  38. ccxt/coinbasepro.py +2 -2
  39. ccxt/coinex.py +4 -3
  40. ccxt/coinlist.py +2 -2
  41. ccxt/cryptocom.py +2 -2
  42. ccxt/currencycom.py +2 -2
  43. ccxt/deribit.py +2 -2
  44. ccxt/gate.py +1 -0
  45. ccxt/htx.py +16 -9
  46. ccxt/huobijp.py +2 -2
  47. ccxt/hyperliquid.py +2 -1
  48. ccxt/kraken.py +3 -3
  49. ccxt/kucoin.py +3 -3
  50. ccxt/luno.py +2 -2
  51. ccxt/mexc.py +2 -2
  52. ccxt/ndax.py +2 -2
  53. ccxt/novadax.py +2 -2
  54. ccxt/okx.py +2 -2
  55. ccxt/pro/__init__.py +1 -1
  56. ccxt/pro/krakenfutures.py +8 -7
  57. ccxt/test/base/test_market.py +1 -1
  58. ccxt/test/test_async.py +16 -12
  59. ccxt/test/test_sync.py +16 -12
  60. ccxt/tradeogre.py +598 -0
  61. ccxt/woo.py +2 -2
  62. {ccxt-4.2.73.dist-info → ccxt-4.2.75.dist-info}/METADATA +11 -10
  63. {ccxt-4.2.73.dist-info → ccxt-4.2.75.dist-info}/RECORD +65 -62
  64. {ccxt-4.2.73.dist-info → ccxt-4.2.75.dist-info}/WHEEL +0 -0
  65. {ccxt-4.2.73.dist-info → ccxt-4.2.75.dist-info}/top_level.txt +0 -0
ccxt/bitget.py CHANGED
@@ -1361,10 +1361,10 @@ class bitget(Exchange, ImplicitAPI):
1361
1361
  },
1362
1362
  'fetchOHLCV': {
1363
1363
  'spot': {
1364
- 'method': 'publicSpotGetV2SpotMarketCandles', # or publicSpotGetV2SpotMarketHistoryCandles
1364
+ 'method': 'publicSpotGetV2SpotMarketCandles', # publicSpotGetV2SpotMarketCandles or publicSpotGetV2SpotMarketHistoryCandles
1365
1365
  },
1366
1366
  'swap': {
1367
- 'method': 'publicMixGetV2MixMarketCandles', # or publicMixGetV2MixMarketHistoryCandles or publicMixGetV2MixMarketHistoryIndexCandles or publicMixGetV2MixMarketHistoryMarkCandles
1367
+ 'method': 'publicMixGetV2MixMarketCandles', # publicMixGetV2MixMarketCandles or publicMixGetV2MixMarketHistoryCandles or publicMixGetV2MixMarketHistoryIndexCandles or publicMixGetV2MixMarketHistoryMarkCandles
1368
1368
  },
1369
1369
  'maxDaysPerTimeframe': {
1370
1370
  '1m': 30,
@@ -3196,11 +3196,13 @@ class bitget(Exchange, ImplicitAPI):
3196
3196
  :returns int[][]: A list of candles ordered, open, high, low, close, volume
3197
3197
  """
3198
3198
  self.load_markets()
3199
- maxLimit = 1000 # max 1000
3199
+ defaultLimit = 100 # default 100, max 1000
3200
+ maxLimitForRecentEndpoint = 1000
3201
+ maxLimitForHistoryEndpoint = 200 # note, max 1000 bars are supported for "recent-candles" endpoint, but "historical-candles" support only max 200
3200
3202
  paginate = False
3201
3203
  paginate, params = self.handle_option_and_params(params, 'fetchOHLCV', 'paginate')
3202
3204
  if paginate:
3203
- return self.fetch_paginated_call_deterministic('fetchOHLCV', symbol, since, limit, timeframe, params, maxLimit)
3205
+ return self.fetch_paginated_call_deterministic('fetchOHLCV', symbol, since, limit, timeframe, params, maxLimitForHistoryEndpoint)
3204
3206
  sandboxMode = self.safe_bool(self.options, 'sandboxMode', False)
3205
3207
  market = None
3206
3208
  if sandboxMode:
@@ -3210,28 +3212,17 @@ class bitget(Exchange, ImplicitAPI):
3210
3212
  market = self.market(symbol)
3211
3213
  marketType = 'spot' if market['spot'] else 'swap'
3212
3214
  timeframes = self.options['timeframes'][marketType]
3213
- selectedTimeframe = self.safe_string(timeframes, timeframe, timeframe)
3215
+ msInDay = 86400000
3214
3216
  duration = self.parse_timeframe(timeframe) * 1000
3215
3217
  request = {
3216
3218
  'symbol': market['id'],
3217
- 'granularity': selectedTimeframe,
3219
+ 'granularity': self.safe_string(timeframes, timeframe, timeframe),
3218
3220
  }
3219
- defaultLimit = 100 # by default, exchange returns 100 items
3220
- msInDay = 1000 * 60 * 60 * 24
3221
- if limit is not None:
3222
- limit = min(limit, maxLimit)
3223
- request['limit'] = limit
3224
3221
  until = self.safe_integer_2(params, 'until', 'till')
3222
+ limitDefined = limit is not None
3223
+ sinceDefined = since is not None
3224
+ untilDefined = until is not None
3225
3225
  params = self.omit(params, ['until', 'till'])
3226
- if until is not None:
3227
- request['endTime'] = until
3228
- if since is not None:
3229
- request['startTime'] = since
3230
- if market['spot'] and (until is None):
3231
- # for spot we need to send "entTime" too
3232
- limitForEnd = limit if (limit is not None) else defaultLimit
3233
- calculatedEnd = self.sum(since, duration * limitForEnd)
3234
- request['endTime'] = calculatedEnd
3235
3226
  response = None
3236
3227
  now = self.milliseconds()
3237
3228
  # retrievable periods listed here:
@@ -3239,33 +3230,52 @@ class bitget(Exchange, ImplicitAPI):
3239
3230
  # - https://www.bitget.com/api-doc/contract/market/Get-Candle-Data#description
3240
3231
  ohlcOptions = self.safe_dict(self.options, 'fetchOHLCV', {})
3241
3232
  retrievableDaysMap = self.safe_dict(ohlcOptions, 'maxDaysPerTimeframe', {})
3242
- maxRetrievableDaysForNonHistory = self.safe_integer(retrievableDaysMap, timeframe, 30) # default to safe minimum
3243
- endpointTsBoundary = now - maxRetrievableDaysForNonHistory * msInDay
3244
- # checks if we need history endpoint
3245
- needsHistoryEndpoint = False
3246
- displaceByLimit = 0 if (limit is None) else limit * duration
3247
- if since is not None and since < endpointTsBoundary:
3248
- # if since it earlier than the allowed diapason
3249
- needsHistoryEndpoint = True
3250
- elif until is not None and until - displaceByLimit < endpointTsBoundary:
3251
- # if until is earlier than the allowed diapason
3252
- needsHistoryEndpoint = True
3233
+ maxRetrievableDaysForRecent = self.safe_integer(retrievableDaysMap, timeframe, 30) # default to safe minimum
3234
+ endpointTsBoundary = now - maxRetrievableDaysForRecent * msInDay
3235
+ if limitDefined:
3236
+ limit = min(limit, maxLimitForRecentEndpoint)
3237
+ request['limit'] = limit
3238
+ else:
3239
+ limit = defaultLimit
3240
+ limitMultipliedDuration = limit * duration
3241
+ # exchange aligns from endTime, so it's important, not startTime
3242
+ # startTime is supported only on "recent" endpoint, not on "historical" endpoint
3243
+ calculatedStartTime = None
3244
+ calculatedEndTime = None
3245
+ if sinceDefined:
3246
+ calculatedStartTime = since
3247
+ request['startTime'] = since
3248
+ if not untilDefined:
3249
+ calculatedEndTime = self.sum(calculatedStartTime, limitMultipliedDuration)
3250
+ request['endTime'] = calculatedEndTime
3251
+ if untilDefined:
3252
+ calculatedEndTime = until
3253
+ request['endTime'] = calculatedEndTime
3254
+ if not sinceDefined:
3255
+ calculatedStartTime = calculatedEndTime - limitMultipliedDuration
3256
+ # we do not need to set "startTime" here
3257
+ historicalEndpointNeeded = (calculatedStartTime is not None) and (calculatedStartTime <= endpointTsBoundary)
3258
+ if historicalEndpointNeeded:
3259
+ # only for "historical-candles" - ensure we use correct max limit
3260
+ if limitDefined:
3261
+ request['limit'] = min(limit, maxLimitForHistoryEndpoint)
3262
+ # make request
3253
3263
  if market['spot']:
3254
- if needsHistoryEndpoint:
3264
+ # checks if we need history endpoint
3265
+ if historicalEndpointNeeded:
3255
3266
  response = self.publicSpotGetV2SpotMarketHistoryCandles(self.extend(request, params))
3256
3267
  else:
3257
3268
  response = self.publicSpotGetV2SpotMarketCandles(self.extend(request, params))
3258
3269
  else:
3259
- maxDistanceDaysForContracts = 90 # maximum 90 days allowed between start-end times
3260
- distanceError = False
3261
- if limit is not None and limit * duration > maxDistanceDaysForContracts * msInDay:
3262
- distanceError = True
3263
- elif since is not None and until is not None and until - since > maxDistanceDaysForContracts * msInDay:
3264
- distanceError = True
3265
- if distanceError:
3266
- raise BadRequest(self.id + ' fetchOHLCV() between start and end must be less than ' + str(maxDistanceDaysForContracts) + ' days')
3267
- priceType = self.safe_string(params, 'price')
3268
- params = self.omit(params, ['price'])
3270
+ maxDistanceDaysForContracts = 90 # for contract, maximum 90 days allowed between start-end times
3271
+ # only correct the request to fix 90 days if until was auto-calculated
3272
+ if sinceDefined:
3273
+ if not untilDefined:
3274
+ request['endTime'] = min(calculatedEndTime, self.sum(since, maxDistanceDaysForContracts * msInDay))
3275
+ elif calculatedEndTime - calculatedStartTime > maxDistanceDaysForContracts * msInDay:
3276
+ raise BadRequest(self.id + ' fetchOHLCV() between start and end must be less than ' + str(maxDistanceDaysForContracts) + ' days')
3277
+ priceType = None
3278
+ priceType, params = self.handle_param_string(params, 'price')
3269
3279
  productType = None
3270
3280
  productType, params = self.handle_product_type_and_params(market, params)
3271
3281
  request['productType'] = productType
@@ -3276,7 +3286,7 @@ class bitget(Exchange, ImplicitAPI):
3276
3286
  elif priceType == 'index':
3277
3287
  response = self.publicMixGetV2MixMarketHistoryIndexCandles(extended)
3278
3288
  else:
3279
- if needsHistoryEndpoint:
3289
+ if historicalEndpointNeeded:
3280
3290
  response = self.publicMixGetV2MixMarketHistoryCandles(extended)
3281
3291
  else:
3282
3292
  response = self.publicMixGetV2MixMarketCandles(extended)
ccxt/bitmart.py CHANGED
@@ -19,6 +19,7 @@ from ccxt.base.errors import InvalidAddress
19
19
  from ccxt.base.errors import InvalidOrder
20
20
  from ccxt.base.errors import OrderNotFound
21
21
  from ccxt.base.errors import NotSupported
22
+ from ccxt.base.errors import NetworkError
22
23
  from ccxt.base.errors import RateLimitExceeded
23
24
  from ccxt.base.errors import ExchangeNotAvailable
24
25
  from ccxt.base.errors import OnMaintenance
@@ -365,6 +366,7 @@ class bitmart(Exchange, ImplicitAPI):
365
366
  '70000': ExchangeError, # 200, no data
366
367
  '70001': BadRequest, # 200, request param can not be null
367
368
  '70002': BadSymbol, # 200, symbol is invalid
369
+ '70003': NetworkError, # {"code":70003,"trace":"81a9d57b63be4819b65d3065e6a4682b.105.17105295323593915","message":"net error, please try later","data":null}
368
370
  '71001': BadRequest, # 200, after is invalid
369
371
  '71002': BadRequest, # 200, before is invalid
370
372
  '71003': BadRequest, # 200, request after or before is invalid
ccxt/bybit.py CHANGED
@@ -93,6 +93,7 @@ class bybit(Exchange, ImplicitAPI):
93
93
  'fetchIsolatedBorrowRates': False,
94
94
  'fetchLedger': True,
95
95
  'fetchLeverage': True,
96
+ 'fetchLeverageTiers': True,
96
97
  'fetchMarketLeverageTiers': True,
97
98
  'fetchMarkets': True,
98
99
  'fetchMarkOHLCV': True,
@@ -6751,35 +6752,6 @@ class bybit(Exchange, ImplicitAPI):
6751
6752
  request['symbol'] = market['id']
6752
6753
  return self.fetch_derivatives_market_leverage_tiers(symbol, params)
6753
6754
 
6754
- def parse_market_leverage_tiers(self, info, market: Market = None):
6755
- #
6756
- # {
6757
- # "id": 1,
6758
- # "symbol": "BTCUSD",
6759
- # "riskLimitValue": "150",
6760
- # "maintenanceMargin": "0.5",
6761
- # "initialMargin": "1",
6762
- # "isLowestRisk": 1,
6763
- # "maxLeverage": "100.00"
6764
- # }
6765
- #
6766
- minNotional = 0
6767
- tiers = []
6768
- for i in range(0, len(info)):
6769
- item = info[i]
6770
- maxNotional = self.safe_number(item, 'riskLimitValue')
6771
- tiers.append({
6772
- 'tier': self.sum(i, 1),
6773
- 'currency': market['base'],
6774
- 'minNotional': minNotional,
6775
- 'maxNotional': maxNotional,
6776
- 'maintenanceMarginRate': self.safe_number(item, 'maintenanceMargin'),
6777
- 'maxLeverage': self.safe_number(item, 'maxLeverage'),
6778
- 'info': item,
6779
- })
6780
- minNotional = maxNotional
6781
- return tiers
6782
-
6783
6755
  def parse_trading_fee(self, fee, market: Market = None):
6784
6756
  #
6785
6757
  # {
@@ -7447,6 +7419,89 @@ class bybit(Exchange, ImplicitAPI):
7447
7419
  'datetime': self.iso8601(timestamp),
7448
7420
  })
7449
7421
 
7422
+ def fetch_leverage_tiers(self, symbols: Strings = None, params={}):
7423
+ """
7424
+ :see: https://bybit-exchange.github.io/docs/v5/market/risk-limit
7425
+ retrieve information on the maximum leverage, for different trade sizes
7426
+ :param str[] [symbols]: a list of unified market symbols
7427
+ :param dict [params]: extra parameters specific to the exchange API endpoint
7428
+ :param str [params.subType]: market subType, ['linear', 'inverse'], default is 'linear'
7429
+ :returns dict: a dictionary of `leverage tiers structures <https://docs.ccxt.com/#/?id=leverage-tiers-structure>`, indexed by market symbols
7430
+ """
7431
+ self.load_markets()
7432
+ market = None
7433
+ if symbols is not None:
7434
+ market = self.market(symbols[0])
7435
+ if market['spot']:
7436
+ raise NotSupported(self.id + ' fetchLeverageTiers() is not supported for spot market')
7437
+ subType = None
7438
+ subType, params = self.handle_sub_type_and_params('fetchTickers', market, params, 'linear')
7439
+ request = {
7440
+ 'category': subType,
7441
+ }
7442
+ response = self.publicGetV5MarketRiskLimit(self.extend(request, params))
7443
+ result = self.safe_dict(response, 'result', {})
7444
+ data = self.safe_list(result, 'list', [])
7445
+ symbols = self.market_symbols(symbols)
7446
+ return self.parse_leverage_tiers(data, symbols, 'symbol')
7447
+
7448
+ def parse_leverage_tiers(self, response, symbols: Strings = None, marketIdKey=None):
7449
+ #
7450
+ # [
7451
+ # {
7452
+ # "id": 1,
7453
+ # "symbol": "BTCUSD",
7454
+ # "riskLimitValue": "150",
7455
+ # "maintenanceMargin": "0.5",
7456
+ # "initialMargin": "1",
7457
+ # "isLowestRisk": 1,
7458
+ # "maxLeverage": "100.00"
7459
+ # }
7460
+ # ]
7461
+ #
7462
+ tiers = {}
7463
+ marketIds = self.market_ids(symbols)
7464
+ filteredResults = self.filter_by_array(response, marketIdKey, marketIds, False)
7465
+ grouped = self.group_by(filteredResults, marketIdKey)
7466
+ keys = list(grouped.keys())
7467
+ for i in range(0, len(keys)):
7468
+ marketId = keys[i]
7469
+ entry = grouped[marketId]
7470
+ market = self.safe_market(marketId, None, None, 'contract')
7471
+ symbol = market['symbol']
7472
+ tiers[symbol] = self.parse_market_leverage_tiers(entry, market)
7473
+ return tiers
7474
+
7475
+ def parse_market_leverage_tiers(self, info, market: Market = None):
7476
+ #
7477
+ # [
7478
+ # {
7479
+ # "id": 1,
7480
+ # "symbol": "BTCUSD",
7481
+ # "riskLimitValue": "150",
7482
+ # "maintenanceMargin": "0.5",
7483
+ # "initialMargin": "1",
7484
+ # "isLowestRisk": 1,
7485
+ # "maxLeverage": "100.00"
7486
+ # }
7487
+ # ]
7488
+ #
7489
+ tiers = []
7490
+ for i in range(0, len(info)):
7491
+ tier = info[i]
7492
+ marketId = self.safe_string(info, 'symbol')
7493
+ market = self.safe_market(marketId)
7494
+ tiers.append({
7495
+ 'tier': self.safe_integer(tier, 'id'),
7496
+ 'currency': market['settle'],
7497
+ 'minNotional': None,
7498
+ 'maxNotional': None,
7499
+ 'maintenanceMarginRate': self.safe_number(tier, 'maintenanceMargin'),
7500
+ 'maxLeverage': self.safe_number(tier, 'maxLeverage'),
7501
+ 'info': tier,
7502
+ })
7503
+ return tiers
7504
+
7450
7505
  def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
7451
7506
  url = self.implode_hostname(self.urls['api'][api]) + '/' + path
7452
7507
  if api == 'public':
ccxt/coinbase.py CHANGED
@@ -6,7 +6,7 @@
6
6
  from ccxt.base.exchange import Exchange
7
7
  from ccxt.abstract.coinbase import ImplicitAPI
8
8
  import hashlib
9
- from ccxt.base.types import Balances, Currency, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction
9
+ from ccxt.base.types import Account, Balances, Currency, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction
10
10
  from typing import List
11
11
  from ccxt.base.errors import ExchangeError
12
12
  from ccxt.base.errors import ArgumentsRequired
@@ -400,7 +400,7 @@ class coinbase(Exchange, ImplicitAPI):
400
400
  #
401
401
  return self.safe_timestamp_2(response, 'epoch', 'epochSeconds')
402
402
 
403
- def fetch_accounts(self, params={}):
403
+ def fetch_accounts(self, params={}) -> List[Account]:
404
404
  """
405
405
  fetch all the accounts associated with a profile
406
406
  :see: https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getaccounts
@@ -414,7 +414,7 @@ class coinbase(Exchange, ImplicitAPI):
414
414
  return self.fetch_accounts_v3(params)
415
415
  return self.fetch_accounts_v2(params)
416
416
 
417
- def fetch_accounts_v2(self, params={}):
417
+ def fetch_accounts_v2(self, params={}) -> List[Account]:
418
418
  self.load_markets()
419
419
  paginate = False
420
420
  paginate, params = self.handle_option_and_params(params, 'fetchAccounts', 'paginate')
@@ -480,7 +480,7 @@ class coinbase(Exchange, ImplicitAPI):
480
480
  accounts[lastIndex] = last
481
481
  return self.parse_accounts(data, params)
482
482
 
483
- def fetch_accounts_v3(self, params={}):
483
+ def fetch_accounts_v3(self, params={}) -> List[Account]:
484
484
  self.load_markets()
485
485
  paginate = False
486
486
  paginate, params = self.handle_option_and_params(params, 'fetchAccounts', 'paginate')
@@ -124,7 +124,7 @@ class coinbaseinternational(Exchange, ImplicitAPI):
124
124
  'test': {
125
125
  'rest': 'https://api-n5e1.coinbase.com/api',
126
126
  },
127
- 'www': 'https://www.coinbaseinternational.com/international-exchange',
127
+ 'www': 'https://international.coinbase.com',
128
128
  'doc': [
129
129
  'https://docs.cloud.coinbaseinternational.com/intx/docs',
130
130
  ],
ccxt/coinbasepro.py CHANGED
@@ -6,7 +6,7 @@
6
6
  from ccxt.base.exchange import Exchange
7
7
  from ccxt.abstract.coinbasepro import ImplicitAPI
8
8
  import hashlib
9
- from ccxt.base.types import Balances, Currency, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction
9
+ from ccxt.base.types import Account, Balances, Currency, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction
10
10
  from typing import List
11
11
  from ccxt.base.errors import ExchangeError
12
12
  from ccxt.base.errors import PermissionDenied
@@ -425,7 +425,7 @@ class coinbasepro(Exchange, ImplicitAPI):
425
425
  }))
426
426
  return result
427
427
 
428
- def fetch_accounts(self, params={}):
428
+ def fetch_accounts(self, params={}) -> List[Account]:
429
429
  """
430
430
  fetch all the accounts associated with a profile
431
431
  :see: https://docs.cloud.coinbase.com/exchange/reference/exchangerestapi_getaccounts
ccxt/coinex.py CHANGED
@@ -146,7 +146,7 @@ class coinex(Exchange, ImplicitAPI):
146
146
  'perpetualPrivate': 'https://api.coinex.com/perpetual',
147
147
  },
148
148
  'www': 'https://www.coinex.com',
149
- 'doc': 'https://github.com/coinexcom/coinex_exchange_api/wiki',
149
+ 'doc': 'https://viabtc.github.io/coinex_api_en_doc',
150
150
  'fees': 'https://www.coinex.com/fees',
151
151
  'referral': 'https://www.coinex.com/register?refer_code=yw5fz',
152
152
  },
@@ -360,6 +360,7 @@ class coinex(Exchange, ImplicitAPI):
360
360
  },
361
361
  'broad': {
362
362
  'ip not allow visit': PermissionDenied,
363
+ 'service too busy': ExchangeNotAvailable,
363
364
  },
364
365
  },
365
366
  })
@@ -4813,7 +4814,7 @@ class coinex(Exchange, ImplicitAPI):
4813
4814
  def borrow_isolated_margin(self, symbol: str, code: str, amount: float, params={}):
4814
4815
  """
4815
4816
  create a loan to borrow margin
4816
- :see: https://github.com/coinexcom/coinex_exchange_api/wiki/086margin_loan
4817
+ :see: https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot002_account017_margin_loan
4817
4818
  :param str symbol: unified market symbol, required for coinex
4818
4819
  :param str code: unified currency code of the currency to borrow
4819
4820
  :param float amount: the amount to borrow
@@ -4848,7 +4849,7 @@ class coinex(Exchange, ImplicitAPI):
4848
4849
  def repay_isolated_margin(self, symbol: str, code: str, amount, params={}):
4849
4850
  """
4850
4851
  repay borrowed margin and interest
4851
- :see: https://github.com/coinexcom/coinex_exchange_api/wiki/087margin_flat
4852
+ :see: https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot002_account018_margin_flat
4852
4853
  :param str symbol: unified market symbol, required for coinex
4853
4854
  :param str code: unified currency code of the currency to repay
4854
4855
  :param float amount: the amount to repay
ccxt/coinlist.py CHANGED
@@ -7,7 +7,7 @@ from ccxt.base.exchange import Exchange
7
7
  from ccxt.abstract.coinlist import ImplicitAPI
8
8
  import hashlib
9
9
  import math
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 Account, Balances, Currency, Int, 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
@@ -1031,7 +1031,7 @@ class coinlist(Exchange, ImplicitAPI):
1031
1031
  'taker': takerFees,
1032
1032
  }
1033
1033
 
1034
- def fetch_accounts(self, params={}):
1034
+ def fetch_accounts(self, params={}) -> List[Account]:
1035
1035
  """
1036
1036
  fetch all the accounts associated with a profile
1037
1037
  :see: https://trade-docs.coinlist.co/?javascript--nodejs#list-accounts
ccxt/cryptocom.py CHANGED
@@ -6,7 +6,7 @@
6
6
  from ccxt.base.exchange import Exchange
7
7
  from ccxt.abstract.cryptocom import ImplicitAPI
8
8
  import hashlib
9
- from ccxt.base.types import Balances, Currency, Int, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction
9
+ from ccxt.base.types import Account, Balances, Currency, Int, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction
10
10
  from typing import List
11
11
  from ccxt.base.errors import ExchangeError
12
12
  from ccxt.base.errors import PermissionDenied
@@ -2298,7 +2298,7 @@ class cryptocom(Exchange, ImplicitAPI):
2298
2298
  }
2299
2299
  return self.safe_string(ledgerType, type, type)
2300
2300
 
2301
- def fetch_accounts(self, params={}):
2301
+ def fetch_accounts(self, params={}) -> List[Account]:
2302
2302
  """
2303
2303
  fetch all the accounts associated with a profile
2304
2304
  :see: https://exchange-docs.crypto.com/exchange/v1/rest-ws/index.html#private-get-accounts
ccxt/currencycom.py CHANGED
@@ -6,7 +6,7 @@
6
6
  from ccxt.base.exchange import Exchange
7
7
  from ccxt.abstract.currencycom import ImplicitAPI
8
8
  import hashlib
9
- from ccxt.base.types import Balances, Currency, Int, Leverage, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction
9
+ from ccxt.base.types import Account, Balances, Currency, Int, Leverage, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction
10
10
  from typing import List
11
11
  from ccxt.base.errors import ExchangeError
12
12
  from ccxt.base.errors import ArgumentsRequired
@@ -574,7 +574,7 @@ class currencycom(Exchange, ImplicitAPI):
574
574
  })
575
575
  return result
576
576
 
577
- def fetch_accounts(self, params={}):
577
+ def fetch_accounts(self, params={}) -> List[Account]:
578
578
  """
579
579
  fetch all the accounts associated with a profile
580
580
  :see: https://apitradedoc.currency.com/swagger-ui.html#/rest-api/accountUsingGET
ccxt/deribit.py CHANGED
@@ -6,7 +6,7 @@
6
6
  from ccxt.base.exchange import Exchange
7
7
  from ccxt.abstract.deribit import ImplicitAPI
8
8
  import hashlib
9
- from ccxt.base.types import Balances, Currency, Greeks, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction, TransferEntry
9
+ from ccxt.base.types import Account, Balances, Currency, Greeks, Int, 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
@@ -682,7 +682,7 @@ class deribit(Exchange, ImplicitAPI):
682
682
  'info': response,
683
683
  }
684
684
 
685
- def fetch_accounts(self, params={}):
685
+ def fetch_accounts(self, params={}) -> List[Account]:
686
686
  """
687
687
  fetch all the accounts associated with a profile
688
688
  :see: https://docs.deribit.com/#private-get_subaccounts
ccxt/gate.py CHANGED
@@ -4010,6 +4010,7 @@ class gate(Exchange, ImplicitAPI):
4010
4010
  'failed': 'canceled',
4011
4011
  'expired': 'canceled',
4012
4012
  'finished': 'closed',
4013
+ 'finish': 'closed',
4013
4014
  'succeeded': 'closed',
4014
4015
  }
4015
4016
  return self.safe_string(statuses, status, status)
ccxt/htx.py CHANGED
@@ -6,7 +6,7 @@
6
6
  from ccxt.base.exchange import Exchange
7
7
  from ccxt.abstract.htx import ImplicitAPI
8
8
  import hashlib
9
- from ccxt.base.types import Balances, Currency, Int, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction, TransferEntry
9
+ from ccxt.base.types import Account, Balances, Currency, Int, 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
@@ -967,6 +967,9 @@ class htx(Exchange, ImplicitAPI):
967
967
  },
968
968
  },
969
969
  },
970
+ 'fetchOHLCV': {
971
+ 'useHistoricalEndpointForSpot': True,
972
+ },
970
973
  'withdraw': {
971
974
  'includeFee': False,
972
975
  },
@@ -2828,6 +2831,7 @@ class htx(Exchange, ImplicitAPI):
2828
2831
  :param int [limit]: the maximum amount of candles to fetch
2829
2832
  :param dict [params]: extra parameters specific to the exchange API endpoint
2830
2833
  :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
2834
+ :param str [params.useHistoricalEndpointForSpot]: True/false - whether use the historical candles endpoint for spot markets or default klines endpoint
2831
2835
  :returns int[][]: A list of candles ordered, open, high, low, close, volume
2832
2836
  """
2833
2837
  self.load_markets()
@@ -2905,16 +2909,19 @@ class htx(Exchange, ImplicitAPI):
2905
2909
  else:
2906
2910
  response = self.contractPublicGetLinearSwapExMarketHistoryKline(self.extend(request, params))
2907
2911
  else:
2908
- if since is not None:
2909
- request['from'] = self.parse_to_int(since / 1000)
2910
- if limit is not None:
2911
- request['size'] = limit # max 2000
2912
2912
  request['symbol'] = market['id']
2913
- if timeframe == '1M' or timeframe == '1y':
2914
- # for some reason 1M and 1Y does not work with the regular endpoint
2915
- # https://github.com/ccxt/ccxt/issues/18006
2913
+ useHistorical = None
2914
+ useHistorical, params = self.handle_option_and_params(params, 'fetchOHLCV', 'useHistoricalEndpointForSpot', True)
2915
+ if not useHistorical:
2916
+ # `limit` only available for the self endpoint
2917
+ if limit is not None:
2918
+ request['size'] = limit # max 2000
2916
2919
  response = self.spotPublicGetMarketHistoryKline(self.extend(request, params))
2917
2920
  else:
2921
+ # `since` only available for the self endpoint
2922
+ if since is not None:
2923
+ # default 150 bars
2924
+ request['from'] = self.parse_to_int(since / 1000)
2918
2925
  response = self.spotPublicGetMarketHistoryCandles(self.extend(request, params))
2919
2926
  #
2920
2927
  # {
@@ -2931,7 +2938,7 @@ class htx(Exchange, ImplicitAPI):
2931
2938
  data = self.safe_value(response, 'data', [])
2932
2939
  return self.parse_ohlcvs(data, market, timeframe, since, limit)
2933
2940
 
2934
- def fetch_accounts(self, params={}):
2941
+ def fetch_accounts(self, params={}) -> List[Account]:
2935
2942
  """
2936
2943
  fetch all the accounts associated with a profile
2937
2944
  :param dict [params]: extra parameters specific to the exchange API endpoint
ccxt/huobijp.py CHANGED
@@ -6,7 +6,7 @@
6
6
  from ccxt.base.exchange import Exchange
7
7
  from ccxt.abstract.huobijp import ImplicitAPI
8
8
  import hashlib
9
- from ccxt.base.types import Balances, Currency, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction
9
+ from ccxt.base.types import Account, Balances, Currency, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction
10
10
  from typing import List
11
11
  from ccxt.base.errors import ExchangeError
12
12
  from ccxt.base.errors import PermissionDenied
@@ -944,7 +944,7 @@ class huobijp(Exchange, ImplicitAPI):
944
944
  data = self.safe_value(response, 'data', [])
945
945
  return self.parse_ohlcvs(data, market, timeframe, since, limit)
946
946
 
947
- def fetch_accounts(self, params={}):
947
+ def fetch_accounts(self, params={}) -> List[Account]:
948
948
  """
949
949
  fetch all the accounts associated with a profile
950
950
  :param dict [params]: extra parameters specific to the exchange API endpoint
ccxt/hyperliquid.py CHANGED
@@ -368,7 +368,7 @@ class hyperliquid(Exchange, ImplicitAPI):
368
368
  'optionType': None,
369
369
  'precision': {
370
370
  'amount': self.parse_number(self.parse_precision(self.safe_string(market, 'szDecimals'))), # decimal places
371
- 'price': self.parse_number('5'), # significant digits
371
+ 'price': 5, # significant digits
372
372
  },
373
373
  'limits': {
374
374
  'leverage': {
@@ -824,6 +824,7 @@ class hyperliquid(Exchange, ImplicitAPI):
824
824
  if price is None:
825
825
  raise ArgumentsRequired(self.id + ' market orders require price to calculate the max slippage price. Default slippage can be set in options(default is 5%).')
826
826
  px = Precise.string_mul(price, Precise.string_add('1', slippage)) if (isBuy) else Precise.string_mul(price, Precise.string_sub('1', slippage))
827
+ px = self.price_to_precision(symbol, px) # round after adding slippage
827
828
  else:
828
829
  px = self.price_to_precision(symbol, price)
829
830
  sz = self.amount_to_precision(symbol, amount)
ccxt/kraken.py CHANGED
@@ -2586,7 +2586,7 @@ class kraken(Exchange, ImplicitAPI):
2586
2586
  # todo unify parsePosition/parsePositions
2587
2587
  return result
2588
2588
 
2589
- def parse_account(self, account):
2589
+ def parse_account_type(self, account):
2590
2590
  accountByType = {
2591
2591
  'spot': 'Spot Wallet',
2592
2592
  'swap': 'Futures Wallet',
@@ -2618,8 +2618,8 @@ class kraken(Exchange, ImplicitAPI):
2618
2618
  """
2619
2619
  self.load_markets()
2620
2620
  currency = self.currency(code)
2621
- fromAccount = self.parse_account(fromAccount)
2622
- toAccount = self.parse_account(toAccount)
2621
+ fromAccount = self.parse_account_type(fromAccount)
2622
+ toAccount = self.parse_account_type(toAccount)
2623
2623
  request = {
2624
2624
  'amount': self.currency_to_precision(code, amount),
2625
2625
  'from': fromAccount,
ccxt/kucoin.py CHANGED
@@ -8,7 +8,7 @@ from ccxt.abstract.kucoin import ImplicitAPI
8
8
  import hashlib
9
9
  import math
10
10
  import json
11
- from ccxt.base.types import Balances, Currency, Int, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction, TransferEntry
11
+ from ccxt.base.types import Account, Balances, Currency, Int, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction, TransferEntry
12
12
  from typing import List
13
13
  from ccxt.base.errors import ExchangeError
14
14
  from ccxt.base.errors import PermissionDenied
@@ -479,7 +479,7 @@ class kucoin(Exchange, ImplicitAPI):
479
479
  '400006': AuthenticationError,
480
480
  '400007': AuthenticationError,
481
481
  '400008': NotSupported,
482
- '400100': BadRequest,
482
+ '400100': InsufficientFunds, # {"msg":"account.available.amount","code":"400100"}
483
483
  '400200': InvalidOrder, # {"code":"400200","msg":"Forbidden to place an order"}
484
484
  '400350': InvalidOrder, # {"code":"400350","msg":"Upper limit for holding: 10,000USDT, you can still buy 10,000USDT worth of coin."}
485
485
  '400370': InvalidOrder, # {"code":"400370","msg":"Max. price: 0.02500000000000000000"}
@@ -1226,7 +1226,7 @@ class kucoin(Exchange, ImplicitAPI):
1226
1226
  }
1227
1227
  return result
1228
1228
 
1229
- def fetch_accounts(self, params={}):
1229
+ def fetch_accounts(self, params={}) -> List[Account]:
1230
1230
  """
1231
1231
  fetch all the accounts associated with a profile
1232
1232
  :see: https://docs.kucoin.com/#list-accounts