ccxt 4.2.20__py2.py3-none-any.whl → 4.2.22__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (62) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/abstract/binance.py +3 -0
  3. ccxt/abstract/binancecoinm.py +3 -0
  4. ccxt/abstract/binanceus.py +16 -12
  5. ccxt/abstract/binanceusdm.py +3 -0
  6. ccxt/abstract/gate.py +1 -0
  7. ccxt/abstract/gateio.py +1 -0
  8. ccxt/abstract/novadax.py +22 -18
  9. ccxt/abstract/phemex.py +1 -0
  10. ccxt/async_support/__init__.py +1 -1
  11. ccxt/async_support/base/exchange.py +16 -4
  12. ccxt/async_support/bigone.py +1 -0
  13. ccxt/async_support/binance.py +14 -3
  14. ccxt/async_support/bitget.py +11 -1
  15. ccxt/async_support/bitrue.py +1 -0
  16. ccxt/async_support/bitvavo.py +250 -152
  17. ccxt/async_support/blockchaincom.py +3 -1
  18. ccxt/async_support/bybit.py +49 -10
  19. ccxt/async_support/coinbasepro.py +1 -0
  20. ccxt/async_support/coinex.py +34 -12
  21. ccxt/async_support/deribit.py +145 -0
  22. ccxt/async_support/gate.py +30 -1
  23. ccxt/async_support/novadax.py +27 -23
  24. ccxt/async_support/okcoin.py +3 -0
  25. ccxt/async_support/phemex.py +7 -3
  26. ccxt/async_support/poloniex.py +1 -0
  27. ccxt/async_support/woo.py +1 -1
  28. ccxt/base/exchange.py +17 -5
  29. ccxt/bigone.py +1 -0
  30. ccxt/binance.py +14 -3
  31. ccxt/bitget.py +11 -1
  32. ccxt/bitrue.py +1 -0
  33. ccxt/bitvavo.py +250 -152
  34. ccxt/blockchaincom.py +3 -1
  35. ccxt/bybit.py +49 -10
  36. ccxt/coinbasepro.py +1 -0
  37. ccxt/coinex.py +34 -12
  38. ccxt/deribit.py +145 -0
  39. ccxt/gate.py +30 -1
  40. ccxt/novadax.py +27 -23
  41. ccxt/okcoin.py +3 -0
  42. ccxt/phemex.py +7 -3
  43. ccxt/poloniex.py +1 -0
  44. ccxt/pro/__init__.py +1 -1
  45. ccxt/pro/bequant.py +7 -1
  46. ccxt/pro/binance.py +7 -4
  47. ccxt/pro/binancecoinm.py +7 -1
  48. ccxt/pro/binanceus.py +7 -1
  49. ccxt/pro/bitcoincom.py +7 -1
  50. ccxt/pro/bitget.py +1 -1
  51. ccxt/pro/bitopro.py +7 -3
  52. ccxt/pro/bitrue.py +5 -1
  53. ccxt/pro/bitvavo.py +623 -19
  54. ccxt/pro/lbank.py +1 -1
  55. ccxt/pro/okx.py +10 -2
  56. ccxt/test/test_async.py +14 -1
  57. ccxt/test/test_sync.py +14 -1
  58. ccxt/woo.py +1 -1
  59. {ccxt-4.2.20.dist-info → ccxt-4.2.22.dist-info}/METADATA +4 -4
  60. {ccxt-4.2.20.dist-info → ccxt-4.2.22.dist-info}/RECORD +62 -62
  61. {ccxt-4.2.20.dist-info → ccxt-4.2.22.dist-info}/WHEEL +0 -0
  62. {ccxt-4.2.20.dist-info → ccxt-4.2.22.dist-info}/top_level.txt +0 -0
@@ -53,7 +53,7 @@ class bybit(Exchange, ImplicitAPI):
53
53
  'closeAllPositions': False,
54
54
  'closePosition': False,
55
55
  'createMarketBuyOrderWithCost': True,
56
- 'createMarketSellOrderWithCost': False,
56
+ 'createMarketSellOrderWithCost': True,
57
57
  'createOrder': True,
58
58
  'createOrders': True,
59
59
  'createOrderWithTakeProfitAndStopLoss': True,
@@ -973,7 +973,7 @@ class bybit(Exchange, ImplicitAPI):
973
973
  'fetchMarkets': ['spot', 'linear', 'inverse', 'option'],
974
974
  'enableUnifiedMargin': None,
975
975
  'enableUnifiedAccount': None,
976
- 'createMarketBuyOrderRequiresPrice': True,
976
+ 'createMarketBuyOrderRequiresPrice': True, # only True for classic accounts
977
977
  'createUnifiedMarginAccount': False,
978
978
  'defaultType': 'swap', # 'swap', 'future', 'option', 'spot'
979
979
  'defaultSubType': 'linear', # 'linear', 'inverse'
@@ -3302,8 +3302,26 @@ class bybit(Exchange, ImplicitAPI):
3302
3302
  market = self.market(symbol)
3303
3303
  if not market['spot']:
3304
3304
  raise NotSupported(self.id + ' createMarketBuyOrderWithCost() supports spot orders only')
3305
- params['createMarketBuyOrderRequiresPrice'] = False
3306
- return await self.create_order(symbol, 'market', 'buy', cost, None, params)
3305
+ return await self.create_order(symbol, 'market', 'buy', cost, 1, params)
3306
+
3307
+ async def create_market_sell_order_with_cost(self, symbol: str, cost, params={}):
3308
+ """
3309
+ :see: https://bybit-exchange.github.io/docs/v5/order/create-order
3310
+ create a market sell order by providing the symbol and cost
3311
+ :param str symbol: unified symbol of the market to create an order in
3312
+ :param float cost: how much you want to trade in units of the quote currency
3313
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3314
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
3315
+ """
3316
+ await self.load_markets()
3317
+ types = await self.is_unified_enabled()
3318
+ enableUnifiedAccount = types[1]
3319
+ if not enableUnifiedAccount:
3320
+ raise NotSupported(self.id + ' createMarketSellOrderWithCost() supports UTA accounts only')
3321
+ market = self.market(symbol)
3322
+ if not market['spot']:
3323
+ raise NotSupported(self.id + ' createMarketSellOrderWithCost() supports spot orders only')
3324
+ return await self.create_order(symbol, 'market', 'sell', cost, 1, params)
3307
3325
 
3308
3326
  async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount, price=None, params={}):
3309
3327
  """
@@ -3344,7 +3362,7 @@ class bybit(Exchange, ImplicitAPI):
3344
3362
  return await self.create_usdc_order(symbol, type, side, amount, price, params)
3345
3363
  trailingAmount = self.safe_string_2(params, 'trailingAmount', 'trailingStop')
3346
3364
  isTrailingAmountOrder = trailingAmount is not None
3347
- orderRequest = self.create_order_request(symbol, type, side, amount, price, params)
3365
+ orderRequest = self.create_order_request(symbol, type, side, amount, price, params, enableUnifiedAccount)
3348
3366
  response = None
3349
3367
  if isTrailingAmountOrder:
3350
3368
  response = await self.privatePostV5PositionTradingStop(orderRequest)
@@ -3365,7 +3383,7 @@ class bybit(Exchange, ImplicitAPI):
3365
3383
  order = self.safe_value(response, 'result', {})
3366
3384
  return self.parse_order(order, market)
3367
3385
 
3368
- def create_order_request(self, symbol: str, type: OrderType, side: OrderSide, amount, price=None, params={}):
3386
+ def create_order_request(self, symbol: str, type: OrderType, side: OrderSide, amount, price=None, params={}, isUTA=True):
3369
3387
  market = self.market(symbol)
3370
3388
  symbol = market['symbol']
3371
3389
  lowerCaseType = type.lower()
@@ -3404,12 +3422,31 @@ class bybit(Exchange, ImplicitAPI):
3404
3422
  request['category'] = 'inverse'
3405
3423
  elif market['option']:
3406
3424
  request['category'] = 'option'
3407
- if market['spot'] and (type == 'market') and (side == 'buy'):
3425
+ cost = self.safe_string(params, 'cost')
3426
+ params = self.omit(params, 'cost')
3427
+ # if the cost is inferable, let's keep the old logic and ignore marketUnit, to minimize the impact of the changes
3428
+ isMarketBuyAndCostInferable = (lowerCaseType == 'market') and (side == 'buy') and ((price is not None) or (cost is not None))
3429
+ if market['spot'] and (type == 'market') and isUTA and not isMarketBuyAndCostInferable:
3430
+ # UTA account can specify the cost of the order on both sides
3431
+ if (cost is not None) or (price is not None):
3432
+ request['marketUnit'] = 'quoteCoin'
3433
+ orderCost = None
3434
+ if cost is not None:
3435
+ orderCost = cost
3436
+ else:
3437
+ amountString = self.number_to_string(amount)
3438
+ priceString = self.number_to_string(price)
3439
+ quoteAmount = Precise.string_mul(amountString, priceString)
3440
+ orderCost = quoteAmount
3441
+ request['qty'] = self.cost_to_precision(symbol, orderCost)
3442
+ else:
3443
+ request['marketUnit'] = 'baseCoin'
3444
+ request['qty'] = self.amount_to_precision(symbol, amount)
3445
+ elif market['spot'] and (type == 'market') and (side == 'buy'):
3446
+ # classic accounts
3408
3447
  # for market buy it requires the amount of quote currency to spend
3409
3448
  createMarketBuyOrderRequiresPrice = True
3410
3449
  createMarketBuyOrderRequiresPrice, params = self.handle_option_and_params(params, 'createOrder', 'createMarketBuyOrderRequiresPrice', True)
3411
- cost = self.safe_number(params, 'cost')
3412
- params = self.omit(params, 'cost')
3413
3450
  if createMarketBuyOrderRequiresPrice:
3414
3451
  if (price is None) and (cost is None):
3415
3452
  raise InvalidOrder(self.id + ' createOrder() requires the price argument for market buy orders to calculate the total cost to spend(amount * price), alternatively set the createMarketBuyOrderRequiresPrice option or param to False and pass the cost to spend in the amount argument')
@@ -3505,6 +3542,8 @@ class bybit(Exchange, ImplicitAPI):
3505
3542
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
3506
3543
  """
3507
3544
  await self.load_markets()
3545
+ accounts = await self.is_unified_enabled()
3546
+ isUta = accounts[1]
3508
3547
  ordersRequests = []
3509
3548
  orderSymbols = []
3510
3549
  for i in range(0, len(orders)):
@@ -3516,7 +3555,7 @@ class bybit(Exchange, ImplicitAPI):
3516
3555
  amount = self.safe_value(rawOrder, 'amount')
3517
3556
  price = self.safe_value(rawOrder, 'price')
3518
3557
  orderParams = self.safe_value(rawOrder, 'params', {})
3519
- orderRequest = self.create_order_request(marketId, type, side, amount, price, orderParams)
3558
+ orderRequest = self.create_order_request(marketId, type, side, amount, price, orderParams, isUta)
3520
3559
  ordersRequests.append(orderRequest)
3521
3560
  symbols = self.market_symbols(orderSymbols, None, False, True, True)
3522
3561
  market = self.market(symbols[0])
@@ -53,6 +53,7 @@ class coinbasepro(Exchange, ImplicitAPI):
53
53
  'fetchDepositAddress': False, # the exchange does not have self method, only createDepositAddress, see https://github.com/ccxt/ccxt/pull/7405
54
54
  'fetchDeposits': True,
55
55
  'fetchDepositsWithdrawals': True,
56
+ 'fetchFundingRate': False,
56
57
  'fetchLedger': True,
57
58
  'fetchMarginMode': False,
58
59
  'fetchMarkets': True,
@@ -1531,8 +1531,9 @@ class coinex(Exchange, ImplicitAPI):
1531
1531
  """
1532
1532
  marketType = None
1533
1533
  marketType, params = self.handle_market_type_and_params('fetchBalance', None, params)
1534
- isMargin = self.safe_value(params, 'margin', False)
1535
- marketType = 'margin' if isMargin else marketType
1534
+ marginMode = None
1535
+ marginMode, params = self.handle_margin_mode_and_params('fetchBalance', params)
1536
+ marketType = 'margin' if (marginMode is not None) else marketType
1536
1537
  params = self.omit(params, 'margin')
1537
1538
  if marketType == 'margin':
1538
1539
  return await self.fetch_margin_balance(params)
@@ -2006,8 +2007,9 @@ class coinex(Exchange, ImplicitAPI):
2006
2007
  if timeInForceRaw is not None:
2007
2008
  request['option'] = timeInForceRaw # exchange takes 'IOC' and 'FOK'
2008
2009
  accountId = self.safe_integer(params, 'account_id')
2009
- defaultType = self.safe_string(self.options, 'defaultType')
2010
- if defaultType == 'margin':
2010
+ marginMode = None
2011
+ marginMode, params = self.handle_margin_mode_and_params('createOrder', params)
2012
+ if marginMode is not None:
2011
2013
  if accountId is None:
2012
2014
  raise BadRequest(self.id + ' createOrder() requires an account_id parameter for margin orders')
2013
2015
  request['account_id'] = accountId
@@ -2474,9 +2476,10 @@ class coinex(Exchange, ImplicitAPI):
2474
2476
  'market': market['id'],
2475
2477
  }
2476
2478
  accountId = self.safe_integer(params, 'account_id')
2477
- defaultType = self.safe_string(self.options, 'defaultType')
2479
+ marginMode = None
2480
+ marginMode, params = self.handle_margin_mode_and_params('cancelOrder', params)
2478
2481
  clientOrderId = self.safe_string_2(params, 'client_id', 'clientOrderId')
2479
- if defaultType == 'margin':
2482
+ if marginMode is not None:
2480
2483
  if accountId is None:
2481
2484
  raise BadRequest(self.id + ' cancelOrder() requires an account_id parameter for margin orders')
2482
2485
  request['account_id'] = accountId
@@ -2815,8 +2818,9 @@ class coinex(Exchange, ImplicitAPI):
2815
2818
  request['market'] = market['id']
2816
2819
  marketType, query = self.handle_market_type_and_params('fetchOrdersByStatus', market, params)
2817
2820
  accountId = self.safe_integer(params, 'account_id')
2818
- defaultType = self.safe_string(self.options, 'defaultType')
2819
- if defaultType == 'margin':
2821
+ marginMode = None
2822
+ marginMode, params = self.handle_margin_mode_and_params('fetchOrdersByStatus', params)
2823
+ if marginMode is not None:
2820
2824
  if accountId is None:
2821
2825
  raise BadRequest(self.id + ' fetchOpenOrders() and fetchClosedOrders() require an account_id parameter for margin orders')
2822
2826
  request['account_id'] = accountId
@@ -3180,8 +3184,9 @@ class coinex(Exchange, ImplicitAPI):
3180
3184
  raise ArgumentsRequired(self.id + ' fetchMyTrades() requires a symbol argument for non-spot markets')
3181
3185
  swap = (type == 'swap')
3182
3186
  accountId = self.safe_integer(params, 'account_id')
3183
- defaultType = self.safe_string(self.options, 'defaultType')
3184
- if defaultType == 'margin':
3187
+ marginMode = None
3188
+ marginMode, params = self.handle_margin_mode_and_params('fetchMyTrades', params)
3189
+ if marginMode is not None:
3185
3190
  if accountId is None:
3186
3191
  raise BadRequest(self.id + ' fetchMyTrades() requires an account_id parameter for margin trades')
3187
3192
  request['account_id'] = accountId
@@ -4419,9 +4424,10 @@ class coinex(Exchange, ImplicitAPI):
4419
4424
  else:
4420
4425
  request['limit'] = 100
4421
4426
  params = self.omit(params, 'page')
4422
- defaultType = self.safe_string(self.options, 'defaultType')
4427
+ marginMode = None
4428
+ marginMode, params = self.handle_margin_mode_and_params('fetchTransfers', params)
4423
4429
  response = None
4424
- if defaultType == 'margin':
4430
+ if marginMode is not None:
4425
4431
  response = await self.privateGetMarginTransferHistory(self.extend(request, params))
4426
4432
  else:
4427
4433
  response = await self.privateGetContractTransferHistory(self.extend(request, params))
@@ -4968,6 +4974,22 @@ class coinex(Exchange, ImplicitAPI):
4968
4974
  depositWithdrawFees[code] = self.assign_default_deposit_withdraw_fees(depositWithdrawFees[code], currency)
4969
4975
  return depositWithdrawFees
4970
4976
 
4977
+ def handle_margin_mode_and_params(self, methodName, params={}, defaultValue=None):
4978
+ """
4979
+ * @ignore
4980
+ marginMode specified by params["marginMode"], self.options["marginMode"], self.options["defaultMarginMode"], params["margin"] = True or self.options["defaultType"] = 'margin'
4981
+ :param dict params: extra parameters specific to the exchange api endpoint
4982
+ :returns Array: the marginMode in lowercase
4983
+ """
4984
+ defaultType = self.safe_string(self.options, 'defaultType')
4985
+ isMargin = self.safe_value(params, 'margin', False)
4986
+ marginMode = None
4987
+ marginMode, params = super(coinex, self).handle_margin_mode_and_params(methodName, params, defaultValue)
4988
+ if marginMode is None:
4989
+ if (defaultType == 'margin') or (isMargin is True):
4990
+ marginMode = 'isolated'
4991
+ return [marginMode, params]
4992
+
4971
4993
  def nonce(self):
4972
4994
  return self.milliseconds()
4973
4995
 
@@ -415,6 +415,151 @@ class deribit(Exchange, ImplicitAPI):
415
415
  },
416
416
  })
417
417
 
418
+ def convert_expire_date(self, date):
419
+ # parse YYMMDD to timestamp
420
+ year = date[0:2]
421
+ month = date[2:4]
422
+ day = date[4:6]
423
+ reconstructedDate = '20' + year + '-' + month + '-' + day + 'T00:00:00Z'
424
+ return reconstructedDate
425
+
426
+ def convert_market_id_expire_date(self, date):
427
+ # parse 19JAN24 to 240119
428
+ monthMappping = {
429
+ 'JAN': '01',
430
+ 'FEB': '02',
431
+ 'MAR': '03',
432
+ 'APR': '04',
433
+ 'MAY': '05',
434
+ 'JUN': '06',
435
+ 'JUL': '07',
436
+ 'AUG': '08',
437
+ 'SEP': '09',
438
+ 'OCT': '10',
439
+ 'NOV': '11',
440
+ 'DEC': '12',
441
+ }
442
+ year = date[0:2]
443
+ monthName = date[2:5]
444
+ month = self.safe_string(monthMappping, monthName)
445
+ day = date[5:7]
446
+ reconstructedDate = day + month + year
447
+ return reconstructedDate
448
+
449
+ def convert_expire_date_to_market_id_date(self, date):
450
+ # parse 240119 to 19JAN24
451
+ year = date[0:2]
452
+ monthRaw = date[2:4]
453
+ month = None
454
+ day = date[4:6]
455
+ if monthRaw == '01':
456
+ month = 'JAN'
457
+ elif monthRaw == '02':
458
+ month = 'FEB'
459
+ elif monthRaw == '03':
460
+ month = 'MAR'
461
+ elif monthRaw == '04':
462
+ month = 'APR'
463
+ elif monthRaw == '05':
464
+ month = 'MAY'
465
+ elif monthRaw == '06':
466
+ month = 'JUN'
467
+ elif monthRaw == '07':
468
+ month = 'JUL'
469
+ elif monthRaw == '08':
470
+ month = 'AUG'
471
+ elif monthRaw == '09':
472
+ month = 'SEP'
473
+ elif monthRaw == '10':
474
+ month = 'OCT'
475
+ elif monthRaw == '11':
476
+ month = 'NOV'
477
+ elif monthRaw == '12':
478
+ month = 'DEC'
479
+ reconstructedDate = day + month + year
480
+ return reconstructedDate
481
+
482
+ def create_expired_option_market(self, symbol):
483
+ # support expired option contracts
484
+ quote = 'USD'
485
+ settle = None
486
+ optionParts = symbol.split('-')
487
+ symbolBase = symbol.split('/')
488
+ base = None
489
+ expiry = None
490
+ if symbol.find('/') > -1:
491
+ base = self.safe_string(symbolBase, 0)
492
+ expiry = self.safe_string(optionParts, 1)
493
+ if symbol.find('USDC') > -1:
494
+ base = base + '_USDC'
495
+ else:
496
+ base = self.safe_string(optionParts, 0)
497
+ expiry = self.convert_market_id_expire_date(self.safe_string(optionParts, 1))
498
+ if symbol.find('USDC') > -1:
499
+ quote = 'USDC'
500
+ settle = 'USDC'
501
+ else:
502
+ settle = base
503
+ splitBase = base
504
+ if base.find('_') > -1:
505
+ splitSymbol = base.split('_')
506
+ splitBase = self.safe_string(splitSymbol, 0)
507
+ strike = self.safe_string(optionParts, 2)
508
+ optionType = self.safe_string(optionParts, 3)
509
+ datetime = self.convert_expire_date(expiry)
510
+ timestamp = self.parse8601(datetime)
511
+ return {
512
+ 'id': base + '-' + self.convert_expire_date_to_market_id_date(expiry) + '-' + strike + '-' + optionType,
513
+ 'symbol': splitBase + '/' + quote + ':' + settle + '-' + expiry + '-' + strike + '-' + optionType,
514
+ 'base': base,
515
+ 'quote': quote,
516
+ 'settle': settle,
517
+ 'baseId': base,
518
+ 'quoteId': quote,
519
+ 'settleId': settle,
520
+ 'active': False,
521
+ 'type': 'option',
522
+ 'linear': None,
523
+ 'inverse': None,
524
+ 'spot': False,
525
+ 'swap': False,
526
+ 'future': False,
527
+ 'option': True,
528
+ 'margin': False,
529
+ 'contract': True,
530
+ 'contractSize': None,
531
+ 'expiry': timestamp,
532
+ 'expiryDatetime': datetime,
533
+ 'optionType': 'call' if (optionType == 'C') else 'put',
534
+ 'strike': self.parse_number(strike),
535
+ 'precision': {
536
+ 'amount': None,
537
+ 'price': None,
538
+ },
539
+ 'limits': {
540
+ 'amount': {
541
+ 'min': None,
542
+ 'max': None,
543
+ },
544
+ 'price': {
545
+ 'min': None,
546
+ 'max': None,
547
+ },
548
+ 'cost': {
549
+ 'min': None,
550
+ 'max': None,
551
+ },
552
+ },
553
+ 'info': None,
554
+ }
555
+
556
+ def safe_market(self, marketId=None, market=None, delimiter=None, marketType=None):
557
+ isOption = (marketId is not None) and ((marketId.endswith('-C')) or (marketId.endswith('-P')))
558
+ if isOption and not (marketId in self.markets_by_id):
559
+ # handle expired option contracts
560
+ return self.create_expired_option_market(marketId)
561
+ return super(deribit, self).safe_market(marketId, market, delimiter, marketType)
562
+
418
563
  async def fetch_time(self, params={}):
419
564
  """
420
565
  fetches the current integer timestamp in milliseconds from the exchange server
@@ -548,6 +548,7 @@ class gate(Exchange, ImplicitAPI):
548
548
  'multi_collateral/currency_quota': 20 / 15,
549
549
  'multi_collateral/currencies': 20 / 15,
550
550
  'multi_collateral/ltv': 20 / 15,
551
+ 'multi_collateral/fixed_rate': 20 / 15,
551
552
  },
552
553
  'post': {
553
554
  'collateral/orders': 20 / 15,
@@ -5169,7 +5170,7 @@ class gate(Exchange, ImplicitAPI):
5169
5170
  retrieve information on the maximum leverage, and maintenance margin for trades of varying trade sizes
5170
5171
  :see: https://www.gate.io/docs/developers/apiv4/en/#list-all-futures-contracts
5171
5172
  :see: https://www.gate.io/docs/developers/apiv4/en/#list-all-futures-contracts-2
5172
- :param str[]|None symbols: list of unified market symbols
5173
+ :param str[] [symbols]: list of unified market symbols
5173
5174
  :param dict [params]: extra parameters specific to the exchange API endpoint
5174
5175
  :returns dict: a dictionary of `leverage tiers structures <https://docs.ccxt.com/#/?id=leverage-tiers-structure>`, indexed by market symbols
5175
5176
  """
@@ -5307,6 +5308,32 @@ class gate(Exchange, ImplicitAPI):
5307
5308
  #
5308
5309
  return self.parse_market_leverage_tiers(response, market)
5309
5310
 
5311
+ def parse_emulated_leverage_tiers(self, info, market=None):
5312
+ maintenanceMarginUnit = self.safe_string(info, 'maintenance_rate') # '0.005',
5313
+ leverageMax = self.safe_string(info, 'leverage_max') # '100',
5314
+ riskLimitStep = self.safe_string(info, 'risk_limit_step') # '1000000',
5315
+ riskLimitMax = self.safe_string(info, 'risk_limit_max') # '16000000',
5316
+ initialMarginUnit = Precise.string_div('1', leverageMax)
5317
+ maintenanceMarginRate = maintenanceMarginUnit
5318
+ initialMarginRatio = initialMarginUnit
5319
+ floor = '0'
5320
+ tiers = []
5321
+ while(Precise.string_lt(floor, riskLimitMax)):
5322
+ cap = Precise.string_add(floor, riskLimitStep)
5323
+ tiers.append({
5324
+ 'tier': self.parse_number(Precise.string_div(cap, riskLimitStep)),
5325
+ 'currency': self.safe_string(market, 'settle'),
5326
+ 'minNotional': self.parse_number(floor),
5327
+ 'maxNotional': self.parse_number(cap),
5328
+ 'maintenanceMarginRate': self.parse_number(maintenanceMarginRate),
5329
+ 'maxLeverage': self.parse_number(Precise.string_div('1', initialMarginRatio)),
5330
+ 'info': info,
5331
+ })
5332
+ maintenanceMarginRate = Precise.string_add(maintenanceMarginRate, maintenanceMarginUnit)
5333
+ initialMarginRatio = Precise.string_add(initialMarginRatio, initialMarginUnit)
5334
+ floor = cap
5335
+ return tiers
5336
+
5310
5337
  def parse_market_leverage_tiers(self, info, market: Market = None):
5311
5338
  #
5312
5339
  # [
@@ -5319,6 +5346,8 @@ class gate(Exchange, ImplicitAPI):
5319
5346
  # }
5320
5347
  # ]
5321
5348
  #
5349
+ if not isinstance(info, list):
5350
+ return self.parse_emulated_leverage_tiers(info, market)
5322
5351
  minNotional = 0
5323
5352
  tiers = []
5324
5353
  for i in range(0, len(info)):
@@ -33,9 +33,9 @@ class novadax(Exchange, ImplicitAPI):
33
33
  'id': 'novadax',
34
34
  'name': 'NovaDAX',
35
35
  'countries': ['BR'], # Brazil
36
- # 60 requests per second = 1000ms / 60 = 16.6667ms between requests(public endpoints, limited by IP address)
37
- # 20 requests per second => cost = 60 / 20 = 3(private endpoints, limited by API Key)
38
- 'rateLimit': 16.6667,
36
+ # 6000 weight per min => 100 weight per second => min weight = 1
37
+ # 100 requests per second =>( 1000ms / 100 ) = 10 ms between requests on average
38
+ 'rateLimit': 10,
39
39
  'version': 'v1',
40
40
  # new metainfo interface
41
41
  'has': {
@@ -133,33 +133,37 @@ class novadax(Exchange, ImplicitAPI):
133
133
  'api': {
134
134
  'public': {
135
135
  'get': {
136
- 'common/symbol': 1.2,
137
- 'common/symbols': 1.2,
138
- 'common/timestamp': 1.2,
139
- 'market/tickers': 1.2,
140
- 'market/ticker': 1.2,
141
- 'market/depth': 1.2,
142
- 'market/trades': 1.2,
143
- 'market/kline/history': 1.2,
136
+ 'common/symbol': 1,
137
+ 'common/symbols': 1,
138
+ 'common/timestamp': 1,
139
+ 'market/tickers': 5,
140
+ 'market/ticker': 1,
141
+ 'market/depth': 1,
142
+ 'market/trades': 5,
143
+ 'market/kline/history': 5,
144
144
  },
145
145
  },
146
146
  'private': {
147
147
  'get': {
148
- 'orders/get': 3,
149
- 'orders/list': 3,
150
- 'orders/fill': 3,
151
- 'orders/fills': 3,
152
- 'account/getBalance': 3,
153
- 'account/subs': 3,
154
- 'account/subs/balance': 3,
155
- 'account/subs/transfer/record': 3,
148
+ 'orders/get': 1,
149
+ 'orders/list': 10,
150
+ 'orders/fill': 3, # not found in doc
151
+ 'orders/fills': 10,
152
+ 'account/getBalance': 1,
153
+ 'account/subs': 1,
154
+ 'account/subs/balance': 1,
155
+ 'account/subs/transfer/record': 10,
156
156
  'wallet/query/deposit-withdraw': 3,
157
157
  },
158
158
  'post': {
159
- 'orders/create': 3,
160
- 'orders/cancel': 3,
161
- 'account/withdraw/coin': 3,
162
- 'account/subs/transfer': 3,
159
+ 'orders/create': 5,
160
+ 'orders/batch-create': 50,
161
+ 'orders/cancel': 1,
162
+ 'orders/batch-cancel': 10,
163
+ 'orders/cancel-by-symbol': 10,
164
+ 'account/subs/transfer': 5,
165
+ 'wallet/withdraw/coin': 3,
166
+ 'account/withdraw/coin': 3, # not found in doc
163
167
  },
164
168
  },
165
169
  },
@@ -67,6 +67,9 @@ class okcoin(Exchange, ImplicitAPI):
67
67
  'fetchCurrencies': True, # see below
68
68
  'fetchDepositAddress': True,
69
69
  'fetchDeposits': True,
70
+ 'fetchFundingHistory': False,
71
+ 'fetchFundingRate': False,
72
+ 'fetchFundingRateHistory': False,
70
73
  'fetchLedger': True,
71
74
  'fetchMarkets': True,
72
75
  'fetchMyTrades': True,
@@ -207,6 +207,7 @@ class phemex(Exchange, ImplicitAPI):
207
207
  'api-data/g-futures/trades': 5, # ?symbol=<symbol>
208
208
  'api-data/futures/trading-fees': 5, # ?symbol=<symbol>
209
209
  'api-data/g-futures/trading-fees': 5, # ?symbol=<symbol>
210
+ 'api-data/futures/v2/tradeAccountDetail': 5, # ?currency=<currecny>&type=<type>&limit=<limit>&offset=<offset>&start=<start>&end=<end>&withCount=<withCount>
210
211
  'g-orders/activeList': 1, # ?symbol=<symbol>
211
212
  'orders/activeList': 1, # ?symbol=<symbol>
212
213
  'exchange/order/list': 5, # ?symbol=<symbol>&start=<start>&end=<end>&offset=<offset>&limit=<limit>&ordStatus=<ordStatus>&withCount=<withCount>
@@ -1849,23 +1850,26 @@ class phemex(Exchange, ImplicitAPI):
1849
1850
  async def fetch_balance(self, params={}) -> Balances:
1850
1851
  """
1851
1852
  query for balance and get the amount of funds available for trading or funds locked in orders
1853
+ :see: https://phemex-docs.github.io/#query-wallets
1852
1854
  :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#query-account-positions
1855
+ :see: https://phemex-docs.github.io/#query-trading-account-and-positions
1853
1856
  :param dict [params]: extra parameters specific to the exchange API endpoint
1854
1857
  :param str [params.type]: spot or swap
1858
+ :param str [params.code]: *swap only* currency code of the balance to query(USD, USDT, etc), default is USDT
1855
1859
  :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
1856
1860
  """
1857
1861
  await self.load_markets()
1858
1862
  type = None
1859
1863
  type, params = self.handle_market_type_and_params('fetchBalance', None, params)
1860
1864
  code = self.safe_string(params, 'code')
1861
- params = self.omit(params, ['type', 'code'])
1865
+ params = self.omit(params, ['code'])
1862
1866
  response = None
1863
1867
  request = {}
1864
1868
  if (type != 'spot') and (type != 'swap'):
1865
1869
  raise BadRequest(self.id + ' does not support ' + type + ' markets, only spot and swap')
1866
1870
  if type == 'swap':
1867
1871
  settle = None
1868
- settle, params = self.handle_option_and_params(params, 'fetchBalance', 'settle')
1872
+ settle, params = self.handle_option_and_params(params, 'fetchBalance', 'settle', 'USDT')
1869
1873
  if code is not None or settle is not None:
1870
1874
  coin = None
1871
1875
  if code is not None:
@@ -2623,7 +2627,7 @@ class phemex(Exchange, ImplicitAPI):
2623
2627
  request['baseQtyEV'] = finalQty
2624
2628
  elif amount is not None:
2625
2629
  if isUSDTSettled:
2626
- request['baseQtyEV'] = self.amount_to_precision(market['symbol'], amount)
2630
+ request['orderQtyRq'] = self.amount_to_precision(market['symbol'], amount)
2627
2631
  else:
2628
2632
  request['baseQtyEV'] = self.to_ev(amount, market)
2629
2633
  stopPrice = self.safe_string_2(params, 'stopPx', 'stopPrice')
@@ -60,6 +60,7 @@ class poloniex(Exchange, ImplicitAPI):
60
60
  'fetchDepositsWithdrawals': True,
61
61
  'fetchDepositWithdrawFee': 'emulated',
62
62
  'fetchDepositWithdrawFees': True,
63
+ 'fetchFundingRate': False,
63
64
  'fetchMarginMode': False,
64
65
  'fetchMarkets': True,
65
66
  'fetchMyTrades': True,
ccxt/async_support/woo.py CHANGED
@@ -66,7 +66,7 @@ class woo(Exchange, ImplicitAPI):
66
66
  'fetchClosedOrder': False,
67
67
  'fetchClosedOrders': False,
68
68
  'fetchCurrencies': True,
69
- 'fetchDepositAddress': False,
69
+ 'fetchDepositAddress': True,
70
70
  'fetchDeposits': True,
71
71
  'fetchDepositsWithdrawals': True,
72
72
  'fetchFundingHistory': True,
ccxt/base/exchange.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # -----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.2.20'
7
+ __version__ = '4.2.22'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
 
@@ -2902,6 +2902,12 @@ class Exchange(object):
2902
2902
  message = '. If you want to build OHLCV candles from trade executions data, visit https://github.com/ccxt/ccxt/tree/master/examples/ and see "build-ohlcv-bars" file'
2903
2903
  raise NotSupported(self.id + ' fetchOHLCV() is not supported yet' + message)
2904
2904
 
2905
+ def fetch_ohlcv_ws(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}):
2906
+ message = ''
2907
+ if self.has['fetchTradesWs']:
2908
+ message = '. If you want to build OHLCV candles from trade executions data, visit https://github.com/ccxt/ccxt/tree/master/examples/ and see "build-ohlcv-bars" file'
2909
+ raise NotSupported(self.id + ' fetchOHLCVWs() is not supported yet. Try using fetchOHLCV instead.' + message)
2910
+
2905
2911
  def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}):
2906
2912
  raise NotSupported(self.id + ' watchOHLCV() is not supported yet')
2907
2913
 
@@ -3198,7 +3204,7 @@ class Exchange(object):
3198
3204
  for i in range(0, len(response)):
3199
3205
  item = response[i]
3200
3206
  id = self.safe_string(item, marketIdKey)
3201
- market = self.safe_market(id, None, None, self.safe_string(self.options, 'defaultType'))
3207
+ market = self.safe_market(id, None, None, 'swap')
3202
3208
  symbol = market['symbol']
3203
3209
  contract = self.safe_value(market, 'contract', False)
3204
3210
  if contract and ((symbols is None) or self.in_array(symbol, symbols)):
@@ -4050,9 +4056,6 @@ class Exchange(object):
4050
4056
  def watch_my_trades(self, symbol: str = None, since: Int = None, limit: Int = None, params={}):
4051
4057
  raise NotSupported(self.id + ' watchMyTrades() is not supported yet')
4052
4058
 
4053
- def fetch_ohlcv_ws(self, symbol: str, timeframe: str = '1m', since: Int = None, limit: Int = None, params={}):
4054
- raise NotSupported(self.id + ' fetchOHLCVWs() is not supported yet')
4055
-
4056
4059
  def fetch_greeks(self, symbol: str, params={}):
4057
4060
  raise NotSupported(self.id + ' fetchGreeks() is not supported yet')
4058
4061
 
@@ -4070,9 +4073,15 @@ class Exchange(object):
4070
4073
  def fetch_deposits(self, code: str = None, since: Int = None, limit: Int = None, params={}):
4071
4074
  raise NotSupported(self.id + ' fetchDeposits() is not supported yet')
4072
4075
 
4076
+ def fetch_deposits_ws(self, code: str = None, since: Int = None, limit: Int = None, params={}):
4077
+ raise NotSupported(self.id + ' fetchDepositsWs() is not supported yet')
4078
+
4073
4079
  def fetch_withdrawals(self, code: str = None, since: Int = None, limit: Int = None, params={}):
4074
4080
  raise NotSupported(self.id + ' fetchWithdrawals() is not supported yet')
4075
4081
 
4082
+ def fetch_withdrawals_ws(self, code: str = None, since: Int = None, limit: Int = None, params={}):
4083
+ raise NotSupported(self.id + ' fetchWithdrawalsWs() is not supported yet')
4084
+
4076
4085
  def fetch_open_interest(self, symbol: str, params={}):
4077
4086
  raise NotSupported(self.id + ' fetchOpenInterest() is not supported yet')
4078
4087
 
@@ -4488,6 +4497,9 @@ class Exchange(object):
4488
4497
  def fetch_trading_fees(self, params={}):
4489
4498
  raise NotSupported(self.id + ' fetchTradingFees() is not supported yet')
4490
4499
 
4500
+ def fetch_trading_fees_ws(self, params={}):
4501
+ raise NotSupported(self.id + ' fetchTradingFeesWs() is not supported yet')
4502
+
4491
4503
  def fetch_trading_fee(self, symbol: str, params={}):
4492
4504
  if not self.has['fetchTradingFees']:
4493
4505
  raise NotSupported(self.id + ' fetchTradingFee() is not supported yet')