ccxt 4.2.21__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 (47) 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/async_support/__init__.py +1 -1
  7. ccxt/async_support/base/exchange.py +1 -1
  8. ccxt/async_support/bigone.py +1 -0
  9. ccxt/async_support/binance.py +14 -3
  10. ccxt/async_support/bitget.py +11 -1
  11. ccxt/async_support/bitrue.py +1 -0
  12. ccxt/async_support/bybit.py +49 -10
  13. ccxt/async_support/coinbasepro.py +1 -0
  14. ccxt/async_support/coinex.py +34 -12
  15. ccxt/async_support/deribit.py +145 -0
  16. ccxt/async_support/okcoin.py +3 -0
  17. ccxt/async_support/phemex.py +5 -2
  18. ccxt/async_support/poloniex.py +1 -0
  19. ccxt/async_support/woo.py +1 -1
  20. ccxt/base/exchange.py +1 -1
  21. ccxt/bigone.py +1 -0
  22. ccxt/binance.py +14 -3
  23. ccxt/bitget.py +11 -1
  24. ccxt/bitrue.py +1 -0
  25. ccxt/bybit.py +49 -10
  26. ccxt/coinbasepro.py +1 -0
  27. ccxt/coinex.py +34 -12
  28. ccxt/deribit.py +145 -0
  29. ccxt/okcoin.py +3 -0
  30. ccxt/phemex.py +5 -2
  31. ccxt/poloniex.py +1 -0
  32. ccxt/pro/__init__.py +1 -1
  33. ccxt/pro/bequant.py +7 -1
  34. ccxt/pro/binance.py +7 -4
  35. ccxt/pro/binancecoinm.py +7 -1
  36. ccxt/pro/binanceus.py +7 -1
  37. ccxt/pro/bitcoincom.py +7 -1
  38. ccxt/pro/bitget.py +1 -1
  39. ccxt/pro/bitrue.py +5 -1
  40. ccxt/pro/okx.py +10 -2
  41. ccxt/test/test_async.py +14 -1
  42. ccxt/test/test_sync.py +14 -1
  43. ccxt/woo.py +1 -1
  44. {ccxt-4.2.21.dist-info → ccxt-4.2.22.dist-info}/METADATA +4 -4
  45. {ccxt-4.2.21.dist-info → ccxt-4.2.22.dist-info}/RECORD +47 -47
  46. {ccxt-4.2.21.dist-info → ccxt-4.2.22.dist-info}/WHEEL +0 -0
  47. {ccxt-4.2.21.dist-info → ccxt-4.2.22.dist-info}/top_level.txt +0 -0
@@ -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
@@ -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,
@@ -1850,23 +1850,26 @@ class phemex(Exchange, ImplicitAPI):
1850
1850
  async def fetch_balance(self, params={}) -> Balances:
1851
1851
  """
1852
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
1853
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
1854
1856
  :param dict [params]: extra parameters specific to the exchange API endpoint
1855
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
1856
1859
  :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
1857
1860
  """
1858
1861
  await self.load_markets()
1859
1862
  type = None
1860
1863
  type, params = self.handle_market_type_and_params('fetchBalance', None, params)
1861
1864
  code = self.safe_string(params, 'code')
1862
- params = self.omit(params, ['type', 'code'])
1865
+ params = self.omit(params, ['code'])
1863
1866
  response = None
1864
1867
  request = {}
1865
1868
  if (type != 'spot') and (type != 'swap'):
1866
1869
  raise BadRequest(self.id + ' does not support ' + type + ' markets, only spot and swap')
1867
1870
  if type == 'swap':
1868
1871
  settle = None
1869
- settle, params = self.handle_option_and_params(params, 'fetchBalance', 'settle')
1872
+ settle, params = self.handle_option_and_params(params, 'fetchBalance', 'settle', 'USDT')
1870
1873
  if code is not None or settle is not None:
1871
1874
  coin = None
1872
1875
  if code is not None:
@@ -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.21'
7
+ __version__ = '4.2.22'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
 
ccxt/bigone.py CHANGED
@@ -52,6 +52,7 @@ class bigone(Exchange, ImplicitAPI):
52
52
  'fetchCurrencies': True,
53
53
  'fetchDepositAddress': True,
54
54
  'fetchDeposits': True,
55
+ 'fetchFundingRate': False,
55
56
  'fetchMarkets': True,
56
57
  'fetchMyTrades': True,
57
58
  'fetchOHLCV': True,
ccxt/binance.py CHANGED
@@ -329,6 +329,7 @@ class binance(Exchange, ImplicitAPI):
329
329
  'convert/exchangeInfo': 50,
330
330
  'convert/assetInfo': 10,
331
331
  'convert/orderStatus': 0.6667,
332
+ 'convert/limit/queryOpenOrders': 20.001, # Weight(UID): 3000 => cost = 0.006667 * 3000 = 20.001
332
333
  'account/status': 0.1,
333
334
  'account/apiTradingStatus': 0.1,
334
335
  'account/apiRestrictions/ipRestriction': 0.1,
@@ -600,6 +601,8 @@ class binance(Exchange, ImplicitAPI):
600
601
  'loan/vip/repay': 40.002,
601
602
  'convert/getQuote': 1.3334, # Weight(UID): 200 => cost = 0.006667 * 200 = 1.3334
602
603
  'convert/acceptQuote': 3.3335, # Weight(UID): 500 => cost = 0.006667 * 500 = 3.3335
604
+ 'convert/limit/placeOrder': 3.3335, # Weight(UID): 500 => cost = 0.006667 * 500 = 3.3335
605
+ 'convert/limit/cancelOrder': 1.3334, # Weight(UID): 200 => cost = 0.006667 * 200 = 1.3334
603
606
  'portfolio/auto-collection': 150, # Weight(IP): 1500 => cost = 0.1 * 1500 = 150
604
607
  'portfolio/asset-collection': 6, # Weight(IP): 60 => cost = 0.1 * 60 = 6
605
608
  'portfolio/bnb-transfer': 150, # Weight(IP): 1500 => cost = 0.1 * 1500 = 150
@@ -7369,12 +7372,20 @@ class binance(Exchange, ImplicitAPI):
7369
7372
 
7370
7373
  def fetch_positions(self, symbols: Strings = None, params={}):
7371
7374
  """
7375
+ :see: https://binance-docs.github.io/apidocs/futures/en/#position-information-v2-user_data
7376
+ :see: https://binance-docs.github.io/apidocs/delivery/en/#position-information-user_data
7377
+ :see: https://binance-docs.github.io/apidocs/futures/en/#account-information-v2-user_data
7378
+ :see: https://binance-docs.github.io/apidocs/delivery/en/#account-information-user_data
7379
+ :see: https://binance-docs.github.io/apidocs/voptions/en/#option-position-information-user_data
7372
7380
  fetch all open positions
7373
- :param str[]|None symbols: list of unified market symbols
7381
+ :param str[] [symbols]: list of unified market symbols
7374
7382
  :param dict [params]: extra parameters specific to the exchange API endpoint
7383
+ :param str [method]: method name to call, "positionRisk", "account" or "option", default is "positionRisk"
7375
7384
  :returns dict[]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
7376
7385
  """
7377
- defaultMethod = self.safe_string(self.options, 'fetchPositions', 'positionRisk')
7386
+ defaultValue = self.safe_string(self.options, 'fetchPositions', 'positionRisk')
7387
+ defaultMethod = None
7388
+ defaultMethod, params = self.handle_option_and_params(params, 'fetchPositions', 'method', defaultValue)
7378
7389
  if defaultMethod == 'positionRisk':
7379
7390
  return self.fetch_positions_risk(symbols, params)
7380
7391
  elif defaultMethod == 'account':
@@ -7382,7 +7393,7 @@ class binance(Exchange, ImplicitAPI):
7382
7393
  elif defaultMethod == 'option':
7383
7394
  return self.fetch_option_positions(symbols, params)
7384
7395
  else:
7385
- raise NotSupported(self.id + '.options["fetchPositions"] = "' + defaultMethod + '" is invalid, please choose between "account", "positionRisk" and "option"')
7396
+ raise NotSupported(self.id + '.options["fetchPositions"]/params["method"] = "' + defaultMethod + '" is invalid, please choose between "account", "positionRisk" and "option"')
7386
7397
 
7387
7398
  def fetch_account_positions(self, symbols: Strings = None, params={}):
7388
7399
  """
ccxt/bitget.py CHANGED
@@ -58,15 +58,21 @@ class bitget(Exchange, ImplicitAPI):
58
58
  'cancelOrders': True,
59
59
  'closeAllPositions': True,
60
60
  'closePosition': True,
61
+ 'createDepositAddress': False,
61
62
  'createMarketBuyOrderWithCost': True,
62
63
  'createMarketOrderWithCost': False,
63
64
  'createMarketSellOrderWithCost': False,
64
65
  'createOrder': True,
65
66
  'createOrders': True,
66
67
  'createOrderWithTakeProfitAndStopLoss': True,
68
+ 'createPostOnlyOrder': True,
67
69
  'createReduceOnlyOrder': False,
70
+ 'createStopLimitOrder': True,
68
71
  'createStopLossOrder': True,
72
+ 'createStopMarketOrder': True,
73
+ 'createStopOrder': True,
69
74
  'createTakeProfitOrder': True,
75
+ 'createTrailingAmountOrder': False,
70
76
  'createTrailingPercentOrder': True,
71
77
  'createTriggerOrder': True,
72
78
  'editOrder': True,
@@ -84,6 +90,7 @@ class bitget(Exchange, ImplicitAPI):
84
90
  'fetchDepositAddress': True,
85
91
  'fetchDepositAddresses': False,
86
92
  'fetchDeposits': True,
93
+ 'fetchDepositsWithdrawals': False,
87
94
  'fetchDepositWithdrawFee': 'emulated',
88
95
  'fetchDepositWithdrawFees': True,
89
96
  'fetchFundingHistory': True,
@@ -97,7 +104,7 @@ class bitget(Exchange, ImplicitAPI):
97
104
  'fetchLeverage': True,
98
105
  'fetchLeverageTiers': False,
99
106
  'fetchLiquidations': False,
100
- 'fetchMarginMode': None,
107
+ 'fetchMarginMode': False,
101
108
  'fetchMarketLeverageTiers': True,
102
109
  'fetchMarkets': True,
103
110
  'fetchMarkOHLCV': True,
@@ -122,8 +129,10 @@ class bitget(Exchange, ImplicitAPI):
122
129
  'fetchTrades': True,
123
130
  'fetchTradingFee': True,
124
131
  'fetchTradingFees': True,
132
+ 'fetchTransactions': False,
125
133
  'fetchTransfer': False,
126
134
  'fetchTransfers': True,
135
+ 'fetchWithdrawAddresses': False,
127
136
  'fetchWithdrawal': False,
128
137
  'fetchWithdrawals': True,
129
138
  'reduceMargin': True,
@@ -132,6 +141,7 @@ class bitget(Exchange, ImplicitAPI):
132
141
  'setLeverage': True,
133
142
  'setMarginMode': True,
134
143
  'setPositionMode': True,
144
+ 'signIn': False,
135
145
  'transfer': True,
136
146
  'withdraw': True,
137
147
  },
ccxt/bitrue.py CHANGED
@@ -72,6 +72,7 @@ class bitrue(Exchange, ImplicitAPI):
72
72
  'fetchDepositsWithdrawals': False,
73
73
  'fetchDepositWithdrawFee': 'emulated',
74
74
  'fetchDepositWithdrawFees': True,
75
+ 'fetchFundingRate': False,
75
76
  'fetchIsolatedBorrowRate': False,
76
77
  'fetchIsolatedBorrowRates': False,
77
78
  'fetchMarginMode': False,
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