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
ccxt/bybit.py CHANGED
@@ -52,7 +52,7 @@ class bybit(Exchange, ImplicitAPI):
52
52
  'closeAllPositions': False,
53
53
  'closePosition': False,
54
54
  'createMarketBuyOrderWithCost': True,
55
- 'createMarketSellOrderWithCost': False,
55
+ 'createMarketSellOrderWithCost': True,
56
56
  'createOrder': True,
57
57
  'createOrders': True,
58
58
  'createOrderWithTakeProfitAndStopLoss': True,
@@ -972,7 +972,7 @@ class bybit(Exchange, ImplicitAPI):
972
972
  'fetchMarkets': ['spot', 'linear', 'inverse', 'option'],
973
973
  'enableUnifiedMargin': None,
974
974
  'enableUnifiedAccount': None,
975
- 'createMarketBuyOrderRequiresPrice': True,
975
+ 'createMarketBuyOrderRequiresPrice': True, # only True for classic accounts
976
976
  'createUnifiedMarginAccount': False,
977
977
  'defaultType': 'swap', # 'swap', 'future', 'option', 'spot'
978
978
  'defaultSubType': 'linear', # 'linear', 'inverse'
@@ -3301,8 +3301,26 @@ class bybit(Exchange, ImplicitAPI):
3301
3301
  market = self.market(symbol)
3302
3302
  if not market['spot']:
3303
3303
  raise NotSupported(self.id + ' createMarketBuyOrderWithCost() supports spot orders only')
3304
- params['createMarketBuyOrderRequiresPrice'] = False
3305
- return self.create_order(symbol, 'market', 'buy', cost, None, params)
3304
+ return self.create_order(symbol, 'market', 'buy', cost, 1, params)
3305
+
3306
+ def create_market_sell_order_with_cost(self, symbol: str, cost, params={}):
3307
+ """
3308
+ :see: https://bybit-exchange.github.io/docs/v5/order/create-order
3309
+ create a market sell order by providing the symbol and cost
3310
+ :param str symbol: unified symbol of the market to create an order in
3311
+ :param float cost: how much you want to trade in units of the quote currency
3312
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3313
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
3314
+ """
3315
+ self.load_markets()
3316
+ types = self.is_unified_enabled()
3317
+ enableUnifiedAccount = types[1]
3318
+ if not enableUnifiedAccount:
3319
+ raise NotSupported(self.id + ' createMarketSellOrderWithCost() supports UTA accounts only')
3320
+ market = self.market(symbol)
3321
+ if not market['spot']:
3322
+ raise NotSupported(self.id + ' createMarketSellOrderWithCost() supports spot orders only')
3323
+ return self.create_order(symbol, 'market', 'sell', cost, 1, params)
3306
3324
 
3307
3325
  def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount, price=None, params={}):
3308
3326
  """
@@ -3343,7 +3361,7 @@ class bybit(Exchange, ImplicitAPI):
3343
3361
  return self.create_usdc_order(symbol, type, side, amount, price, params)
3344
3362
  trailingAmount = self.safe_string_2(params, 'trailingAmount', 'trailingStop')
3345
3363
  isTrailingAmountOrder = trailingAmount is not None
3346
- orderRequest = self.create_order_request(symbol, type, side, amount, price, params)
3364
+ orderRequest = self.create_order_request(symbol, type, side, amount, price, params, enableUnifiedAccount)
3347
3365
  response = None
3348
3366
  if isTrailingAmountOrder:
3349
3367
  response = self.privatePostV5PositionTradingStop(orderRequest)
@@ -3364,7 +3382,7 @@ class bybit(Exchange, ImplicitAPI):
3364
3382
  order = self.safe_value(response, 'result', {})
3365
3383
  return self.parse_order(order, market)
3366
3384
 
3367
- def create_order_request(self, symbol: str, type: OrderType, side: OrderSide, amount, price=None, params={}):
3385
+ def create_order_request(self, symbol: str, type: OrderType, side: OrderSide, amount, price=None, params={}, isUTA=True):
3368
3386
  market = self.market(symbol)
3369
3387
  symbol = market['symbol']
3370
3388
  lowerCaseType = type.lower()
@@ -3403,12 +3421,31 @@ class bybit(Exchange, ImplicitAPI):
3403
3421
  request['category'] = 'inverse'
3404
3422
  elif market['option']:
3405
3423
  request['category'] = 'option'
3406
- if market['spot'] and (type == 'market') and (side == 'buy'):
3424
+ cost = self.safe_string(params, 'cost')
3425
+ params = self.omit(params, 'cost')
3426
+ # if the cost is inferable, let's keep the old logic and ignore marketUnit, to minimize the impact of the changes
3427
+ isMarketBuyAndCostInferable = (lowerCaseType == 'market') and (side == 'buy') and ((price is not None) or (cost is not None))
3428
+ if market['spot'] and (type == 'market') and isUTA and not isMarketBuyAndCostInferable:
3429
+ # UTA account can specify the cost of the order on both sides
3430
+ if (cost is not None) or (price is not None):
3431
+ request['marketUnit'] = 'quoteCoin'
3432
+ orderCost = None
3433
+ if cost is not None:
3434
+ orderCost = cost
3435
+ else:
3436
+ amountString = self.number_to_string(amount)
3437
+ priceString = self.number_to_string(price)
3438
+ quoteAmount = Precise.string_mul(amountString, priceString)
3439
+ orderCost = quoteAmount
3440
+ request['qty'] = self.cost_to_precision(symbol, orderCost)
3441
+ else:
3442
+ request['marketUnit'] = 'baseCoin'
3443
+ request['qty'] = self.amount_to_precision(symbol, amount)
3444
+ elif market['spot'] and (type == 'market') and (side == 'buy'):
3445
+ # classic accounts
3407
3446
  # for market buy it requires the amount of quote currency to spend
3408
3447
  createMarketBuyOrderRequiresPrice = True
3409
3448
  createMarketBuyOrderRequiresPrice, params = self.handle_option_and_params(params, 'createOrder', 'createMarketBuyOrderRequiresPrice', True)
3410
- cost = self.safe_number(params, 'cost')
3411
- params = self.omit(params, 'cost')
3412
3449
  if createMarketBuyOrderRequiresPrice:
3413
3450
  if (price is None) and (cost is None):
3414
3451
  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')
@@ -3504,6 +3541,8 @@ class bybit(Exchange, ImplicitAPI):
3504
3541
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
3505
3542
  """
3506
3543
  self.load_markets()
3544
+ accounts = self.is_unified_enabled()
3545
+ isUta = accounts[1]
3507
3546
  ordersRequests = []
3508
3547
  orderSymbols = []
3509
3548
  for i in range(0, len(orders)):
@@ -3515,7 +3554,7 @@ class bybit(Exchange, ImplicitAPI):
3515
3554
  amount = self.safe_value(rawOrder, 'amount')
3516
3555
  price = self.safe_value(rawOrder, 'price')
3517
3556
  orderParams = self.safe_value(rawOrder, 'params', {})
3518
- orderRequest = self.create_order_request(marketId, type, side, amount, price, orderParams)
3557
+ orderRequest = self.create_order_request(marketId, type, side, amount, price, orderParams, isUta)
3519
3558
  ordersRequests.append(orderRequest)
3520
3559
  symbols = self.market_symbols(orderSymbols, None, False, True, True)
3521
3560
  market = self.market(symbols[0])
ccxt/coinbasepro.py CHANGED
@@ -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,
ccxt/coinex.py CHANGED
@@ -1530,8 +1530,9 @@ class coinex(Exchange, ImplicitAPI):
1530
1530
  """
1531
1531
  marketType = None
1532
1532
  marketType, params = self.handle_market_type_and_params('fetchBalance', None, params)
1533
- isMargin = self.safe_value(params, 'margin', False)
1534
- marketType = 'margin' if isMargin else marketType
1533
+ marginMode = None
1534
+ marginMode, params = self.handle_margin_mode_and_params('fetchBalance', params)
1535
+ marketType = 'margin' if (marginMode is not None) else marketType
1535
1536
  params = self.omit(params, 'margin')
1536
1537
  if marketType == 'margin':
1537
1538
  return self.fetch_margin_balance(params)
@@ -2005,8 +2006,9 @@ class coinex(Exchange, ImplicitAPI):
2005
2006
  if timeInForceRaw is not None:
2006
2007
  request['option'] = timeInForceRaw # exchange takes 'IOC' and 'FOK'
2007
2008
  accountId = self.safe_integer(params, 'account_id')
2008
- defaultType = self.safe_string(self.options, 'defaultType')
2009
- if defaultType == 'margin':
2009
+ marginMode = None
2010
+ marginMode, params = self.handle_margin_mode_and_params('createOrder', params)
2011
+ if marginMode is not None:
2010
2012
  if accountId is None:
2011
2013
  raise BadRequest(self.id + ' createOrder() requires an account_id parameter for margin orders')
2012
2014
  request['account_id'] = accountId
@@ -2473,9 +2475,10 @@ class coinex(Exchange, ImplicitAPI):
2473
2475
  'market': market['id'],
2474
2476
  }
2475
2477
  accountId = self.safe_integer(params, 'account_id')
2476
- defaultType = self.safe_string(self.options, 'defaultType')
2478
+ marginMode = None
2479
+ marginMode, params = self.handle_margin_mode_and_params('cancelOrder', params)
2477
2480
  clientOrderId = self.safe_string_2(params, 'client_id', 'clientOrderId')
2478
- if defaultType == 'margin':
2481
+ if marginMode is not None:
2479
2482
  if accountId is None:
2480
2483
  raise BadRequest(self.id + ' cancelOrder() requires an account_id parameter for margin orders')
2481
2484
  request['account_id'] = accountId
@@ -2814,8 +2817,9 @@ class coinex(Exchange, ImplicitAPI):
2814
2817
  request['market'] = market['id']
2815
2818
  marketType, query = self.handle_market_type_and_params('fetchOrdersByStatus', market, params)
2816
2819
  accountId = self.safe_integer(params, 'account_id')
2817
- defaultType = self.safe_string(self.options, 'defaultType')
2818
- if defaultType == 'margin':
2820
+ marginMode = None
2821
+ marginMode, params = self.handle_margin_mode_and_params('fetchOrdersByStatus', params)
2822
+ if marginMode is not None:
2819
2823
  if accountId is None:
2820
2824
  raise BadRequest(self.id + ' fetchOpenOrders() and fetchClosedOrders() require an account_id parameter for margin orders')
2821
2825
  request['account_id'] = accountId
@@ -3179,8 +3183,9 @@ class coinex(Exchange, ImplicitAPI):
3179
3183
  raise ArgumentsRequired(self.id + ' fetchMyTrades() requires a symbol argument for non-spot markets')
3180
3184
  swap = (type == 'swap')
3181
3185
  accountId = self.safe_integer(params, 'account_id')
3182
- defaultType = self.safe_string(self.options, 'defaultType')
3183
- if defaultType == 'margin':
3186
+ marginMode = None
3187
+ marginMode, params = self.handle_margin_mode_and_params('fetchMyTrades', params)
3188
+ if marginMode is not None:
3184
3189
  if accountId is None:
3185
3190
  raise BadRequest(self.id + ' fetchMyTrades() requires an account_id parameter for margin trades')
3186
3191
  request['account_id'] = accountId
@@ -4418,9 +4423,10 @@ class coinex(Exchange, ImplicitAPI):
4418
4423
  else:
4419
4424
  request['limit'] = 100
4420
4425
  params = self.omit(params, 'page')
4421
- defaultType = self.safe_string(self.options, 'defaultType')
4426
+ marginMode = None
4427
+ marginMode, params = self.handle_margin_mode_and_params('fetchTransfers', params)
4422
4428
  response = None
4423
- if defaultType == 'margin':
4429
+ if marginMode is not None:
4424
4430
  response = self.privateGetMarginTransferHistory(self.extend(request, params))
4425
4431
  else:
4426
4432
  response = self.privateGetContractTransferHistory(self.extend(request, params))
@@ -4967,6 +4973,22 @@ class coinex(Exchange, ImplicitAPI):
4967
4973
  depositWithdrawFees[code] = self.assign_default_deposit_withdraw_fees(depositWithdrawFees[code], currency)
4968
4974
  return depositWithdrawFees
4969
4975
 
4976
+ def handle_margin_mode_and_params(self, methodName, params={}, defaultValue=None):
4977
+ """
4978
+ * @ignore
4979
+ marginMode specified by params["marginMode"], self.options["marginMode"], self.options["defaultMarginMode"], params["margin"] = True or self.options["defaultType"] = 'margin'
4980
+ :param dict params: extra parameters specific to the exchange api endpoint
4981
+ :returns Array: the marginMode in lowercase
4982
+ """
4983
+ defaultType = self.safe_string(self.options, 'defaultType')
4984
+ isMargin = self.safe_value(params, 'margin', False)
4985
+ marginMode = None
4986
+ marginMode, params = super(coinex, self).handle_margin_mode_and_params(methodName, params, defaultValue)
4987
+ if marginMode is None:
4988
+ if (defaultType == 'margin') or (isMargin is True):
4989
+ marginMode = 'isolated'
4990
+ return [marginMode, params]
4991
+
4970
4992
  def nonce(self):
4971
4993
  return self.milliseconds()
4972
4994
 
ccxt/deribit.py CHANGED
@@ -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
  def fetch_time(self, params={}):
419
564
  """
420
565
  fetches the current integer timestamp in milliseconds from the exchange server
ccxt/gate.py CHANGED
@@ -547,6 +547,7 @@ class gate(Exchange, ImplicitAPI):
547
547
  'multi_collateral/currency_quota': 20 / 15,
548
548
  'multi_collateral/currencies': 20 / 15,
549
549
  'multi_collateral/ltv': 20 / 15,
550
+ 'multi_collateral/fixed_rate': 20 / 15,
550
551
  },
551
552
  'post': {
552
553
  'collateral/orders': 20 / 15,
@@ -5168,7 +5169,7 @@ class gate(Exchange, ImplicitAPI):
5168
5169
  retrieve information on the maximum leverage, and maintenance margin for trades of varying trade sizes
5169
5170
  :see: https://www.gate.io/docs/developers/apiv4/en/#list-all-futures-contracts
5170
5171
  :see: https://www.gate.io/docs/developers/apiv4/en/#list-all-futures-contracts-2
5171
- :param str[]|None symbols: list of unified market symbols
5172
+ :param str[] [symbols]: list of unified market symbols
5172
5173
  :param dict [params]: extra parameters specific to the exchange API endpoint
5173
5174
  :returns dict: a dictionary of `leverage tiers structures <https://docs.ccxt.com/#/?id=leverage-tiers-structure>`, indexed by market symbols
5174
5175
  """
@@ -5306,6 +5307,32 @@ class gate(Exchange, ImplicitAPI):
5306
5307
  #
5307
5308
  return self.parse_market_leverage_tiers(response, market)
5308
5309
 
5310
+ def parse_emulated_leverage_tiers(self, info, market=None):
5311
+ maintenanceMarginUnit = self.safe_string(info, 'maintenance_rate') # '0.005',
5312
+ leverageMax = self.safe_string(info, 'leverage_max') # '100',
5313
+ riskLimitStep = self.safe_string(info, 'risk_limit_step') # '1000000',
5314
+ riskLimitMax = self.safe_string(info, 'risk_limit_max') # '16000000',
5315
+ initialMarginUnit = Precise.string_div('1', leverageMax)
5316
+ maintenanceMarginRate = maintenanceMarginUnit
5317
+ initialMarginRatio = initialMarginUnit
5318
+ floor = '0'
5319
+ tiers = []
5320
+ while(Precise.string_lt(floor, riskLimitMax)):
5321
+ cap = Precise.string_add(floor, riskLimitStep)
5322
+ tiers.append({
5323
+ 'tier': self.parse_number(Precise.string_div(cap, riskLimitStep)),
5324
+ 'currency': self.safe_string(market, 'settle'),
5325
+ 'minNotional': self.parse_number(floor),
5326
+ 'maxNotional': self.parse_number(cap),
5327
+ 'maintenanceMarginRate': self.parse_number(maintenanceMarginRate),
5328
+ 'maxLeverage': self.parse_number(Precise.string_div('1', initialMarginRatio)),
5329
+ 'info': info,
5330
+ })
5331
+ maintenanceMarginRate = Precise.string_add(maintenanceMarginRate, maintenanceMarginUnit)
5332
+ initialMarginRatio = Precise.string_add(initialMarginRatio, initialMarginUnit)
5333
+ floor = cap
5334
+ return tiers
5335
+
5309
5336
  def parse_market_leverage_tiers(self, info, market: Market = None):
5310
5337
  #
5311
5338
  # [
@@ -5318,6 +5345,8 @@ class gate(Exchange, ImplicitAPI):
5318
5345
  # }
5319
5346
  # ]
5320
5347
  #
5348
+ if not isinstance(info, list):
5349
+ return self.parse_emulated_leverage_tiers(info, market)
5321
5350
  minNotional = 0
5322
5351
  tiers = []
5323
5352
  for i in range(0, len(info)):
ccxt/novadax.py CHANGED
@@ -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
  },
ccxt/okcoin.py CHANGED
@@ -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,
ccxt/phemex.py CHANGED
@@ -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
  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
  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')
ccxt/poloniex.py CHANGED
@@ -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/pro/__init__.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
 
ccxt/pro/bequant.py CHANGED
@@ -5,11 +5,17 @@
5
5
 
6
6
  from ccxt.pro.hitbtc import hitbtc
7
7
 
8
+ import ccxt.async_support.bequant as bequantRest
9
+
8
10
 
9
11
  class bequant(hitbtc):
10
12
 
11
13
  def describe(self):
12
- return self.deep_extend(super(bequant, self).describe(), {
14
+ # eslint-disable-next-line new-cap
15
+ restInstance = bequantRest()
16
+ restDescribe = restInstance.describe()
17
+ extended = self.deep_extend(super(bequant, self).describe(), restDescribe)
18
+ return self.deep_extend(extended, {
13
19
  'id': 'bequant',
14
20
  'name': 'Bequant',
15
21
  'countries': ['MT'], # Malta
ccxt/pro/binance.py CHANGED
@@ -49,7 +49,7 @@ class binance(ccxt.async_support.binance):
49
49
  'ws': {
50
50
  'spot': 'wss://testnet.binance.vision/ws',
51
51
  'margin': 'wss://testnet.binance.vision/ws',
52
- 'future': 'wss://stream.binancefuture.com/ws',
52
+ 'future': 'wss://fstream.binancefuture.com/ws',
53
53
  'delivery': 'wss://dstream.binancefuture.com/ws',
54
54
  'ws': 'wss://testnet.binance.vision/ws-api/v3',
55
55
  },
@@ -1811,12 +1811,13 @@ class binance(ccxt.async_support.binance):
1811
1811
 
1812
1812
  async def watch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
1813
1813
  """
1814
- :see: https://binance-docs.github.io/apidocs/spot/en/#payload-order-update
1815
1814
  watches information on multiple orders made by the user
1816
- :param str symbol: unified market symbol of the market orders were made in
1815
+ :see: https://binance-docs.github.io/apidocs/spot/en/#payload-order-update
1816
+ :param str symbol: unified market symbol of the market the orders were made in
1817
1817
  :param int [since]: the earliest time in ms to fetch orders for
1818
1818
  :param int [limit]: the maximum number of order structures to retrieve
1819
1819
  :param dict [params]: extra parameters specific to the exchange API endpoint
1820
+ :param str|None [params.marginMode]: 'cross' or 'isolated', for spot margin
1820
1821
  :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1821
1822
  """
1822
1823
  await self.load_markets()
@@ -1836,8 +1837,10 @@ class binance(ccxt.async_support.binance):
1836
1837
  type = 'delivery'
1837
1838
  params = self.extend(params, {'type': type, 'symbol': symbol}) # needed inside authenticate for isolated margin
1838
1839
  await self.authenticate(params)
1840
+ marginMode = None
1841
+ marginMode, params = self.handle_margin_mode_and_params('watchOrders', params)
1839
1842
  urlType = type
1840
- if type == 'margin':
1843
+ if (type == 'margin') or ((type == 'spot') and (marginMode is not None)):
1841
1844
  urlType = 'spot' # spot-margin shares the same stream spot
1842
1845
  url = self.urls['api']['ws'][urlType] + '/' + self.options[type]['listenKey']
1843
1846
  client = self.client(url)