ccxt 4.4.7__py2.py3-none-any.whl → 4.4.8__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.7'
25
+ __version__ = '4.4.8'
26
26
 
27
27
  # ----------------------------------------------------------------------------
28
28
 
ccxt/abstract/binance.py CHANGED
@@ -702,6 +702,7 @@ class ImplicitAPI:
702
702
  papi_post_repay_futures_negative_balance = papiPostRepayFuturesNegativeBalance = Entry('repay-futures-negative-balance', 'papi', 'POST', {'cost': 150})
703
703
  papi_post_listenkey = papiPostListenKey = Entry('listenKey', 'papi', 'POST', {'cost': 1})
704
704
  papi_post_asset_collection = papiPostAssetCollection = Entry('asset-collection', 'papi', 'POST', {'cost': 3})
705
+ papi_post_margin_repay_debt = papiPostMarginRepayDebt = Entry('margin/repay-debt', 'papi', 'POST', {'cost': 0.4})
705
706
  papi_put_listenkey = papiPutListenKey = Entry('listenKey', 'papi', 'PUT', {'cost': 1})
706
707
  papi_delete_um_order = papiDeleteUmOrder = Entry('um/order', 'papi', 'DELETE', {'cost': 1})
707
708
  papi_delete_um_conditional_order = papiDeleteUmConditionalOrder = Entry('um/conditional/order', 'papi', 'DELETE', {'cost': 1})
@@ -702,6 +702,7 @@ class ImplicitAPI:
702
702
  papi_post_repay_futures_negative_balance = papiPostRepayFuturesNegativeBalance = Entry('repay-futures-negative-balance', 'papi', 'POST', {'cost': 150})
703
703
  papi_post_listenkey = papiPostListenKey = Entry('listenKey', 'papi', 'POST', {'cost': 1})
704
704
  papi_post_asset_collection = papiPostAssetCollection = Entry('asset-collection', 'papi', 'POST', {'cost': 3})
705
+ papi_post_margin_repay_debt = papiPostMarginRepayDebt = Entry('margin/repay-debt', 'papi', 'POST', {'cost': 0.4})
705
706
  papi_put_listenkey = papiPutListenKey = Entry('listenKey', 'papi', 'PUT', {'cost': 1})
706
707
  papi_delete_um_order = papiDeleteUmOrder = Entry('um/order', 'papi', 'DELETE', {'cost': 1})
707
708
  papi_delete_um_conditional_order = papiDeleteUmConditionalOrder = Entry('um/conditional/order', 'papi', 'DELETE', {'cost': 1})
@@ -754,6 +754,7 @@ class ImplicitAPI:
754
754
  papi_post_repay_futures_negative_balance = papiPostRepayFuturesNegativeBalance = Entry('repay-futures-negative-balance', 'papi', 'POST', {'cost': 150})
755
755
  papi_post_listenkey = papiPostListenKey = Entry('listenKey', 'papi', 'POST', {'cost': 1})
756
756
  papi_post_asset_collection = papiPostAssetCollection = Entry('asset-collection', 'papi', 'POST', {'cost': 3})
757
+ papi_post_margin_repay_debt = papiPostMarginRepayDebt = Entry('margin/repay-debt', 'papi', 'POST', {'cost': 0.4})
757
758
  papi_put_listenkey = papiPutListenKey = Entry('listenKey', 'papi', 'PUT', {'cost': 1})
758
759
  papi_delete_um_order = papiDeleteUmOrder = Entry('um/order', 'papi', 'DELETE', {'cost': 1})
759
760
  papi_delete_um_conditional_order = papiDeleteUmConditionalOrder = Entry('um/conditional/order', 'papi', 'DELETE', {'cost': 1})
@@ -702,6 +702,7 @@ class ImplicitAPI:
702
702
  papi_post_repay_futures_negative_balance = papiPostRepayFuturesNegativeBalance = Entry('repay-futures-negative-balance', 'papi', 'POST', {'cost': 150})
703
703
  papi_post_listenkey = papiPostListenKey = Entry('listenKey', 'papi', 'POST', {'cost': 1})
704
704
  papi_post_asset_collection = papiPostAssetCollection = Entry('asset-collection', 'papi', 'POST', {'cost': 3})
705
+ papi_post_margin_repay_debt = papiPostMarginRepayDebt = Entry('margin/repay-debt', 'papi', 'POST', {'cost': 0.4})
705
706
  papi_put_listenkey = papiPutListenKey = Entry('listenKey', 'papi', 'PUT', {'cost': 1})
706
707
  papi_delete_um_order = papiDeleteUmOrder = Entry('um/order', 'papi', 'DELETE', {'cost': 1})
707
708
  papi_delete_um_conditional_order = papiDeleteUmConditionalOrder = Entry('um/conditional/order', 'papi', 'DELETE', {'cost': 1})
ccxt/abstract/bybit.py CHANGED
@@ -132,6 +132,9 @@ class ImplicitAPI:
132
132
  private_get_v5_account_contract_transaction_log = privateGetV5AccountContractTransactionLog = Entry('v5/account/contract-transaction-log', 'private', 'GET', {'cost': 1})
133
133
  private_get_v5_account_smp_group = privateGetV5AccountSmpGroup = Entry('v5/account/smp-group', 'private', 'GET', {'cost': 1})
134
134
  private_get_v5_account_mmp_state = privateGetV5AccountMmpState = Entry('v5/account/mmp-state', 'private', 'GET', {'cost': 5})
135
+ private_get_v5_asset_exchange_query_coin_list = privateGetV5AssetExchangeQueryCoinList = Entry('v5/asset/exchange/query-coin-list', 'private', 'GET', {'cost': 0.5})
136
+ private_get_v5_asset_exchange_convert_result_query = privateGetV5AssetExchangeConvertResultQuery = Entry('v5/asset/exchange/convert-result-query', 'private', 'GET', {'cost': 0.5})
137
+ private_get_v5_asset_exchange_query_convert_history = privateGetV5AssetExchangeQueryConvertHistory = Entry('v5/asset/exchange/query-convert-history', 'private', 'GET', {'cost': 0.5})
135
138
  private_get_v5_asset_exchange_order_record = privateGetV5AssetExchangeOrderRecord = Entry('v5/asset/exchange/order-record', 'private', 'GET', {'cost': 5})
136
139
  private_get_v5_asset_delivery_record = privateGetV5AssetDeliveryRecord = Entry('v5/asset/delivery-record', 'private', 'GET', {'cost': 5})
137
140
  private_get_v5_asset_settlement_record = privateGetV5AssetSettlementRecord = Entry('v5/asset/settlement-record', 'private', 'GET', {'cost': 5})
@@ -270,6 +273,8 @@ class ImplicitAPI:
270
273
  private_post_v5_account_set_hedging_mode = privatePostV5AccountSetHedgingMode = Entry('v5/account/set-hedging-mode', 'private', 'POST', {'cost': 5})
271
274
  private_post_v5_account_mmp_modify = privatePostV5AccountMmpModify = Entry('v5/account/mmp-modify', 'private', 'POST', {'cost': 5})
272
275
  private_post_v5_account_mmp_reset = privatePostV5AccountMmpReset = Entry('v5/account/mmp-reset', 'private', 'POST', {'cost': 5})
276
+ private_post_v5_asset_exchange_quote_apply = privatePostV5AssetExchangeQuoteApply = Entry('v5/asset/exchange/quote-apply', 'private', 'POST', {'cost': 1})
277
+ private_post_v5_asset_exchange_convert_execute = privatePostV5AssetExchangeConvertExecute = Entry('v5/asset/exchange/convert-execute', 'private', 'POST', {'cost': 1})
273
278
  private_post_v5_asset_transfer_inter_transfer = privatePostV5AssetTransferInterTransfer = Entry('v5/asset/transfer/inter-transfer', 'private', 'POST', {'cost': 50})
274
279
  private_post_v5_asset_transfer_save_transfer_sub_member = privatePostV5AssetTransferSaveTransferSubMember = Entry('v5/asset/transfer/save-transfer-sub-member', 'private', 'POST', {'cost': 150})
275
280
  private_post_v5_asset_transfer_universal_transfer = privatePostV5AssetTransferUniversalTransfer = Entry('v5/asset/transfer/universal-transfer', 'private', 'POST', {'cost': 10})
ccxt/abstract/okx.py CHANGED
@@ -79,6 +79,7 @@ class ImplicitAPI:
79
79
  public_get_copytrading_public_preference_currency = publicGetCopytradingPublicPreferenceCurrency = Entry('copytrading/public-preference-currency', 'public', 'GET', {'cost': 4})
80
80
  public_get_copytrading_public_current_subpositions = publicGetCopytradingPublicCurrentSubpositions = Entry('copytrading/public-current-subpositions', 'public', 'GET', {'cost': 4})
81
81
  public_get_copytrading_public_subpositions_history = publicGetCopytradingPublicSubpositionsHistory = Entry('copytrading/public-subpositions-history', 'public', 'GET', {'cost': 4})
82
+ public_get_support_announcements_types = publicGetSupportAnnouncementsTypes = Entry('support/announcements-types', 'public', 'GET', {'cost': 20})
82
83
  private_get_rfq_counterparties = privateGetRfqCounterparties = Entry('rfq/counterparties', 'private', 'GET', {'cost': 4})
83
84
  private_get_rfq_maker_instrument_settings = privateGetRfqMakerInstrumentSettings = Entry('rfq/maker-instrument-settings', 'private', 'GET', {'cost': 4})
84
85
  private_get_rfq_mmp_config = privateGetRfqMmpConfig = Entry('rfq/mmp-config', 'private', 'GET', {'cost': 4})
@@ -208,6 +209,7 @@ class ImplicitAPI:
208
209
  private_get_broker_fd_if_rebate = privateGetBrokerFdIfRebate = Entry('broker/fd/if-rebate', 'private', 'GET', {'cost': 5})
209
210
  private_get_affiliate_invitee_detail = privateGetAffiliateInviteeDetail = Entry('affiliate/invitee/detail', 'private', 'GET', {'cost': 1})
210
211
  private_get_users_partner_if_rebate = privateGetUsersPartnerIfRebate = Entry('users/partner/if-rebate', 'private', 'GET', {'cost': 1})
212
+ private_get_support_announcements = privateGetSupportAnnouncements = Entry('support/announcements', 'private', 'GET', {'cost': 4})
211
213
  private_post_rfq_create_rfq = privatePostRfqCreateRfq = Entry('rfq/create-rfq', 'private', 'POST', {'cost': 4})
212
214
  private_post_rfq_cancel_rfq = privatePostRfqCancelRfq = Entry('rfq/cancel-rfq', 'private', 'POST', {'cost': 4})
213
215
  private_post_rfq_cancel_batch_rfqs = privatePostRfqCancelBatchRfqs = Entry('rfq/cancel-batch-rfqs', 'private', 'POST', {'cost': 10})
@@ -4,7 +4,7 @@
4
4
 
5
5
  # -----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.4.7'
7
+ __version__ = '4.4.8'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  # -----------------------------------------------------------------------------
4
4
 
5
- __version__ = '4.4.7'
5
+ __version__ = '4.4.8'
6
6
 
7
7
  # -----------------------------------------------------------------------------
8
8
 
@@ -1115,6 +1115,7 @@ class binance(Exchange, ImplicitAPI):
1115
1115
  'repay-futures-negative-balance': 150, # Weight(IP): 1500 => cost = 0.1 * 1500 = 150
1116
1116
  'listenKey': 1, # 1
1117
1117
  'asset-collection': 3,
1118
+ 'margin/repay-debt': 0.4, # Weight(Order): 0.4 =>(1000 / (50 * 0.4)) * 60 = 3000
1118
1119
  },
1119
1120
  'put': {
1120
1121
  'listenKey': 1, # 1
@@ -1232,6 +1233,7 @@ class binance(Exchange, ImplicitAPI):
1232
1233
  ],
1233
1234
  'fetchCurrencies': True, # self is a private call and it requires API keys
1234
1235
  # 'fetchTradesMethod': 'publicGetAggTrades', # publicGetTrades, publicGetHistoricalTrades, eapiPublicGetTrades
1236
+ # 'repayCrossMarginMethod': 'papiPostRepayLoan', # papiPostMarginRepayDebt
1235
1237
  'defaultTimeInForce': 'GTC', # 'GTC' = Good To Cancel(default), 'IOC' = Immediate Or Cancel
1236
1238
  'defaultType': 'spot', # 'spot', 'future', 'margin', 'delivery', 'option'
1237
1239
  'defaultSubType': None, # 'linear', 'inverse'
@@ -2879,7 +2881,7 @@ class binance(Exchange, ImplicitAPI):
2879
2881
  res = self.safe_value(results, i)
2880
2882
  if fetchMargins and isinstance(res, list):
2881
2883
  keysList = list(self.index_by(res, 'symbol').keys())
2882
- length = (self.options['crossMarginPairsData'])
2884
+ length = len(self.options['crossMarginPairsData'])
2883
2885
  # first one is the cross-margin promise
2884
2886
  if length == 0:
2885
2887
  self.options['crossMarginPairsData'] = keysList
@@ -11242,10 +11244,13 @@ class binance(Exchange, ImplicitAPI):
11242
11244
  repay borrowed margin and interest
11243
11245
  :see: https://developers.binance.com/docs/derivatives/portfolio-margin/trade/Margin-Account-Repay
11244
11246
  :see: https://developers.binance.com/docs/margin_trading/borrow-and-repay/Margin-Account-Borrow-Repay
11247
+ :see: https://developers.binance.com/docs/derivatives/portfolio-margin/trade/Margin-Account-Repay-Debt
11245
11248
  :param str code: unified currency code of the currency to repay
11246
11249
  :param float amount: the amount to repay
11247
11250
  :param dict [params]: extra parameters specific to the exchange API endpoint
11248
11251
  :param boolean [params.portfolioMargin]: set to True if you would like to repay margin in a portfolio margin account
11252
+ :param str [params.repayCrossMarginMethod]: *portfolio margin only* 'papiPostRepayLoan'(default), 'papiPostMarginRepayDebt'(alternative)
11253
+ :param str [params.specifyRepayAssets]: *portfolio margin papiPostMarginRepayDebt only* specific asset list to repay debt
11249
11254
  :returns dict: a `margin loan structure <https://docs.ccxt.com/#/?id=margin-loan-structure>`
11250
11255
  """
11251
11256
  await self.load_markets()
@@ -11258,17 +11263,37 @@ class binance(Exchange, ImplicitAPI):
11258
11263
  isPortfolioMargin = None
11259
11264
  isPortfolioMargin, params = self.handle_option_and_params_2(params, 'repayCrossMargin', 'papi', 'portfolioMargin', False)
11260
11265
  if isPortfolioMargin:
11261
- response = await self.papiPostRepayLoan(self.extend(request, params))
11266
+ method = None
11267
+ method, params = self.handle_option_and_params_2(params, 'repayCrossMargin', 'repayCrossMarginMethod', 'method')
11268
+ if method == 'papiPostMarginRepayDebt':
11269
+ response = await self.papiPostMarginRepayDebt(self.extend(request, params))
11270
+ #
11271
+ # {
11272
+ # "asset": "USDC",
11273
+ # "amount": 10,
11274
+ # "specifyRepayAssets": null,
11275
+ # "updateTime": 1727170761267,
11276
+ # "success": True
11277
+ # }
11278
+ #
11279
+ else:
11280
+ response = await self.papiPostRepayLoan(self.extend(request, params))
11281
+ #
11282
+ # {
11283
+ # "tranId": 108988250265,
11284
+ # "clientTag":""
11285
+ # }
11286
+ #
11262
11287
  else:
11263
11288
  request['isIsolated'] = 'FALSE'
11264
11289
  request['type'] = 'REPAY'
11265
11290
  response = await self.sapiPostMarginBorrowRepay(self.extend(request, params))
11266
- #
11267
- # {
11268
- # "tranId": 108988250265,
11269
- # "clientTag":""
11270
- # }
11271
- #
11291
+ #
11292
+ # {
11293
+ # "tranId": 108988250265,
11294
+ # "clientTag":""
11295
+ # }
11296
+ #
11272
11297
  return self.parse_margin_loan(response, currency)
11273
11298
 
11274
11299
  async def repay_isolated_margin(self, symbol: str, code: str, amount, params={}):
@@ -11370,13 +11395,25 @@ class binance(Exchange, ImplicitAPI):
11370
11395
  # "clientTag":""
11371
11396
  # }
11372
11397
  #
11398
+ # repayCrossMargin alternative endpoint
11399
+ #
11400
+ # {
11401
+ # "asset": "USDC",
11402
+ # "amount": 10,
11403
+ # "specifyRepayAssets": null,
11404
+ # "updateTime": 1727170761267,
11405
+ # "success": True
11406
+ # }
11407
+ #
11408
+ currencyId = self.safe_string(info, 'asset')
11409
+ timestamp = self.safe_integer(info, 'updateTime')
11373
11410
  return {
11374
11411
  'id': self.safe_integer(info, 'tranId'),
11375
- 'currency': self.safe_currency_code(None, currency),
11376
- 'amount': None,
11412
+ 'currency': self.safe_currency_code(currencyId, currency),
11413
+ 'amount': self.safe_number(info, 'amount'),
11377
11414
  'symbol': None,
11378
- 'timestamp': None,
11379
- 'datetime': None,
11415
+ 'timestamp': timestamp,
11416
+ 'datetime': self.iso8601(timestamp),
11380
11417
  'info': info,
11381
11418
  }
11382
11419
 
@@ -7,7 +7,7 @@ from ccxt.async_support.base.exchange import Exchange
7
7
  from ccxt.abstract.bybit import ImplicitAPI
8
8
  import asyncio
9
9
  import hashlib
10
- from ccxt.base.types import Balances, CrossBorrowRate, Currencies, Currency, Greeks, Int, LedgerEntry, Leverage, LeverageTier, LeverageTiers, Market, MarketInterface, Num, Option, OptionChain, Order, OrderBook, OrderRequest, CancellationRequest, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, Trade, TradingFeeInterface, TradingFees, Transaction, TransferEntry
10
+ from ccxt.base.types import Balances, Conversion, CrossBorrowRate, Currencies, Currency, Greeks, Int, LedgerEntry, Leverage, LeverageTier, LeverageTiers, Market, MarketInterface, Num, Option, OptionChain, Order, OrderBook, OrderRequest, CancellationRequest, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, Trade, TradingFeeInterface, TradingFees, Transaction, TransferEntry
11
11
  from typing import List
12
12
  from ccxt.base.errors import ExchangeError
13
13
  from ccxt.base.errors import AuthenticationError
@@ -57,6 +57,7 @@ class bybit(Exchange, ImplicitAPI):
57
57
  'cancelOrdersForSymbols': True,
58
58
  'closeAllPositions': False,
59
59
  'closePosition': False,
60
+ 'createConvertTrade': True,
60
61
  'createMarketBuyOrderWithCost': True,
61
62
  'createMarketSellOrderWithCost': True,
62
63
  'createOrder': True,
@@ -80,6 +81,10 @@ class bybit(Exchange, ImplicitAPI):
80
81
  'fetchCanceledOrders': True,
81
82
  'fetchClosedOrder': True,
82
83
  'fetchClosedOrders': True,
84
+ 'fetchConvertCurrencies': True,
85
+ 'fetchConvertQuote': True,
86
+ 'fetchConvertTrade': True,
87
+ 'fetchConvertTradeHistory': True,
83
88
  'fetchCrossBorrowRate': True,
84
89
  'fetchCrossBorrowRates': False,
85
90
  'fetchCurrencies': True,
@@ -346,6 +351,9 @@ class bybit(Exchange, ImplicitAPI):
346
351
  'v5/account/smp-group': 1,
347
352
  'v5/account/mmp-state': 5,
348
353
  # asset
354
+ 'v5/asset/exchange/query-coin-list': 0.5, # 100/s => cost = 50 / 100 = 0.5
355
+ 'v5/asset/exchange/convert-result-query': 0.5, # 100/s => cost = 50 / 100 = 0.5
356
+ 'v5/asset/exchange/query-convert-history': 0.5, # 100/s => cost = 50 / 100 = 0.5
349
357
  'v5/asset/exchange/order-record': 5, # 10/s => cost = 50 / 10 = 5
350
358
  'v5/asset/delivery-record': 5,
351
359
  'v5/asset/settlement-record': 5,
@@ -504,6 +512,8 @@ class bybit(Exchange, ImplicitAPI):
504
512
  'v5/account/mmp-modify': 5,
505
513
  'v5/account/mmp-reset': 5,
506
514
  # asset
515
+ 'v5/asset/exchange/quote-apply': 1, # 50/s
516
+ 'v5/asset/exchange/convert-execute': 1, # 50/s
507
517
  'v5/asset/transfer/inter-transfer': 50, # 1/s => cost = 50 / 1 = 50
508
518
  'v5/asset/transfer/save-transfer-sub-member': 150, # 1/3/s => cost = 50 / 1/3 = 150
509
519
  'v5/asset/transfer/universal-transfer': 10, # 5/s => cost = 50 / 5 = 10
@@ -8246,6 +8256,345 @@ class bybit(Exchange, ImplicitAPI):
8246
8256
  positions = self.parse_positions(rawPositions, symbols, params)
8247
8257
  return self.filter_by_since_limit(positions, since, limit)
8248
8258
 
8259
+ async def fetch_convert_currencies(self, params={}) -> Currencies:
8260
+ """
8261
+ fetches all available currencies that can be converted
8262
+ :see: https://bybit-exchange.github.io/docs/v5/asset/convert/convert-coin-list
8263
+ :param dict [params]: extra parameters specific to the exchange API endpoint
8264
+ :param str [params.accountType]: eb_convert_uta, eb_convert_spot, eb_convert_funding, eb_convert_inverse, or eb_convert_contract
8265
+ :returns dict: an associative dictionary of currencies
8266
+ """
8267
+ await self.load_markets()
8268
+ accountType = None
8269
+ enableUnifiedMargin, enableUnifiedAccount = await self.is_unified_enabled()
8270
+ isUnifiedAccount = (enableUnifiedMargin or enableUnifiedAccount)
8271
+ accountTypeDefault = 'eb_convert_uta' if isUnifiedAccount else 'eb_convert_spot'
8272
+ accountType, params = self.handle_option_and_params(params, 'fetchConvertCurrencies', 'accountType', accountTypeDefault)
8273
+ request: dict = {
8274
+ 'accountType': accountType,
8275
+ }
8276
+ response = await self.privateGetV5AssetExchangeQueryCoinList(self.extend(request, params))
8277
+ #
8278
+ # {
8279
+ # "retCode": 0,
8280
+ # "retMsg": "ok",
8281
+ # "result": {
8282
+ # "coins": [
8283
+ # {
8284
+ # "coin": "MATIC",
8285
+ # "fullName": "MATIC",
8286
+ # "icon": "https://s1.bycsi.com/app/assets/token/0552ae79c535c3095fa18f7b377dd2e9.svg",
8287
+ # "iconNight": "https://t1.bycsi.com/app/assets/token/f59301aef2d6ac2165c4c4603e672fb4.svg",
8288
+ # "accuracyLength": 8,
8289
+ # "coinType": "crypto",
8290
+ # "balance": "0",
8291
+ # "uBalance": "0",
8292
+ # "timePeriod": 0,
8293
+ # "singleFromMinLimit": "1.1",
8294
+ # "singleFromMaxLimit": "20001",
8295
+ # "singleToMinLimit": "0",
8296
+ # "singleToMaxLimit": "0",
8297
+ # "dailyFromMinLimit": "0",
8298
+ # "dailyFromMaxLimit": "0",
8299
+ # "dailyToMinLimit": "0",
8300
+ # "dailyToMaxLimit": "0",
8301
+ # "disableFrom": False,
8302
+ # "disableTo": False
8303
+ # },
8304
+ # ]
8305
+ # },
8306
+ # "retExtInfo": {},
8307
+ # "time": 1727256416250
8308
+ # }
8309
+ #
8310
+ result: dict = {}
8311
+ data = self.safe_dict(response, 'result', {})
8312
+ coins = self.safe_list(data, 'coins', [])
8313
+ for i in range(0, len(coins)):
8314
+ entry = coins[i]
8315
+ id = self.safe_string(entry, 'coin')
8316
+ disableFrom = self.safe_bool(entry, 'disableFrom')
8317
+ disableTo = self.safe_bool(entry, 'disableTo')
8318
+ inactive = (disableFrom or disableTo)
8319
+ code = self.safe_currency_code(id)
8320
+ result[code] = {
8321
+ 'info': entry,
8322
+ 'id': id,
8323
+ 'code': code,
8324
+ 'networks': None,
8325
+ 'type': self.safe_string(entry, 'coinType'),
8326
+ 'name': self.safe_string(entry, 'fullName'),
8327
+ 'active': not inactive,
8328
+ 'deposit': None,
8329
+ 'withdraw': self.safe_number(entry, 'balance'),
8330
+ 'fee': None,
8331
+ 'precision': None,
8332
+ 'limits': {
8333
+ 'amount': {
8334
+ 'min': self.safe_number(entry, 'singleFromMinLimit'),
8335
+ 'max': self.safe_number(entry, 'singleFromMaxLimit'),
8336
+ },
8337
+ 'withdraw': {
8338
+ 'min': None,
8339
+ 'max': None,
8340
+ },
8341
+ 'deposit': {
8342
+ 'min': None,
8343
+ 'max': None,
8344
+ },
8345
+ },
8346
+ 'created': None,
8347
+ }
8348
+ return result
8349
+
8350
+ async def fetch_convert_quote(self, fromCode: str, toCode: str, amount: Num = None, params={}) -> Conversion:
8351
+ """
8352
+ fetch a quote for converting from one currency to another
8353
+ :see: https://bybit-exchange.github.io/docs/v5/asset/convert/apply-quote
8354
+ :param str fromCode: the currency that you want to sell and convert from
8355
+ :param str toCode: the currency that you want to buy and convert into
8356
+ :param float [amount]: how much you want to trade in units of the from currency
8357
+ :param dict [params]: extra parameters specific to the exchange API endpoint
8358
+ :param str [params.accountType]: eb_convert_uta, eb_convert_spot, eb_convert_funding, eb_convert_inverse, or eb_convert_contract
8359
+ :returns dict: a `conversion structure <https://docs.ccxt.com/#/?id=conversion-structure>`
8360
+ """
8361
+ await self.load_markets()
8362
+ accountType = None
8363
+ enableUnifiedMargin, enableUnifiedAccount = await self.is_unified_enabled()
8364
+ isUnifiedAccount = (enableUnifiedMargin or enableUnifiedAccount)
8365
+ accountTypeDefault = 'eb_convert_uta' if isUnifiedAccount else 'eb_convert_spot'
8366
+ accountType, params = self.handle_option_and_params(params, 'fetchConvertQuote', 'accountType', accountTypeDefault)
8367
+ request: dict = {
8368
+ 'fromCoin': fromCode,
8369
+ 'toCoin': toCode,
8370
+ 'requestAmount': self.number_to_string(amount),
8371
+ 'requestCoin': fromCode,
8372
+ 'accountType': accountType,
8373
+ }
8374
+ response = await self.privatePostV5AssetExchangeQuoteApply(self.extend(request, params))
8375
+ #
8376
+ # {
8377
+ # "retCode": 0,
8378
+ # "retMsg": "ok",
8379
+ # "result": {
8380
+ # "quoteTxId": "1010020692439481682687668224",
8381
+ # "exchangeRate": "0.000015330836780000",
8382
+ # "fromCoin": "USDT",
8383
+ # "fromCoinType": "crypto",
8384
+ # "toCoin": "BTC",
8385
+ # "toCoinType": "crypto",
8386
+ # "fromAmount": "10",
8387
+ # "toAmount": "0.000153308367800000",
8388
+ # "expiredTime": "1727257413353",
8389
+ # "requestId": ""
8390
+ # },
8391
+ # "retExtInfo": {},
8392
+ # "time": 1727257398375
8393
+ # }
8394
+ #
8395
+ data = self.safe_dict(response, 'result', {})
8396
+ fromCurrencyId = self.safe_string(data, 'fromCoin', fromCode)
8397
+ fromCurrency = self.currency(fromCurrencyId)
8398
+ toCurrencyId = self.safe_string(data, 'toCoin', toCode)
8399
+ toCurrency = self.currency(toCurrencyId)
8400
+ return self.parse_conversion(data, fromCurrency, toCurrency)
8401
+
8402
+ async def create_convert_trade(self, id: str, fromCode: str, toCode: str, amount: Num = None, params={}) -> Conversion:
8403
+ """
8404
+ convert from one currency to another
8405
+ :see: https://bybit-exchange.github.io/docs/v5/asset/convert/confirm-quote
8406
+ :param str id: the id of the trade that you want to make
8407
+ :param str fromCode: the currency that you want to sell and convert from
8408
+ :param str toCode: the currency that you want to buy and convert into
8409
+ :param float amount: how much you want to trade in units of the from currency
8410
+ :param dict [params]: extra parameters specific to the exchange API endpoint
8411
+ :returns dict: a `conversion structure <https://docs.ccxt.com/#/?id=conversion-structure>`
8412
+ """
8413
+ await self.load_markets()
8414
+ request: dict = {
8415
+ 'quoteTxId': id,
8416
+ }
8417
+ response = await self.privatePostV5AssetExchangeConvertExecute(self.extend(request, params))
8418
+ #
8419
+ # {
8420
+ # "retCode": 0,
8421
+ # "retMsg": "ok",
8422
+ # "result": {
8423
+ # "exchangeStatus": "processing",
8424
+ # "quoteTxId": "1010020692439483803499737088"
8425
+ # },
8426
+ # "retExtInfo": {},
8427
+ # "time": 1727257904969
8428
+ # }
8429
+ #
8430
+ data = self.safe_dict(response, 'result', {})
8431
+ return self.parse_conversion(data)
8432
+
8433
+ async def fetch_convert_trade(self, id: str, code: Str = None, params={}) -> Conversion:
8434
+ """
8435
+ fetch the data for a conversion trade
8436
+ :see: https://bybit-exchange.github.io/docs/v5/asset/convert/get-convert-result
8437
+ :param str id: the id of the trade that you want to fetch
8438
+ :param str [code]: the unified currency code of the conversion trade
8439
+ :param dict [params]: extra parameters specific to the exchange API endpoint
8440
+ :param str [params.accountType]: eb_convert_uta, eb_convert_spot, eb_convert_funding, eb_convert_inverse, or eb_convert_contract
8441
+ :returns dict: a `conversion structure <https://docs.ccxt.com/#/?id=conversion-structure>`
8442
+ """
8443
+ await self.load_markets()
8444
+ accountType = None
8445
+ enableUnifiedMargin, enableUnifiedAccount = await self.is_unified_enabled()
8446
+ isUnifiedAccount = (enableUnifiedMargin or enableUnifiedAccount)
8447
+ accountTypeDefault = 'eb_convert_uta' if isUnifiedAccount else 'eb_convert_spot'
8448
+ accountType, params = self.handle_option_and_params(params, 'fetchConvertQuote', 'accountType', accountTypeDefault)
8449
+ request: dict = {
8450
+ 'quoteTxId': id,
8451
+ 'accountType': accountType,
8452
+ }
8453
+ response = await self.privateGetV5AssetExchangeConvertResultQuery(self.extend(request, params))
8454
+ #
8455
+ # {
8456
+ # "retCode": 0,
8457
+ # "retMsg": "ok",
8458
+ # "result": {
8459
+ # "result": {
8460
+ # "accountType": "eb_convert_uta",
8461
+ # "exchangeTxId": "1010020692439483803499737088",
8462
+ # "userId": "100406395",
8463
+ # "fromCoin": "USDT",
8464
+ # "fromCoinType": "crypto",
8465
+ # "fromAmount": "10",
8466
+ # "toCoin": "BTC",
8467
+ # "toCoinType": "crypto",
8468
+ # "toAmount": "0.00015344889",
8469
+ # "exchangeStatus": "success",
8470
+ # "extInfo": {},
8471
+ # "convertRate": "0.000015344889",
8472
+ # "createdAt": "1727257904726"
8473
+ # }
8474
+ # },
8475
+ # "retExtInfo": {},
8476
+ # "time": 1727258257216
8477
+ # }
8478
+ #
8479
+ data = self.safe_dict(response, 'result', {})
8480
+ result = self.safe_dict(data, 'result', {})
8481
+ fromCurrencyId = self.safe_string(result, 'fromCoin')
8482
+ toCurrencyId = self.safe_string(result, 'toCoin')
8483
+ fromCurrency = None
8484
+ toCurrency = None
8485
+ if fromCurrencyId is not None:
8486
+ fromCurrency = self.currency(fromCurrencyId)
8487
+ if toCurrencyId is not None:
8488
+ toCurrency = self.currency(toCurrencyId)
8489
+ return self.parse_conversion(result, fromCurrency, toCurrency)
8490
+
8491
+ async def fetch_convert_trade_history(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Conversion]:
8492
+ """
8493
+ fetch the users history of conversion trades
8494
+ :see: https://bybit-exchange.github.io/docs/v5/asset/convert/get-convert-history
8495
+ :param str [code]: the unified currency code
8496
+ :param int [since]: the earliest time in ms to fetch conversions for
8497
+ :param int [limit]: the maximum number of conversion structures to retrieve
8498
+ :param dict [params]: extra parameters specific to the exchange API endpoint
8499
+ :param str [params.accountType]: eb_convert_uta, eb_convert_spot, eb_convert_funding, eb_convert_inverse, or eb_convert_contract
8500
+ :returns dict[]: a list of `conversion structures <https://docs.ccxt.com/#/?id=conversion-structure>`
8501
+ """
8502
+ await self.load_markets()
8503
+ request: dict = {}
8504
+ if limit is not None:
8505
+ request['limit'] = limit
8506
+ response = await self.privateGetV5AssetExchangeQueryConvertHistory(self.extend(request, params))
8507
+ #
8508
+ # {
8509
+ # "retCode": 0,
8510
+ # "retMsg": "ok",
8511
+ # "result": {
8512
+ # "list": [
8513
+ # {
8514
+ # "accountType": "eb_convert_uta",
8515
+ # "exchangeTxId": "1010020692439483803499737088",
8516
+ # "userId": "100406395",
8517
+ # "fromCoin": "USDT",
8518
+ # "fromCoinType": "crypto",
8519
+ # "fromAmount": "10",
8520
+ # "toCoin": "BTC",
8521
+ # "toCoinType": "crypto",
8522
+ # "toAmount": "0.00015344889",
8523
+ # "exchangeStatus": "success",
8524
+ # "extInfo": {},
8525
+ # "convertRate": "0.000015344889",
8526
+ # "createdAt": "1727257904726"
8527
+ # }
8528
+ # ]
8529
+ # },
8530
+ # "retExtInfo": {},
8531
+ # "time": 1727258761874
8532
+ # }
8533
+ #
8534
+ data = self.safe_dict(response, 'result', {})
8535
+ dataList = self.safe_list(data, 'list', [])
8536
+ return self.parse_conversions(dataList, code, 'fromCoin', 'toCoin', since, limit)
8537
+
8538
+ def parse_conversion(self, conversion: dict, fromCurrency: Currency = None, toCurrency: Currency = None) -> Conversion:
8539
+ #
8540
+ # fetchConvertQuote
8541
+ #
8542
+ # {
8543
+ # "quoteTxId": "1010020692439481682687668224",
8544
+ # "exchangeRate": "0.000015330836780000",
8545
+ # "fromCoin": "USDT",
8546
+ # "fromCoinType": "crypto",
8547
+ # "toCoin": "BTC",
8548
+ # "toCoinType": "crypto",
8549
+ # "fromAmount": "10",
8550
+ # "toAmount": "0.000153308367800000",
8551
+ # "expiredTime": "1727257413353",
8552
+ # "requestId": ""
8553
+ # }
8554
+ #
8555
+ # createConvertTrade
8556
+ #
8557
+ # {
8558
+ # "exchangeStatus": "processing",
8559
+ # "quoteTxId": "1010020692439483803499737088"
8560
+ # }
8561
+ #
8562
+ # fetchConvertTrade, fetchConvertTradeHistory
8563
+ #
8564
+ # {
8565
+ # "accountType": "eb_convert_uta",
8566
+ # "exchangeTxId": "1010020692439483803499737088",
8567
+ # "userId": "100406395",
8568
+ # "fromCoin": "USDT",
8569
+ # "fromCoinType": "crypto",
8570
+ # "fromAmount": "10",
8571
+ # "toCoin": "BTC",
8572
+ # "toCoinType": "crypto",
8573
+ # "toAmount": "0.00015344889",
8574
+ # "exchangeStatus": "success",
8575
+ # "extInfo": {},
8576
+ # "convertRate": "0.000015344889",
8577
+ # "createdAt": "1727257904726"
8578
+ # }
8579
+ #
8580
+ timestamp = self.safe_integer_2(conversion, 'expiredTime', 'createdAt')
8581
+ fromCoin = self.safe_string(conversion, 'fromCoin')
8582
+ fromCode = self.safe_currency_code(fromCoin, fromCurrency)
8583
+ to = self.safe_string(conversion, 'toCoin')
8584
+ toCode = self.safe_currency_code(to, toCurrency)
8585
+ return {
8586
+ 'info': conversion,
8587
+ 'timestamp': timestamp,
8588
+ 'datetime': self.iso8601(timestamp),
8589
+ 'id': self.safe_string_2(conversion, 'quoteTxId', 'exchangeTxId'),
8590
+ 'fromCurrency': fromCode,
8591
+ 'fromAmount': self.safe_number(conversion, 'fromAmount'),
8592
+ 'toCurrency': toCode,
8593
+ 'toAmount': self.safe_number(conversion, 'toAmount'),
8594
+ 'price': None,
8595
+ 'fee': None,
8596
+ }
8597
+
8249
8598
  def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
8250
8599
  url = self.implode_hostname(self.urls['api'][api]) + '/' + path
8251
8600
  if api == 'public':