ccxt 4.4.60__py2.py3-none-any.whl → 4.4.62__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.
@@ -7,7 +7,7 @@ from ccxt.async_support.base.exchange import Exchange
7
7
  from ccxt.abstract.phemex import ImplicitAPI
8
8
  import hashlib
9
9
  import numbers
10
- from ccxt.base.types import Any, Balances, Currencies, Currency, DepositAddress, Int, LeverageTier, LeverageTiers, MarginModification, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, FundingRate, Trade, Transaction, TransferEntry
10
+ from ccxt.base.types import Any, Balances, Conversion, Currencies, Currency, DepositAddress, Int, LeverageTier, LeverageTiers, MarginModification, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, FundingRate, Trade, Transaction, TransferEntry
11
11
  from typing import List
12
12
  from ccxt.base.errors import ExchangeError
13
13
  from ccxt.base.errors import AuthenticationError
@@ -50,6 +50,7 @@ class phemex(Exchange, ImplicitAPI):
50
50
  'cancelAllOrders': True,
51
51
  'cancelOrder': True,
52
52
  'closePosition': False,
53
+ 'createConvertTrade': True,
53
54
  'createOrder': True,
54
55
  'createReduceOnlyOrder': True,
55
56
  'createStopLimitOrder': True,
@@ -60,6 +61,9 @@ class phemex(Exchange, ImplicitAPI):
60
61
  'fetchBorrowRateHistories': False,
61
62
  'fetchBorrowRateHistory': False,
62
63
  'fetchClosedOrders': True,
64
+ 'fetchConvertQuote': True,
65
+ 'fetchConvertTrade': False,
66
+ 'fetchConvertTradeHistory': True,
63
67
  'fetchCrossBorrowRate': False,
64
68
  'fetchCrossBorrowRates': False,
65
69
  'fetchCurrencies': True,
@@ -1078,7 +1082,7 @@ class phemex(Exchange, ImplicitAPI):
1078
1082
  for i in range(0, len(products)):
1079
1083
  market = products[i]
1080
1084
  type = self.safe_string_lower(market, 'type')
1081
- if (type == 'perpetual') or (type == 'perpetualv2'):
1085
+ if (type == 'perpetual') or (type == 'perpetualv2') or (type == 'perpetualpilot'):
1082
1086
  id = self.safe_string(market, 'symbol')
1083
1087
  riskLimitValues = self.safe_value(riskLimitsById, id, {})
1084
1088
  market = self.extend(market, riskLimitValues)
@@ -1254,7 +1258,7 @@ class phemex(Exchange, ImplicitAPI):
1254
1258
  precise.decimals = precise.decimals - scale
1255
1259
  precise.reduce()
1256
1260
  preciseString = str(precise)
1257
- return self.parse_to_int(preciseString)
1261
+ return self.parse_to_numeric(preciseString)
1258
1262
 
1259
1263
  def to_ev(self, amount, market: Market = None):
1260
1264
  if (amount is None) or (market is None):
@@ -2547,7 +2551,6 @@ class phemex(Exchange, ImplicitAPI):
2547
2551
  market = self.market(symbol)
2548
2552
  requestSide = self.capitalize(side)
2549
2553
  type = self.capitalize(type)
2550
- reduceOnly = self.safe_bool(params, 'reduceOnly')
2551
2554
  request: dict = {
2552
2555
  # common
2553
2556
  'symbol': market['id'],
@@ -2630,8 +2633,10 @@ class phemex(Exchange, ImplicitAPI):
2630
2633
  posSide = self.safe_string_lower(params, 'posSide')
2631
2634
  if posSide is None:
2632
2635
  if hedged:
2636
+ reduceOnly = self.safe_bool(params, 'reduceOnly')
2633
2637
  if reduceOnly:
2634
2638
  side = 'sell' if (side == 'buy') else 'buy'
2639
+ params = self.omit(params, 'reduceOnly')
2635
2640
  posSide = 'Long' if (side == 'buy') else 'Short'
2636
2641
  else:
2637
2642
  posSide = 'Merged'
@@ -2709,7 +2714,6 @@ class phemex(Exchange, ImplicitAPI):
2709
2714
  else:
2710
2715
  request['stopLossEp'] = self.to_ep(stopLossPrice, market)
2711
2716
  params = self.omit(params, 'stopLossPrice')
2712
- params = self.omit(params, 'reduceOnly')
2713
2717
  response = None
2714
2718
  if market['settle'] == 'USDT':
2715
2719
  response = await self.privatePostGOrders(self.extend(request, params))
@@ -4760,6 +4764,218 @@ class phemex(Exchange, ImplicitAPI):
4760
4764
  'datetime': self.iso8601(timestamp),
4761
4765
  }, market)
4762
4766
 
4767
+ async def fetch_convert_quote(self, fromCode: str, toCode: str, amount: Num = None, params={}) -> Conversion:
4768
+ """
4769
+ fetch a quote for converting from one currency to another
4770
+
4771
+ https://phemex-docs.github.io/#rfq-quote
4772
+
4773
+ :param str fromCode: the currency that you want to sell and convert from
4774
+ :param str toCode: the currency that you want to buy and convert into
4775
+ :param float amount: how much you want to trade in units of the from currency
4776
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4777
+ :returns dict: a `conversion structure <https://docs.ccxt.com/#/?id=conversion-structure>`
4778
+ """
4779
+ await self.load_markets()
4780
+ fromCurrency = self.currency(fromCode)
4781
+ toCurrency = self.currency(toCode)
4782
+ valueScale = self.safe_integer(fromCurrency, 'valueScale')
4783
+ request: dict = {
4784
+ 'fromCurrency': fromCode,
4785
+ 'toCurrency': toCode,
4786
+ 'fromAmountEv': self.to_en(amount, valueScale),
4787
+ }
4788
+ response = await self.privateGetAssetsQuote(self.extend(request, params))
4789
+ #
4790
+ # {
4791
+ # "code": 0,
4792
+ # "msg": "OK",
4793
+ # "data": {
4794
+ # "code": "GIF...AAA",
4795
+ # "quoteArgs": {
4796
+ # "origin": 10,
4797
+ # "price": "0.00000939",
4798
+ # "proceeds": "0.00000000",
4799
+ # "ttlMs": 7000,
4800
+ # "expireAt": 1739875826009,
4801
+ # "requestAt": 1739875818009,
4802
+ # "quoteAt": 1739875816594
4803
+ # }
4804
+ # }
4805
+ # }
4806
+ #
4807
+ data = self.safe_dict(response, 'data', {})
4808
+ return self.parse_conversion(data, fromCurrency, toCurrency)
4809
+
4810
+ async def create_convert_trade(self, id: str, fromCode: str, toCode: str, amount: Num = None, params={}) -> Conversion:
4811
+ """
4812
+ convert from one currency to another
4813
+
4814
+ https://phemex-docs.github.io/#convert
4815
+
4816
+ :param str id: the id of the trade that you want to make
4817
+ :param str fromCode: the currency that you want to sell and convert from
4818
+ :param str toCode: the currency that you want to buy and convert into
4819
+ :param float [amount]: how much you want to trade in units of the from currency
4820
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4821
+ :returns dict: a `conversion structure <https://docs.ccxt.com/#/?id=conversion-structure>`
4822
+ """
4823
+ await self.load_markets()
4824
+ fromCurrency = self.currency(fromCode)
4825
+ toCurrency = self.currency(toCode)
4826
+ valueScale = self.safe_integer(fromCurrency, 'valueScale')
4827
+ request: dict = {
4828
+ 'code': id,
4829
+ 'fromCurrency': fromCode,
4830
+ 'toCurrency': toCode,
4831
+ }
4832
+ if amount is not None:
4833
+ request['fromAmountEv'] = self.to_en(amount, valueScale)
4834
+ response = await self.privatePostAssetsConvert(self.extend(request, params))
4835
+ #
4836
+ # {
4837
+ # "code": 0,
4838
+ # "msg": "OK",
4839
+ # "data": {
4840
+ # "moveOp": 0,
4841
+ # "fromCurrency": "USDT",
4842
+ # "toCurrency": "BTC",
4843
+ # "fromAmountEv": 4000000000,
4844
+ # "toAmountEv": 41511,
4845
+ # "linkKey": "45c8ed8e-d3f4-472d-8262-e464e8c46247",
4846
+ # "status": 10
4847
+ # }
4848
+ # }
4849
+ #
4850
+ data = self.safe_dict(response, 'data', {})
4851
+ fromCurrencyId = self.safe_string(data, 'fromCurrency')
4852
+ fromResult = self.safe_currency(fromCurrencyId, fromCurrency)
4853
+ toCurrencyId = self.safe_string(data, 'toCurrency')
4854
+ to = self.safe_currency(toCurrencyId, toCurrency)
4855
+ return self.parse_conversion(data, fromResult, to)
4856
+
4857
+ async def fetch_convert_trade_history(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Conversion]:
4858
+ """
4859
+ fetch the users history of conversion trades
4860
+
4861
+ https://phemex-docs.github.io/#query-convert-history
4862
+
4863
+ :param str [code]: the unified currency code
4864
+ :param int [since]: the earliest time in ms to fetch conversions for
4865
+ :param int [limit]: the maximum number of conversion structures to retrieve, default 20, max 200
4866
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4867
+ :param str [params.until]: the end time in ms
4868
+ :param str [params.fromCurrency]: the currency that you sold and converted from
4869
+ :param str [params.toCurrency]: the currency that you bought and converted into
4870
+ :returns dict[]: a list of `conversion structures <https://docs.ccxt.com/#/?id=conversion-structure>`
4871
+ """
4872
+ await self.load_markets()
4873
+ request: dict = {}
4874
+ if code is not None:
4875
+ request['fromCurrency'] = code
4876
+ if since is not None:
4877
+ request['startTime'] = since
4878
+ if limit is not None:
4879
+ request['limit'] = limit
4880
+ request, params = self.handle_until_option('endTime', request, params)
4881
+ response = await self.privateGetAssetsConvert(self.extend(request, params))
4882
+ #
4883
+ # {
4884
+ # "code": 0,
4885
+ # "msg": "OK",
4886
+ # "data": {
4887
+ # "total": 2,
4888
+ # "rows": [
4889
+ # {
4890
+ # "linkKey": "45c8ed8e-d3f4-472d-8262-e464e8c46247",
4891
+ # "createTime": 1739882294000,
4892
+ # "fromCurrency": "USDT",
4893
+ # "toCurrency": "BTC",
4894
+ # "fromAmountEv": 4000000000,
4895
+ # "toAmountEv": 41511,
4896
+ # "status": 10,
4897
+ # "conversionRate": 1037,
4898
+ # "errorCode": 0
4899
+ # },
4900
+ # ]
4901
+ # }
4902
+ # }
4903
+ #
4904
+ data = self.safe_dict(response, 'data', {})
4905
+ rows = self.safe_list(data, 'rows', [])
4906
+ return self.parse_conversions(rows, code, 'fromCurrency', 'toCurrency', since, limit)
4907
+
4908
+ def parse_conversion(self, conversion: dict, fromCurrency: Currency = None, toCurrency: Currency = None) -> Conversion:
4909
+ #
4910
+ # fetchConvertQuote
4911
+ #
4912
+ # {
4913
+ # "code": "GIF...AAA",
4914
+ # "quoteArgs": {
4915
+ # "origin": 10,
4916
+ # "price": "0.00000939",
4917
+ # "proceeds": "0.00000000",
4918
+ # "ttlMs": 7000,
4919
+ # "expireAt": 1739875826009,
4920
+ # "requestAt": 1739875818009,
4921
+ # "quoteAt": 1739875816594
4922
+ # }
4923
+ # }
4924
+ #
4925
+ # createConvertTrade
4926
+ #
4927
+ # {
4928
+ # "moveOp": 0,
4929
+ # "fromCurrency": "USDT",
4930
+ # "toCurrency": "BTC",
4931
+ # "fromAmountEv": 4000000000,
4932
+ # "toAmountEv": 41511,
4933
+ # "linkKey": "45c8ed8e-d3f4-472d-8262-e464e8c46247",
4934
+ # "status": 10
4935
+ # }
4936
+ #
4937
+ # fetchConvertTradeHistory
4938
+ #
4939
+ # {
4940
+ # "linkKey": "45c8ed8e-d3f4-472d-8262-e464e8c46247",
4941
+ # "createTime": 1739882294000,
4942
+ # "fromCurrency": "USDT",
4943
+ # "toCurrency": "BTC",
4944
+ # "fromAmountEv": 4000000000,
4945
+ # "toAmountEv": 41511,
4946
+ # "status": 10,
4947
+ # "conversionRate": 1037,
4948
+ # "errorCode": 0
4949
+ # }
4950
+ #
4951
+ quoteArgs = self.safe_dict(conversion, 'quoteArgs', {})
4952
+ requestTime = self.safe_integer(quoteArgs, 'requestAt')
4953
+ timestamp = self.safe_integer(conversion, 'createTime', requestTime)
4954
+ fromCoin = self.safe_string(conversion, 'fromCurrency', self.safe_string(fromCurrency, 'code'))
4955
+ fromCode = self.safe_currency_code(fromCoin, fromCurrency)
4956
+ toCoin = self.safe_string(conversion, 'toCurrency', self.safe_string(toCurrency, 'code'))
4957
+ toCode = self.safe_currency_code(toCoin, toCurrency)
4958
+ fromValueScale = self.safe_integer(fromCurrency, 'valueScale')
4959
+ toValueScale = self.safe_integer(toCurrency, 'valueScale')
4960
+ fromAmount = self.from_en(self.safe_string(conversion, 'fromAmountEv'), fromValueScale)
4961
+ if fromAmount is None and quoteArgs is not None:
4962
+ fromAmount = self.from_en(self.safe_string(quoteArgs, 'origin'), fromValueScale)
4963
+ toAmount = self.from_en(self.safe_string(conversion, 'toAmountEv'), toValueScale)
4964
+ if toAmount is None and quoteArgs is not None:
4965
+ toAmount = self.from_en(self.safe_string(quoteArgs, 'proceeds'), toValueScale)
4966
+ return {
4967
+ 'info': conversion,
4968
+ 'timestamp': timestamp,
4969
+ 'datetime': self.iso8601(timestamp),
4970
+ 'id': self.safe_string(conversion, 'code'),
4971
+ 'fromCurrency': fromCode,
4972
+ 'fromAmount': self.parse_number(fromAmount),
4973
+ 'toCurrency': toCode,
4974
+ 'toAmount': self.parse_number(toAmount),
4975
+ 'price': self.safe_number(quoteArgs, 'price'),
4976
+ 'fee': None,
4977
+ }
4978
+
4763
4979
  def handle_errors(self, httpCode: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
4764
4980
  if response is None:
4765
4981
  return None # fallback to default error handler
@@ -1150,6 +1150,7 @@ class whitebit(Exchange, ImplicitAPI):
1150
1150
  # "clientOrderId": "customId11",
1151
1151
  # "role": 2, # 1 = maker, 2 = taker
1152
1152
  # "deal": "0.00419198" # amount in money
1153
+ # "feeAsset": "USDT"
1153
1154
  # }
1154
1155
  #
1155
1156
  # fetchMyTrades
@@ -1165,6 +1166,7 @@ class whitebit(Exchange, ImplicitAPI):
1165
1166
  # "deal": "9.981007",
1166
1167
  # "fee": "0.009981007",
1167
1168
  # "orderId": 58166729555,
1169
+ # "feeAsset": "USDT"
1168
1170
  # }
1169
1171
  #
1170
1172
  market = self.safe_market(None, market)
@@ -1185,7 +1187,7 @@ class whitebit(Exchange, ImplicitAPI):
1185
1187
  if feeCost is not None:
1186
1188
  fee = {
1187
1189
  'cost': feeCost,
1188
- 'currency': market['quote'],
1190
+ 'currency': self.safe_currency_code(self.safe_string(trade, 'feeAsset')),
1189
1191
  }
1190
1192
  return self.safe_trade({
1191
1193
  'info': trade,
ccxt/base/exchange.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # -----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.4.60'
7
+ __version__ = '4.4.62'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
 
@@ -160,6 +160,7 @@ class Exchange(object):
160
160
  symbols = None
161
161
  codes = None
162
162
  timeframes = {}
163
+ tokenBucket = None
163
164
 
164
165
  fees = {
165
166
  'trading': {
@@ -188,6 +189,7 @@ class Exchange(object):
188
189
  urls = None
189
190
  api = None
190
191
  parseJsonResponse = True
192
+ throttler = None
191
193
 
192
194
  # PROXY & USER-AGENTS (see "examples/proxy-usage" file for explanation)
193
195
  proxy = None # for backwards compatibility
@@ -223,6 +225,7 @@ class Exchange(object):
223
225
  }
224
226
  headers = None
225
227
  origin = '*' # CORS origin
228
+ MAX_VALUE = float('inf')
226
229
  #
227
230
  proxies = None
228
231
 
@@ -404,15 +407,8 @@ class Exchange(object):
404
407
  else:
405
408
  setattr(self, key, settings[key])
406
409
 
407
- if self.markets:
408
- self.set_markets(self.markets)
409
-
410
410
  self.after_construct()
411
411
 
412
- is_sandbox = self.safe_bool_2(self.options, 'sandbox', 'testnet', False)
413
- if is_sandbox:
414
- self.set_sandbox_mode(is_sandbox)
415
-
416
412
  # convert all properties from underscore notation foo_bar to camelcase notation fooBar
417
413
  cls = type(self)
418
414
  for name in dir(self):
@@ -431,13 +427,6 @@ class Exchange(object):
431
427
  else:
432
428
  setattr(self, camelcase, attr)
433
429
 
434
- self.tokenBucket = self.extend({
435
- 'refillRate': 1.0 / self.rateLimit if self.rateLimit > 0 else float('inf'),
436
- 'delay': 0.001,
437
- 'capacity': 1.0,
438
- 'defaultCost': 1.0,
439
- }, getattr(self, 'tokenBucket', {}))
440
-
441
430
  if not self.session and self.synchronous:
442
431
  self.session = Session()
443
432
  self.session.trust_env = self.requests_trust_env
@@ -456,6 +445,10 @@ class Exchange(object):
456
445
  def __str__(self):
457
446
  return self.name
458
447
 
448
+ def init_throttler(self, cost=None):
449
+ # stub in sync
450
+ pass
451
+
459
452
  def throttle(self, cost=None):
460
453
  now = float(self.milliseconds())
461
454
  elapsed = now - self.lastRestRequestTimestamp
@@ -2745,8 +2738,35 @@ class Exchange(object):
2745
2738
  return timestamp
2746
2739
 
2747
2740
  def after_construct(self):
2741
+ # networks
2748
2742
  self.create_networks_by_id_object()
2749
2743
  self.features_generator()
2744
+ # init predefined markets if any
2745
+ if self.markets:
2746
+ self.set_markets(self.markets)
2747
+ # init the request rate limiter
2748
+ self.init_rest_rate_limiter()
2749
+ # sanbox mode
2750
+ isSandbox = self.safe_bool_2(self.options, 'sandbox', 'testnet', False)
2751
+ if isSandbox:
2752
+ self.set_sandbox_mode(isSandbox)
2753
+
2754
+ def init_rest_rate_limiter(self):
2755
+ if self.rateLimit is None or (self.id is not None and self.rateLimit == -1):
2756
+ raise ExchangeError(self.id + '.rateLimit property is not configured')
2757
+ refillRate = self.MAX_VALUE
2758
+ if self.rateLimit > 0:
2759
+ refillRate = 1 / self.rateLimit
2760
+ defaultBucket = {
2761
+ 'delay': 0.001,
2762
+ 'capacity': 1,
2763
+ 'cost': 1,
2764
+ 'maxCapacity': 1000,
2765
+ 'refillRate': refillRate,
2766
+ }
2767
+ existingBucket = {} if (self.tokenBucket is None) else self.tokenBucket
2768
+ self.tokenBucket = self.extend(defaultBucket, existingBucket)
2769
+ self.init_throttler()
2750
2770
 
2751
2771
  def features_generator(self):
2752
2772
  #
@@ -4665,20 +4685,27 @@ class Exchange(object):
4665
4685
  :param str [defaultValue]: assigned programatically in the method calling handleMarketTypeAndParams
4666
4686
  :returns [str, dict]: the market type and params with type and defaultType omitted
4667
4687
  """
4668
- defaultType = self.safe_string_2(self.options, 'defaultType', 'type', 'spot')
4669
- if defaultValue is None: # defaultValue takes precendence over exchange wide defaultType
4670
- defaultValue = defaultType
4688
+ # type from param
4689
+ type = self.safe_string_2(params, 'defaultType', 'type')
4690
+ if type is not None:
4691
+ params = self.omit(params, ['defaultType', 'type'])
4692
+ return [type, params]
4693
+ # type from market
4694
+ if market is not None:
4695
+ return [market['type'], params]
4696
+ # type from default-argument
4697
+ if defaultValue is not None:
4698
+ return [defaultValue, params]
4671
4699
  methodOptions = self.safe_dict(self.options, methodName)
4672
- methodType = defaultValue
4673
- if methodOptions is not None: # user defined methodType takes precedence over defaultValue
4700
+ if methodOptions is not None:
4674
4701
  if isinstance(methodOptions, str):
4675
- methodType = methodOptions
4702
+ return [methodOptions, params]
4676
4703
  else:
4677
- methodType = self.safe_string_2(methodOptions, 'defaultType', 'type', methodType)
4678
- marketType = methodType if (market is None) else market['type']
4679
- type = self.safe_string_2(params, 'defaultType', 'type', marketType)
4680
- params = self.omit(params, ['defaultType', 'type'])
4681
- return [type, params]
4704
+ typeFromMethod = self.safe_string_2(methodOptions, 'defaultType', 'type')
4705
+ if typeFromMethod is not None:
4706
+ return [typeFromMethod, params]
4707
+ defaultType = self.safe_string_2(self.options, 'defaultType', 'type', 'spot')
4708
+ return [defaultType, params]
4682
4709
 
4683
4710
  def handle_sub_type_and_params(self, methodName: str, market=None, params={}, defaultValue=None):
4684
4711
  subType = None
ccxt/bingx.py CHANGED
@@ -4454,13 +4454,12 @@ class bingx(Exchange, ImplicitAPI):
4454
4454
  :param boolean [params.twap]: if fetching twap orders
4455
4455
  :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
4456
4456
  """
4457
- if symbol is None:
4458
- raise ArgumentsRequired(self.id + ' fetchClosedOrders() requires a symbol argument')
4459
4457
  self.load_markets()
4460
- market = self.market(symbol)
4461
- request: dict = {
4462
- 'symbol': market['id'],
4463
- }
4458
+ market = None
4459
+ request: dict = {}
4460
+ if symbol is not None:
4461
+ market = self.market(symbol)
4462
+ request['symbol'] = market['id']
4464
4463
  type = None
4465
4464
  subType = None
4466
4465
  standard = None
ccxt/bybit.py CHANGED
@@ -73,7 +73,9 @@ class bybit(Exchange, ImplicitAPI):
73
73
  'createTrailingAmountOrder': True,
74
74
  'createTriggerOrder': True,
75
75
  'editOrder': True,
76
+ 'editOrders': True,
76
77
  'fetchBalance': True,
78
+ 'fetchBidsAsks': 'emulated',
77
79
  'fetchBorrowInterest': False, # temporarily disabled, doesn't work
78
80
  'fetchBorrowRateHistories': False,
79
81
  'fetchBorrowRateHistory': False,
@@ -254,6 +256,7 @@ class bybit(Exchange, ImplicitAPI):
254
256
  'v5/spot-lever-token/reference': 5,
255
257
  # spot margin trade
256
258
  'v5/spot-margin-trade/data': 5,
259
+ 'v5/spot-margin-trade/collateral': 5,
257
260
  'v5/spot-cross-margin-trade/data': 5,
258
261
  'v5/spot-cross-margin-trade/pledge-token': 5,
259
262
  'v5/spot-cross-margin-trade/borrow-token': 5,
@@ -1239,6 +1242,9 @@ class bybit(Exchange, ImplicitAPI):
1239
1242
  'fetchOHLCV': {
1240
1243
  'limit': 1000,
1241
1244
  },
1245
+ 'editOrders': {
1246
+ 'max': 10,
1247
+ },
1242
1248
  },
1243
1249
  'spot': {
1244
1250
  'extends': 'default',
@@ -2462,6 +2468,20 @@ class bybit(Exchange, ImplicitAPI):
2462
2468
  tickerList = self.safe_list(result, 'list', [])
2463
2469
  return self.parse_tickers(tickerList, parsedSymbols)
2464
2470
 
2471
+ def fetch_bids_asks(self, symbols: Strings = None, params={}):
2472
+ """
2473
+ fetches the bid and ask price and volume for multiple markets
2474
+
2475
+ https://bybit-exchange.github.io/docs/v5/market/tickers
2476
+
2477
+ :param str[]|None symbols: unified symbols of the markets to fetch the bids and asks for, all markets are returned if not assigned
2478
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2479
+ :param str [params.subType]: *contract only* 'linear', 'inverse'
2480
+ :param str [params.baseCoin]: *option only* base coin, default is 'BTC'
2481
+ :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
2482
+ """
2483
+ return self.fetch_tickers(symbols, params)
2484
+
2465
2485
  def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
2466
2486
  #
2467
2487
  # [
@@ -3984,13 +4004,15 @@ class bybit(Exchange, ImplicitAPI):
3984
4004
  price = self.safe_value(rawOrder, 'price')
3985
4005
  orderParams = self.safe_dict(rawOrder, 'params', {})
3986
4006
  orderRequest = self.create_order_request(marketId, type, side, amount, price, orderParams, isUta)
4007
+ del orderRequest['category']
3987
4008
  ordersRequests.append(orderRequest)
3988
4009
  symbols = self.market_symbols(orderSymbols, None, False, True, True)
3989
4010
  market = self.market(symbols[0])
4011
+ unifiedMarginStatus = self.safe_integer(self.options, 'unifiedMarginStatus', 3)
3990
4012
  category = None
3991
4013
  category, params = self.get_bybit_type('createOrders', market, params)
3992
- if category == 'inverse':
3993
- raise NotSupported(self.id + ' createOrders does not allow inverse orders')
4014
+ if (category == 'inverse') and (unifiedMarginStatus < 5):
4015
+ raise NotSupported(self.id + ' createOrders does not allow inverse orders for non UTA2.0 account')
3994
4016
  request: dict = {
3995
4017
  'category': category,
3996
4018
  'request': ordersRequests,
@@ -4157,6 +4179,91 @@ class bybit(Exchange, ImplicitAPI):
4157
4179
  'id': self.safe_string(result, 'orderId'),
4158
4180
  })
4159
4181
 
4182
+ def edit_orders(self, orders: List[OrderRequest], params={}):
4183
+ """
4184
+ edit a list of trade orders
4185
+
4186
+ https://bybit-exchange.github.io/docs/v5/order/batch-amend
4187
+
4188
+ :param Array orders: list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params
4189
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4190
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
4191
+ """
4192
+ self.load_markets()
4193
+ ordersRequests = []
4194
+ orderSymbols = []
4195
+ for i in range(0, len(orders)):
4196
+ rawOrder = orders[i]
4197
+ symbol = self.safe_string(rawOrder, 'symbol')
4198
+ orderSymbols.append(symbol)
4199
+ id = self.safe_string(rawOrder, 'id')
4200
+ type = self.safe_string(rawOrder, 'type')
4201
+ side = self.safe_string(rawOrder, 'side')
4202
+ amount = self.safe_value(rawOrder, 'amount')
4203
+ price = self.safe_value(rawOrder, 'price')
4204
+ orderParams = self.safe_dict(rawOrder, 'params', {})
4205
+ orderRequest = self.edit_order_request(id, symbol, type, side, amount, price, orderParams)
4206
+ del orderRequest['category']
4207
+ ordersRequests.append(orderRequest)
4208
+ orderSymbols = self.market_symbols(orderSymbols, None, False, True, True)
4209
+ market = self.market(orderSymbols[0])
4210
+ unifiedMarginStatus = self.safe_integer(self.options, 'unifiedMarginStatus', 3)
4211
+ category = None
4212
+ category, params = self.get_bybit_type('editOrders', market, params)
4213
+ if (category == 'inverse') and (unifiedMarginStatus < 5):
4214
+ raise NotSupported(self.id + ' editOrders does not allow inverse orders for non UTA2.0 account')
4215
+ request: dict = {
4216
+ 'category': category,
4217
+ 'request': ordersRequests,
4218
+ }
4219
+ response = self.privatePostV5OrderAmendBatch(self.extend(request, params))
4220
+ result = self.safe_dict(response, 'result', {})
4221
+ data = self.safe_list(result, 'list', [])
4222
+ retInfo = self.safe_dict(response, 'retExtInfo', {})
4223
+ codes = self.safe_list(retInfo, 'list', [])
4224
+ # self.extend the error with the unsuccessful orders
4225
+ for i in range(0, len(codes)):
4226
+ code = codes[i]
4227
+ retCode = self.safe_integer(code, 'code')
4228
+ if retCode != 0:
4229
+ data[i] = self.extend(data[i], code)
4230
+ #
4231
+ # {
4232
+ # "retCode": 0,
4233
+ # "retMsg": "OK",
4234
+ # "result": {
4235
+ # "list": [
4236
+ # {
4237
+ # "category": "option",
4238
+ # "symbol": "ETH-30DEC22-500-C",
4239
+ # "orderId": "b551f227-7059-4fb5-a6a6-699c04dbd2f2",
4240
+ # "orderLinkId": ""
4241
+ # },
4242
+ # {
4243
+ # "category": "option",
4244
+ # "symbol": "ETH-30DEC22-700-C",
4245
+ # "orderId": "fa6a595f-1a57-483f-b9d3-30e9c8235a52",
4246
+ # "orderLinkId": ""
4247
+ # }
4248
+ # ]
4249
+ # },
4250
+ # "retExtInfo": {
4251
+ # "list": [
4252
+ # {
4253
+ # "code": 0,
4254
+ # "msg": "OK"
4255
+ # },
4256
+ # {
4257
+ # "code": 0,
4258
+ # "msg": "OK"
4259
+ # }
4260
+ # ]
4261
+ # },
4262
+ # "time": 1672222808060
4263
+ # }
4264
+ #
4265
+ return self.parse_orders(data)
4266
+
4160
4267
  def cancel_order_request(self, id: str, symbol: Str = None, params={}):
4161
4268
  market = self.market(symbol)
4162
4269
  request: dict = {