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/__init__.py CHANGED
@@ -22,7 +22,7 @@
22
22
 
23
23
  # ----------------------------------------------------------------------------
24
24
 
25
- __version__ = '4.2.73'
25
+ __version__ = '4.2.75'
26
26
 
27
27
  # ----------------------------------------------------------------------------
28
28
 
@@ -173,6 +173,7 @@ from ccxt.poloniexfutures import poloniexfutures # noqa: F4
173
173
  from ccxt.probit import probit # noqa: F401
174
174
  from ccxt.timex import timex # noqa: F401
175
175
  from ccxt.tokocrypto import tokocrypto # noqa: F401
176
+ from ccxt.tradeogre import tradeogre # noqa: F401
176
177
  from ccxt.upbit import upbit # noqa: F401
177
178
  from ccxt.wavesexchange import wavesexchange # noqa: F401
178
179
  from ccxt.wazirx import wazirx # noqa: F401
@@ -277,6 +278,7 @@ exchanges = [
277
278
  'probit',
278
279
  'timex',
279
280
  'tokocrypto',
281
+ 'tradeogre',
280
282
  'upbit',
281
283
  'wavesexchange',
282
284
  'wazirx',
@@ -0,0 +1,16 @@
1
+ from ccxt.base.types import Entry
2
+
3
+
4
+ class ImplicitAPI:
5
+ public_get_markets = publicGetMarkets = Entry('markets', 'public', 'GET', {'cost': 1})
6
+ public_get_orders_market = publicGetOrdersMarket = Entry('orders/{market}', 'public', 'GET', {'cost': 1})
7
+ public_get_ticker_market = publicGetTickerMarket = Entry('ticker/{market}', 'public', 'GET', {'cost': 1})
8
+ public_get_history_market = publicGetHistoryMarket = Entry('history/{market}', 'public', 'GET', {'cost': 1})
9
+ private_get_account_balance = privateGetAccountBalance = Entry('account/balance', 'private', 'GET', {'cost': 1})
10
+ private_get_account_balances = privateGetAccountBalances = Entry('account/balances', 'private', 'GET', {'cost': 1})
11
+ private_get_account_order_uuid = privateGetAccountOrderUuid = Entry('account/order/{uuid}', 'private', 'GET', {'cost': 1})
12
+ private_post_order_buy = privatePostOrderBuy = Entry('order/buy', 'private', 'POST', {'cost': 1})
13
+ private_post_order_sell = privatePostOrderSell = Entry('order/sell', 'private', 'POST', {'cost': 1})
14
+ private_post_order_cancel = privatePostOrderCancel = Entry('order/cancel', 'private', 'POST', {'cost': 1})
15
+ private_post_orders = privatePostOrders = Entry('orders', 'private', 'POST', {'cost': 1})
16
+ private_post_account_orders = privatePostAccountOrders = Entry('account/orders', 'private', 'POST', {'cost': 1})
ccxt/ascendex.py CHANGED
@@ -6,7 +6,7 @@
6
6
  from ccxt.base.exchange import Exchange
7
7
  from ccxt.abstract.ascendex import ImplicitAPI
8
8
  import hashlib
9
- from ccxt.base.types import Balances, Currency, Int, Leverage, Leverages, MarginMode, MarginModes, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction, TransferEntry
9
+ from ccxt.base.types import Account, Balances, Currency, Int, Leverage, Leverages, MarginMode, MarginModes, 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
@@ -714,7 +714,7 @@ class ascendex(Exchange, ImplicitAPI):
714
714
  data = self.safe_value(response, 'data')
715
715
  return self.safe_integer(data, 'requestReceiveAt')
716
716
 
717
- def fetch_accounts(self, params={}):
717
+ def fetch_accounts(self, params={}) -> List[Account]:
718
718
  """
719
719
  fetch all the accounts associated with a profile
720
720
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -747,7 +747,7 @@ class ascendex(Exchange, ImplicitAPI):
747
747
  {
748
748
  'id': accountGroup,
749
749
  'type': None,
750
- 'currency': None,
750
+ 'code': None,
751
751
  'info': response,
752
752
  },
753
753
  ]
@@ -2590,7 +2590,8 @@ class ascendex(Exchange, ImplicitAPI):
2590
2590
  notional = self.safe_string(position, 'buyOpenOrderNotional')
2591
2591
  if Precise.string_eq(notional, '0'):
2592
2592
  notional = self.safe_string(position, 'sellOpenOrderNotional')
2593
- marginMode = self.safe_string(position, 'marginType')
2593
+ marginType = self.safe_string(position, 'marginType')
2594
+ marginMode = 'cross' if (marginType == 'crossed') else 'isolated'
2594
2595
  collateral = None
2595
2596
  if marginMode == 'isolated':
2596
2597
  collateral = self.safe_string(position, 'isolatedMargin')
@@ -4,7 +4,7 @@
4
4
 
5
5
  # -----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.2.73'
7
+ __version__ = '4.2.75'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
 
@@ -153,6 +153,7 @@ from ccxt.async_support.poloniexfutures import poloniexfutures
153
153
  from ccxt.async_support.probit import probit # noqa: F401
154
154
  from ccxt.async_support.timex import timex # noqa: F401
155
155
  from ccxt.async_support.tokocrypto import tokocrypto # noqa: F401
156
+ from ccxt.async_support.tradeogre import tradeogre # noqa: F401
156
157
  from ccxt.async_support.upbit import upbit # noqa: F401
157
158
  from ccxt.async_support.wavesexchange import wavesexchange # noqa: F401
158
159
  from ccxt.async_support.wazirx import wazirx # noqa: F401
@@ -257,6 +258,7 @@ exchanges = [
257
258
  'probit',
258
259
  'timex',
259
260
  'tokocrypto',
261
+ 'tradeogre',
260
262
  'upbit',
261
263
  'wavesexchange',
262
264
  'wazirx',
@@ -6,7 +6,7 @@
6
6
  from ccxt.async_support.base.exchange import Exchange
7
7
  from ccxt.abstract.ascendex import ImplicitAPI
8
8
  import hashlib
9
- from ccxt.base.types import Balances, Currency, Int, Leverage, Leverages, MarginMode, MarginModes, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction, TransferEntry
9
+ from ccxt.base.types import Account, Balances, Currency, Int, Leverage, Leverages, MarginMode, MarginModes, 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
@@ -714,7 +714,7 @@ class ascendex(Exchange, ImplicitAPI):
714
714
  data = self.safe_value(response, 'data')
715
715
  return self.safe_integer(data, 'requestReceiveAt')
716
716
 
717
- async def fetch_accounts(self, params={}):
717
+ async def fetch_accounts(self, params={}) -> List[Account]:
718
718
  """
719
719
  fetch all the accounts associated with a profile
720
720
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -747,7 +747,7 @@ class ascendex(Exchange, ImplicitAPI):
747
747
  {
748
748
  'id': accountGroup,
749
749
  'type': None,
750
- 'currency': None,
750
+ 'code': None,
751
751
  'info': response,
752
752
  },
753
753
  ]
@@ -2590,7 +2590,8 @@ class ascendex(Exchange, ImplicitAPI):
2590
2590
  notional = self.safe_string(position, 'buyOpenOrderNotional')
2591
2591
  if Precise.string_eq(notional, '0'):
2592
2592
  notional = self.safe_string(position, 'sellOpenOrderNotional')
2593
- marginMode = self.safe_string(position, 'marginType')
2593
+ marginType = self.safe_string(position, 'marginType')
2594
+ marginMode = 'cross' if (marginType == 'crossed') else 'isolated'
2594
2595
  collateral = None
2595
2596
  if marginMode == 'isolated':
2596
2597
  collateral = self.safe_string(position, 'isolatedMargin')
@@ -2,7 +2,7 @@
2
2
 
3
3
  # -----------------------------------------------------------------------------
4
4
 
5
- __version__ = '4.2.73'
5
+ __version__ = '4.2.75'
6
6
 
7
7
  # -----------------------------------------------------------------------------
8
8
 
@@ -1362,10 +1362,10 @@ class bitget(Exchange, ImplicitAPI):
1362
1362
  },
1363
1363
  'fetchOHLCV': {
1364
1364
  'spot': {
1365
- 'method': 'publicSpotGetV2SpotMarketCandles', # or publicSpotGetV2SpotMarketHistoryCandles
1365
+ 'method': 'publicSpotGetV2SpotMarketCandles', # publicSpotGetV2SpotMarketCandles or publicSpotGetV2SpotMarketHistoryCandles
1366
1366
  },
1367
1367
  'swap': {
1368
- 'method': 'publicMixGetV2MixMarketCandles', # or publicMixGetV2MixMarketHistoryCandles or publicMixGetV2MixMarketHistoryIndexCandles or publicMixGetV2MixMarketHistoryMarkCandles
1368
+ 'method': 'publicMixGetV2MixMarketCandles', # publicMixGetV2MixMarketCandles or publicMixGetV2MixMarketHistoryCandles or publicMixGetV2MixMarketHistoryIndexCandles or publicMixGetV2MixMarketHistoryMarkCandles
1369
1369
  },
1370
1370
  'maxDaysPerTimeframe': {
1371
1371
  '1m': 30,
@@ -3197,11 +3197,13 @@ class bitget(Exchange, ImplicitAPI):
3197
3197
  :returns int[][]: A list of candles ordered, open, high, low, close, volume
3198
3198
  """
3199
3199
  await self.load_markets()
3200
- maxLimit = 1000 # max 1000
3200
+ defaultLimit = 100 # default 100, max 1000
3201
+ maxLimitForRecentEndpoint = 1000
3202
+ maxLimitForHistoryEndpoint = 200 # note, max 1000 bars are supported for "recent-candles" endpoint, but "historical-candles" support only max 200
3201
3203
  paginate = False
3202
3204
  paginate, params = self.handle_option_and_params(params, 'fetchOHLCV', 'paginate')
3203
3205
  if paginate:
3204
- return await self.fetch_paginated_call_deterministic('fetchOHLCV', symbol, since, limit, timeframe, params, maxLimit)
3206
+ return await self.fetch_paginated_call_deterministic('fetchOHLCV', symbol, since, limit, timeframe, params, maxLimitForHistoryEndpoint)
3205
3207
  sandboxMode = self.safe_bool(self.options, 'sandboxMode', False)
3206
3208
  market = None
3207
3209
  if sandboxMode:
@@ -3211,28 +3213,17 @@ class bitget(Exchange, ImplicitAPI):
3211
3213
  market = self.market(symbol)
3212
3214
  marketType = 'spot' if market['spot'] else 'swap'
3213
3215
  timeframes = self.options['timeframes'][marketType]
3214
- selectedTimeframe = self.safe_string(timeframes, timeframe, timeframe)
3216
+ msInDay = 86400000
3215
3217
  duration = self.parse_timeframe(timeframe) * 1000
3216
3218
  request = {
3217
3219
  'symbol': market['id'],
3218
- 'granularity': selectedTimeframe,
3220
+ 'granularity': self.safe_string(timeframes, timeframe, timeframe),
3219
3221
  }
3220
- defaultLimit = 100 # by default, exchange returns 100 items
3221
- msInDay = 1000 * 60 * 60 * 24
3222
- if limit is not None:
3223
- limit = min(limit, maxLimit)
3224
- request['limit'] = limit
3225
3222
  until = self.safe_integer_2(params, 'until', 'till')
3223
+ limitDefined = limit is not None
3224
+ sinceDefined = since is not None
3225
+ untilDefined = until is not None
3226
3226
  params = self.omit(params, ['until', 'till'])
3227
- if until is not None:
3228
- request['endTime'] = until
3229
- if since is not None:
3230
- request['startTime'] = since
3231
- if market['spot'] and (until is None):
3232
- # for spot we need to send "entTime" too
3233
- limitForEnd = limit if (limit is not None) else defaultLimit
3234
- calculatedEnd = self.sum(since, duration * limitForEnd)
3235
- request['endTime'] = calculatedEnd
3236
3227
  response = None
3237
3228
  now = self.milliseconds()
3238
3229
  # retrievable periods listed here:
@@ -3240,33 +3231,52 @@ class bitget(Exchange, ImplicitAPI):
3240
3231
  # - https://www.bitget.com/api-doc/contract/market/Get-Candle-Data#description
3241
3232
  ohlcOptions = self.safe_dict(self.options, 'fetchOHLCV', {})
3242
3233
  retrievableDaysMap = self.safe_dict(ohlcOptions, 'maxDaysPerTimeframe', {})
3243
- maxRetrievableDaysForNonHistory = self.safe_integer(retrievableDaysMap, timeframe, 30) # default to safe minimum
3244
- endpointTsBoundary = now - maxRetrievableDaysForNonHistory * msInDay
3245
- # checks if we need history endpoint
3246
- needsHistoryEndpoint = False
3247
- displaceByLimit = 0 if (limit is None) else limit * duration
3248
- if since is not None and since < endpointTsBoundary:
3249
- # if since it earlier than the allowed diapason
3250
- needsHistoryEndpoint = True
3251
- elif until is not None and until - displaceByLimit < endpointTsBoundary:
3252
- # if until is earlier than the allowed diapason
3253
- needsHistoryEndpoint = True
3234
+ maxRetrievableDaysForRecent = self.safe_integer(retrievableDaysMap, timeframe, 30) # default to safe minimum
3235
+ endpointTsBoundary = now - maxRetrievableDaysForRecent * msInDay
3236
+ if limitDefined:
3237
+ limit = min(limit, maxLimitForRecentEndpoint)
3238
+ request['limit'] = limit
3239
+ else:
3240
+ limit = defaultLimit
3241
+ limitMultipliedDuration = limit * duration
3242
+ # exchange aligns from endTime, so it's important, not startTime
3243
+ # startTime is supported only on "recent" endpoint, not on "historical" endpoint
3244
+ calculatedStartTime = None
3245
+ calculatedEndTime = None
3246
+ if sinceDefined:
3247
+ calculatedStartTime = since
3248
+ request['startTime'] = since
3249
+ if not untilDefined:
3250
+ calculatedEndTime = self.sum(calculatedStartTime, limitMultipliedDuration)
3251
+ request['endTime'] = calculatedEndTime
3252
+ if untilDefined:
3253
+ calculatedEndTime = until
3254
+ request['endTime'] = calculatedEndTime
3255
+ if not sinceDefined:
3256
+ calculatedStartTime = calculatedEndTime - limitMultipliedDuration
3257
+ # we do not need to set "startTime" here
3258
+ historicalEndpointNeeded = (calculatedStartTime is not None) and (calculatedStartTime <= endpointTsBoundary)
3259
+ if historicalEndpointNeeded:
3260
+ # only for "historical-candles" - ensure we use correct max limit
3261
+ if limitDefined:
3262
+ request['limit'] = min(limit, maxLimitForHistoryEndpoint)
3263
+ # make request
3254
3264
  if market['spot']:
3255
- if needsHistoryEndpoint:
3265
+ # checks if we need history endpoint
3266
+ if historicalEndpointNeeded:
3256
3267
  response = await self.publicSpotGetV2SpotMarketHistoryCandles(self.extend(request, params))
3257
3268
  else:
3258
3269
  response = await self.publicSpotGetV2SpotMarketCandles(self.extend(request, params))
3259
3270
  else:
3260
- maxDistanceDaysForContracts = 90 # maximum 90 days allowed between start-end times
3261
- distanceError = False
3262
- if limit is not None and limit * duration > maxDistanceDaysForContracts * msInDay:
3263
- distanceError = True
3264
- elif since is not None and until is not None and until - since > maxDistanceDaysForContracts * msInDay:
3265
- distanceError = True
3266
- if distanceError:
3267
- raise BadRequest(self.id + ' fetchOHLCV() between start and end must be less than ' + str(maxDistanceDaysForContracts) + ' days')
3268
- priceType = self.safe_string(params, 'price')
3269
- params = self.omit(params, ['price'])
3271
+ maxDistanceDaysForContracts = 90 # for contract, maximum 90 days allowed between start-end times
3272
+ # only correct the request to fix 90 days if until was auto-calculated
3273
+ if sinceDefined:
3274
+ if not untilDefined:
3275
+ request['endTime'] = min(calculatedEndTime, self.sum(since, maxDistanceDaysForContracts * msInDay))
3276
+ elif calculatedEndTime - calculatedStartTime > maxDistanceDaysForContracts * msInDay:
3277
+ raise BadRequest(self.id + ' fetchOHLCV() between start and end must be less than ' + str(maxDistanceDaysForContracts) + ' days')
3278
+ priceType = None
3279
+ priceType, params = self.handle_param_string(params, 'price')
3270
3280
  productType = None
3271
3281
  productType, params = self.handle_product_type_and_params(market, params)
3272
3282
  request['productType'] = productType
@@ -3277,7 +3287,7 @@ class bitget(Exchange, ImplicitAPI):
3277
3287
  elif priceType == 'index':
3278
3288
  response = await self.publicMixGetV2MixMarketHistoryIndexCandles(extended)
3279
3289
  else:
3280
- if needsHistoryEndpoint:
3290
+ if historicalEndpointNeeded:
3281
3291
  response = await self.publicMixGetV2MixMarketHistoryCandles(extended)
3282
3292
  else:
3283
3293
  response = await self.publicMixGetV2MixMarketCandles(extended)
@@ -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
@@ -94,6 +94,7 @@ class bybit(Exchange, ImplicitAPI):
94
94
  'fetchIsolatedBorrowRates': False,
95
95
  'fetchLedger': True,
96
96
  'fetchLeverage': True,
97
+ 'fetchLeverageTiers': True,
97
98
  'fetchMarketLeverageTiers': True,
98
99
  'fetchMarkets': True,
99
100
  'fetchMarkOHLCV': True,
@@ -6752,35 +6753,6 @@ class bybit(Exchange, ImplicitAPI):
6752
6753
  request['symbol'] = market['id']
6753
6754
  return await self.fetch_derivatives_market_leverage_tiers(symbol, params)
6754
6755
 
6755
- def parse_market_leverage_tiers(self, info, market: Market = None):
6756
- #
6757
- # {
6758
- # "id": 1,
6759
- # "symbol": "BTCUSD",
6760
- # "riskLimitValue": "150",
6761
- # "maintenanceMargin": "0.5",
6762
- # "initialMargin": "1",
6763
- # "isLowestRisk": 1,
6764
- # "maxLeverage": "100.00"
6765
- # }
6766
- #
6767
- minNotional = 0
6768
- tiers = []
6769
- for i in range(0, len(info)):
6770
- item = info[i]
6771
- maxNotional = self.safe_number(item, 'riskLimitValue')
6772
- tiers.append({
6773
- 'tier': self.sum(i, 1),
6774
- 'currency': market['base'],
6775
- 'minNotional': minNotional,
6776
- 'maxNotional': maxNotional,
6777
- 'maintenanceMarginRate': self.safe_number(item, 'maintenanceMargin'),
6778
- 'maxLeverage': self.safe_number(item, 'maxLeverage'),
6779
- 'info': item,
6780
- })
6781
- minNotional = maxNotional
6782
- return tiers
6783
-
6784
6756
  def parse_trading_fee(self, fee, market: Market = None):
6785
6757
  #
6786
6758
  # {
@@ -7448,6 +7420,89 @@ class bybit(Exchange, ImplicitAPI):
7448
7420
  'datetime': self.iso8601(timestamp),
7449
7421
  })
7450
7422
 
7423
+ async def fetch_leverage_tiers(self, symbols: Strings = None, params={}):
7424
+ """
7425
+ :see: https://bybit-exchange.github.io/docs/v5/market/risk-limit
7426
+ retrieve information on the maximum leverage, for different trade sizes
7427
+ :param str[] [symbols]: a list of unified market symbols
7428
+ :param dict [params]: extra parameters specific to the exchange API endpoint
7429
+ :param str [params.subType]: market subType, ['linear', 'inverse'], default is 'linear'
7430
+ :returns dict: a dictionary of `leverage tiers structures <https://docs.ccxt.com/#/?id=leverage-tiers-structure>`, indexed by market symbols
7431
+ """
7432
+ await self.load_markets()
7433
+ market = None
7434
+ if symbols is not None:
7435
+ market = self.market(symbols[0])
7436
+ if market['spot']:
7437
+ raise NotSupported(self.id + ' fetchLeverageTiers() is not supported for spot market')
7438
+ subType = None
7439
+ subType, params = self.handle_sub_type_and_params('fetchTickers', market, params, 'linear')
7440
+ request = {
7441
+ 'category': subType,
7442
+ }
7443
+ response = await self.publicGetV5MarketRiskLimit(self.extend(request, params))
7444
+ result = self.safe_dict(response, 'result', {})
7445
+ data = self.safe_list(result, 'list', [])
7446
+ symbols = self.market_symbols(symbols)
7447
+ return self.parse_leverage_tiers(data, symbols, 'symbol')
7448
+
7449
+ def parse_leverage_tiers(self, response, symbols: Strings = None, marketIdKey=None):
7450
+ #
7451
+ # [
7452
+ # {
7453
+ # "id": 1,
7454
+ # "symbol": "BTCUSD",
7455
+ # "riskLimitValue": "150",
7456
+ # "maintenanceMargin": "0.5",
7457
+ # "initialMargin": "1",
7458
+ # "isLowestRisk": 1,
7459
+ # "maxLeverage": "100.00"
7460
+ # }
7461
+ # ]
7462
+ #
7463
+ tiers = {}
7464
+ marketIds = self.market_ids(symbols)
7465
+ filteredResults = self.filter_by_array(response, marketIdKey, marketIds, False)
7466
+ grouped = self.group_by(filteredResults, marketIdKey)
7467
+ keys = list(grouped.keys())
7468
+ for i in range(0, len(keys)):
7469
+ marketId = keys[i]
7470
+ entry = grouped[marketId]
7471
+ market = self.safe_market(marketId, None, None, 'contract')
7472
+ symbol = market['symbol']
7473
+ tiers[symbol] = self.parse_market_leverage_tiers(entry, market)
7474
+ return tiers
7475
+
7476
+ def parse_market_leverage_tiers(self, info, market: Market = None):
7477
+ #
7478
+ # [
7479
+ # {
7480
+ # "id": 1,
7481
+ # "symbol": "BTCUSD",
7482
+ # "riskLimitValue": "150",
7483
+ # "maintenanceMargin": "0.5",
7484
+ # "initialMargin": "1",
7485
+ # "isLowestRisk": 1,
7486
+ # "maxLeverage": "100.00"
7487
+ # }
7488
+ # ]
7489
+ #
7490
+ tiers = []
7491
+ for i in range(0, len(info)):
7492
+ tier = info[i]
7493
+ marketId = self.safe_string(info, 'symbol')
7494
+ market = self.safe_market(marketId)
7495
+ tiers.append({
7496
+ 'tier': self.safe_integer(tier, 'id'),
7497
+ 'currency': market['settle'],
7498
+ 'minNotional': None,
7499
+ 'maxNotional': None,
7500
+ 'maintenanceMarginRate': self.safe_number(tier, 'maintenanceMargin'),
7501
+ 'maxLeverage': self.safe_number(tier, 'maxLeverage'),
7502
+ 'info': tier,
7503
+ })
7504
+ return tiers
7505
+
7451
7506
  def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
7452
7507
  url = self.implode_hostname(self.urls['api'][api]) + '/' + path
7453
7508
  if api == 'public':
@@ -7,7 +7,7 @@ from ccxt.async_support.base.exchange import Exchange
7
7
  from ccxt.abstract.coinbase import ImplicitAPI
8
8
  import asyncio
9
9
  import hashlib
10
- from ccxt.base.types import Balances, Currency, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction
10
+ from ccxt.base.types import Account, Balances, Currency, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction
11
11
  from typing import List
12
12
  from ccxt.base.errors import ExchangeError
13
13
  from ccxt.base.errors import ArgumentsRequired
@@ -401,7 +401,7 @@ class coinbase(Exchange, ImplicitAPI):
401
401
  #
402
402
  return self.safe_timestamp_2(response, 'epoch', 'epochSeconds')
403
403
 
404
- async def fetch_accounts(self, params={}):
404
+ async def fetch_accounts(self, params={}) -> List[Account]:
405
405
  """
406
406
  fetch all the accounts associated with a profile
407
407
  :see: https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getaccounts
@@ -415,7 +415,7 @@ class coinbase(Exchange, ImplicitAPI):
415
415
  return await self.fetch_accounts_v3(params)
416
416
  return await self.fetch_accounts_v2(params)
417
417
 
418
- async def fetch_accounts_v2(self, params={}):
418
+ async def fetch_accounts_v2(self, params={}) -> List[Account]:
419
419
  await self.load_markets()
420
420
  paginate = False
421
421
  paginate, params = self.handle_option_and_params(params, 'fetchAccounts', 'paginate')
@@ -481,7 +481,7 @@ class coinbase(Exchange, ImplicitAPI):
481
481
  accounts[lastIndex] = last
482
482
  return self.parse_accounts(data, params)
483
483
 
484
- async def fetch_accounts_v3(self, params={}):
484
+ async def fetch_accounts_v3(self, params={}) -> List[Account]:
485
485
  await self.load_markets()
486
486
  paginate = False
487
487
  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
  ],
@@ -6,7 +6,7 @@
6
6
  from ccxt.async_support.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
- async def fetch_accounts(self, params={}):
428
+ async 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
@@ -147,7 +147,7 @@ class coinex(Exchange, ImplicitAPI):
147
147
  'perpetualPrivate': 'https://api.coinex.com/perpetual',
148
148
  },
149
149
  'www': 'https://www.coinex.com',
150
- 'doc': 'https://github.com/coinexcom/coinex_exchange_api/wiki',
150
+ 'doc': 'https://viabtc.github.io/coinex_api_en_doc',
151
151
  'fees': 'https://www.coinex.com/fees',
152
152
  'referral': 'https://www.coinex.com/register?refer_code=yw5fz',
153
153
  },
@@ -361,6 +361,7 @@ class coinex(Exchange, ImplicitAPI):
361
361
  },
362
362
  'broad': {
363
363
  'ip not allow visit': PermissionDenied,
364
+ 'service too busy': ExchangeNotAvailable,
364
365
  },
365
366
  },
366
367
  })
@@ -4814,7 +4815,7 @@ class coinex(Exchange, ImplicitAPI):
4814
4815
  async def borrow_isolated_margin(self, symbol: str, code: str, amount: float, params={}):
4815
4816
  """
4816
4817
  create a loan to borrow margin
4817
- :see: https://github.com/coinexcom/coinex_exchange_api/wiki/086margin_loan
4818
+ :see: https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot002_account017_margin_loan
4818
4819
  :param str symbol: unified market symbol, required for coinex
4819
4820
  :param str code: unified currency code of the currency to borrow
4820
4821
  :param float amount: the amount to borrow
@@ -4849,7 +4850,7 @@ class coinex(Exchange, ImplicitAPI):
4849
4850
  async def repay_isolated_margin(self, symbol: str, code: str, amount, params={}):
4850
4851
  """
4851
4852
  repay borrowed margin and interest
4852
- :see: https://github.com/coinexcom/coinex_exchange_api/wiki/087margin_flat
4853
+ :see: https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot002_account018_margin_flat
4853
4854
  :param str symbol: unified market symbol, required for coinex
4854
4855
  :param str code: unified currency code of the currency to repay
4855
4856
  :param float amount: the amount to repay
@@ -7,7 +7,7 @@ from ccxt.async_support.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
- async def fetch_accounts(self, params={}):
1034
+ async 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
@@ -6,7 +6,7 @@
6
6
  from ccxt.async_support.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
- async def fetch_accounts(self, params={}):
2301
+ async 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
@@ -6,7 +6,7 @@
6
6
  from ccxt.async_support.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
- async def fetch_accounts(self, params={}):
577
+ async 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
@@ -6,7 +6,7 @@
6
6
  from ccxt.async_support.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
- async def fetch_accounts(self, params={}):
685
+ async 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
@@ -4011,6 +4011,7 @@ class gate(Exchange, ImplicitAPI):
4011
4011
  'failed': 'canceled',
4012
4012
  'expired': 'canceled',
4013
4013
  'finished': 'closed',
4014
+ 'finish': 'closed',
4014
4015
  'succeeded': 'closed',
4015
4016
  }
4016
4017
  return self.safe_string(statuses, status, status)