ccxt 4.4.61__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.
ccxt/__init__.py CHANGED
@@ -22,7 +22,7 @@
22
22
 
23
23
  # ----------------------------------------------------------------------------
24
24
 
25
- __version__ = '4.4.61'
25
+ __version__ = '4.4.62'
26
26
 
27
27
  # ----------------------------------------------------------------------------
28
28
 
ccxt/abstract/bybit.py CHANGED
@@ -48,6 +48,7 @@ class ImplicitAPI:
48
48
  public_get_v5_spot_lever_token_info = publicGetV5SpotLeverTokenInfo = Entry('v5/spot-lever-token/info', 'public', 'GET', {'cost': 5})
49
49
  public_get_v5_spot_lever_token_reference = publicGetV5SpotLeverTokenReference = Entry('v5/spot-lever-token/reference', 'public', 'GET', {'cost': 5})
50
50
  public_get_v5_spot_margin_trade_data = publicGetV5SpotMarginTradeData = Entry('v5/spot-margin-trade/data', 'public', 'GET', {'cost': 5})
51
+ public_get_v5_spot_margin_trade_collateral = publicGetV5SpotMarginTradeCollateral = Entry('v5/spot-margin-trade/collateral', 'public', 'GET', {'cost': 5})
51
52
  public_get_v5_spot_cross_margin_trade_data = publicGetV5SpotCrossMarginTradeData = Entry('v5/spot-cross-margin-trade/data', 'public', 'GET', {'cost': 5})
52
53
  public_get_v5_spot_cross_margin_trade_pledge_token = publicGetV5SpotCrossMarginTradePledgeToken = Entry('v5/spot-cross-margin-trade/pledge-token', 'public', 'GET', {'cost': 5})
53
54
  public_get_v5_spot_cross_margin_trade_borrow_token = publicGetV5SpotCrossMarginTradeBorrowToken = Entry('v5/spot-cross-margin-trade/borrow-token', 'public', 'GET', {'cost': 5})
@@ -4,7 +4,7 @@
4
4
 
5
5
  # -----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.4.61'
7
+ __version__ = '4.4.62'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  # -----------------------------------------------------------------------------
4
4
 
5
- __version__ = '4.4.61'
5
+ __version__ = '4.4.62'
6
6
 
7
7
  # -----------------------------------------------------------------------------
8
8
 
@@ -74,18 +74,20 @@ class Exchange(BaseExchange):
74
74
  self.verify = config.get('verify', self.verify)
75
75
  self.own_session = 'session' not in config
76
76
  self.cafile = config.get('cafile', certifi.where())
77
+ self.throttler = None
77
78
  super(Exchange, self).__init__(config)
78
- self.throttle = None
79
- self.init_rest_rate_limiter()
80
79
  self.markets_loading = None
81
80
  self.reloading_markets = False
82
81
 
83
- def init_rest_rate_limiter(self):
84
- self.throttle = Throttler(self.tokenBucket, self.asyncio_loop)
85
-
86
82
  def get_event_loop(self):
87
83
  return self.asyncio_loop
88
84
 
85
+ def init_throttler(self, cost=None):
86
+ self.throttler = Throttler(self.tokenBucket, self.asyncio_loop)
87
+
88
+ async def throttle(self, cost=None):
89
+ return await self.throttler(cost)
90
+
89
91
  def get_session(self):
90
92
  return self.session
91
93
 
@@ -107,7 +109,7 @@ class Exchange(BaseExchange):
107
109
  self.asyncio_loop = asyncio.get_running_loop()
108
110
  else:
109
111
  self.asyncio_loop = asyncio.get_event_loop()
110
- self.throttle.loop = self.asyncio_loop
112
+ self.throttler.loop = self.asyncio_loop
111
113
 
112
114
  if self.ssl_context is None:
113
115
  # Create our SSL context object with our CA cert file
@@ -4455,13 +4455,12 @@ class bingx(Exchange, ImplicitAPI):
4455
4455
  :param boolean [params.twap]: if fetching twap orders
4456
4456
  :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
4457
4457
  """
4458
- if symbol is None:
4459
- raise ArgumentsRequired(self.id + ' fetchClosedOrders() requires a symbol argument')
4460
4458
  await self.load_markets()
4461
- market = self.market(symbol)
4462
- request: dict = {
4463
- 'symbol': market['id'],
4464
- }
4459
+ market = None
4460
+ request: dict = {}
4461
+ if symbol is not None:
4462
+ market = self.market(symbol)
4463
+ request['symbol'] = market['id']
4465
4464
  type = None
4466
4465
  subType = None
4467
4466
  standard = None
@@ -74,7 +74,9 @@ class bybit(Exchange, ImplicitAPI):
74
74
  'createTrailingAmountOrder': True,
75
75
  'createTriggerOrder': True,
76
76
  'editOrder': True,
77
+ 'editOrders': True,
77
78
  'fetchBalance': True,
79
+ 'fetchBidsAsks': 'emulated',
78
80
  'fetchBorrowInterest': False, # temporarily disabled, doesn't work
79
81
  'fetchBorrowRateHistories': False,
80
82
  'fetchBorrowRateHistory': False,
@@ -255,6 +257,7 @@ class bybit(Exchange, ImplicitAPI):
255
257
  'v5/spot-lever-token/reference': 5,
256
258
  # spot margin trade
257
259
  'v5/spot-margin-trade/data': 5,
260
+ 'v5/spot-margin-trade/collateral': 5,
258
261
  'v5/spot-cross-margin-trade/data': 5,
259
262
  'v5/spot-cross-margin-trade/pledge-token': 5,
260
263
  'v5/spot-cross-margin-trade/borrow-token': 5,
@@ -1240,6 +1243,9 @@ class bybit(Exchange, ImplicitAPI):
1240
1243
  'fetchOHLCV': {
1241
1244
  'limit': 1000,
1242
1245
  },
1246
+ 'editOrders': {
1247
+ 'max': 10,
1248
+ },
1243
1249
  },
1244
1250
  'spot': {
1245
1251
  'extends': 'default',
@@ -2463,6 +2469,20 @@ class bybit(Exchange, ImplicitAPI):
2463
2469
  tickerList = self.safe_list(result, 'list', [])
2464
2470
  return self.parse_tickers(tickerList, parsedSymbols)
2465
2471
 
2472
+ async def fetch_bids_asks(self, symbols: Strings = None, params={}):
2473
+ """
2474
+ fetches the bid and ask price and volume for multiple markets
2475
+
2476
+ https://bybit-exchange.github.io/docs/v5/market/tickers
2477
+
2478
+ :param str[]|None symbols: unified symbols of the markets to fetch the bids and asks for, all markets are returned if not assigned
2479
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2480
+ :param str [params.subType]: *contract only* 'linear', 'inverse'
2481
+ :param str [params.baseCoin]: *option only* base coin, default is 'BTC'
2482
+ :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
2483
+ """
2484
+ return await self.fetch_tickers(symbols, params)
2485
+
2466
2486
  def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
2467
2487
  #
2468
2488
  # [
@@ -3985,13 +4005,15 @@ class bybit(Exchange, ImplicitAPI):
3985
4005
  price = self.safe_value(rawOrder, 'price')
3986
4006
  orderParams = self.safe_dict(rawOrder, 'params', {})
3987
4007
  orderRequest = self.create_order_request(marketId, type, side, amount, price, orderParams, isUta)
4008
+ del orderRequest['category']
3988
4009
  ordersRequests.append(orderRequest)
3989
4010
  symbols = self.market_symbols(orderSymbols, None, False, True, True)
3990
4011
  market = self.market(symbols[0])
4012
+ unifiedMarginStatus = self.safe_integer(self.options, 'unifiedMarginStatus', 3)
3991
4013
  category = None
3992
4014
  category, params = self.get_bybit_type('createOrders', market, params)
3993
- if category == 'inverse':
3994
- raise NotSupported(self.id + ' createOrders does not allow inverse orders')
4015
+ if (category == 'inverse') and (unifiedMarginStatus < 5):
4016
+ raise NotSupported(self.id + ' createOrders does not allow inverse orders for non UTA2.0 account')
3995
4017
  request: dict = {
3996
4018
  'category': category,
3997
4019
  'request': ordersRequests,
@@ -4158,6 +4180,91 @@ class bybit(Exchange, ImplicitAPI):
4158
4180
  'id': self.safe_string(result, 'orderId'),
4159
4181
  })
4160
4182
 
4183
+ async def edit_orders(self, orders: List[OrderRequest], params={}):
4184
+ """
4185
+ edit a list of trade orders
4186
+
4187
+ https://bybit-exchange.github.io/docs/v5/order/batch-amend
4188
+
4189
+ :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
4190
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4191
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
4192
+ """
4193
+ await self.load_markets()
4194
+ ordersRequests = []
4195
+ orderSymbols = []
4196
+ for i in range(0, len(orders)):
4197
+ rawOrder = orders[i]
4198
+ symbol = self.safe_string(rawOrder, 'symbol')
4199
+ orderSymbols.append(symbol)
4200
+ id = self.safe_string(rawOrder, 'id')
4201
+ type = self.safe_string(rawOrder, 'type')
4202
+ side = self.safe_string(rawOrder, 'side')
4203
+ amount = self.safe_value(rawOrder, 'amount')
4204
+ price = self.safe_value(rawOrder, 'price')
4205
+ orderParams = self.safe_dict(rawOrder, 'params', {})
4206
+ orderRequest = self.edit_order_request(id, symbol, type, side, amount, price, orderParams)
4207
+ del orderRequest['category']
4208
+ ordersRequests.append(orderRequest)
4209
+ orderSymbols = self.market_symbols(orderSymbols, None, False, True, True)
4210
+ market = self.market(orderSymbols[0])
4211
+ unifiedMarginStatus = self.safe_integer(self.options, 'unifiedMarginStatus', 3)
4212
+ category = None
4213
+ category, params = self.get_bybit_type('editOrders', market, params)
4214
+ if (category == 'inverse') and (unifiedMarginStatus < 5):
4215
+ raise NotSupported(self.id + ' editOrders does not allow inverse orders for non UTA2.0 account')
4216
+ request: dict = {
4217
+ 'category': category,
4218
+ 'request': ordersRequests,
4219
+ }
4220
+ response = await self.privatePostV5OrderAmendBatch(self.extend(request, params))
4221
+ result = self.safe_dict(response, 'result', {})
4222
+ data = self.safe_list(result, 'list', [])
4223
+ retInfo = self.safe_dict(response, 'retExtInfo', {})
4224
+ codes = self.safe_list(retInfo, 'list', [])
4225
+ # self.extend the error with the unsuccessful orders
4226
+ for i in range(0, len(codes)):
4227
+ code = codes[i]
4228
+ retCode = self.safe_integer(code, 'code')
4229
+ if retCode != 0:
4230
+ data[i] = self.extend(data[i], code)
4231
+ #
4232
+ # {
4233
+ # "retCode": 0,
4234
+ # "retMsg": "OK",
4235
+ # "result": {
4236
+ # "list": [
4237
+ # {
4238
+ # "category": "option",
4239
+ # "symbol": "ETH-30DEC22-500-C",
4240
+ # "orderId": "b551f227-7059-4fb5-a6a6-699c04dbd2f2",
4241
+ # "orderLinkId": ""
4242
+ # },
4243
+ # {
4244
+ # "category": "option",
4245
+ # "symbol": "ETH-30DEC22-700-C",
4246
+ # "orderId": "fa6a595f-1a57-483f-b9d3-30e9c8235a52",
4247
+ # "orderLinkId": ""
4248
+ # }
4249
+ # ]
4250
+ # },
4251
+ # "retExtInfo": {
4252
+ # "list": [
4253
+ # {
4254
+ # "code": 0,
4255
+ # "msg": "OK"
4256
+ # },
4257
+ # {
4258
+ # "code": 0,
4259
+ # "msg": "OK"
4260
+ # }
4261
+ # ]
4262
+ # },
4263
+ # "time": 1672222808060
4264
+ # }
4265
+ #
4266
+ return self.parse_orders(data)
4267
+
4161
4268
  def cancel_order_request(self, id: str, symbol: Str = None, params={}):
4162
4269
  market = self.market(symbol)
4163
4270
  request: dict = {
@@ -981,9 +981,9 @@ class kraken(Exchange, ImplicitAPI):
981
981
  'high': self.safe_string(high, 1),
982
982
  'low': self.safe_string(low, 1),
983
983
  'bid': self.safe_string(bid, 0),
984
- 'bidVolume': None,
984
+ 'bidVolume': self.safe_string(bid, 2),
985
985
  'ask': self.safe_string(ask, 0),
986
- 'askVolume': None,
986
+ 'askVolume': self.safe_string(ask, 2),
987
987
  'vwap': vwap,
988
988
  'open': self.safe_string(ticker, 'o'),
989
989
  'close': last,
@@ -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') or (type == 'PerpetualPilot'):
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,