ccxt 4.2.99__py2.py3-none-any.whl → 4.3.1__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.2.99'
25
+ __version__ = '4.3.1'
26
26
 
27
27
  # ----------------------------------------------------------------------------
28
28
 
ccxt/ascendex.py CHANGED
@@ -11,6 +11,7 @@ from typing import List
11
11
  from ccxt.base.errors import ExchangeError
12
12
  from ccxt.base.errors import AuthenticationError
13
13
  from ccxt.base.errors import PermissionDenied
14
+ from ccxt.base.errors import AccountSuspended
14
15
  from ccxt.base.errors import ArgumentsRequired
15
16
  from ccxt.base.errors import BadRequest
16
17
  from ccxt.base.errors import BadSymbol
@@ -368,7 +369,7 @@ class ascendex(Exchange, ImplicitAPI):
368
369
  '300013': InvalidOrder, # INVALID_BATCH_ORDER Some or all orders are invalid in batch order request
369
370
  '300014': InvalidOrder, # {"code":300014,"message":"Order price doesn't conform to the required tick size: 0.1","reason":"TICK_SIZE_VIOLATION"}
370
371
  '300020': InvalidOrder, # TRADING_RESTRICTED There is some trading restriction on account or asset
371
- '300021': InvalidOrder, # TRADING_DISABLED Trading is disabled on account or asset
372
+ '300021': AccountSuspended, # {"code":300021,"message":"Trading disabled for self account.","reason":"TRADING_DISABLED"}
372
373
  '300031': InvalidOrder, # NO_MARKET_PRICE No market price for market type order trading
373
374
  '310001': InsufficientFunds, # INVALID_MARGIN_BALANCE No enough margin balance
374
375
  '310002': InvalidOrder, # INVALID_MARGIN_ACCOUNT Not a valid account for margin trading
@@ -4,7 +4,7 @@
4
4
 
5
5
  # -----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.2.99'
7
+ __version__ = '4.3.1'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
 
@@ -11,6 +11,7 @@ from typing import List
11
11
  from ccxt.base.errors import ExchangeError
12
12
  from ccxt.base.errors import AuthenticationError
13
13
  from ccxt.base.errors import PermissionDenied
14
+ from ccxt.base.errors import AccountSuspended
14
15
  from ccxt.base.errors import ArgumentsRequired
15
16
  from ccxt.base.errors import BadRequest
16
17
  from ccxt.base.errors import BadSymbol
@@ -368,7 +369,7 @@ class ascendex(Exchange, ImplicitAPI):
368
369
  '300013': InvalidOrder, # INVALID_BATCH_ORDER Some or all orders are invalid in batch order request
369
370
  '300014': InvalidOrder, # {"code":300014,"message":"Order price doesn't conform to the required tick size: 0.1","reason":"TICK_SIZE_VIOLATION"}
370
371
  '300020': InvalidOrder, # TRADING_RESTRICTED There is some trading restriction on account or asset
371
- '300021': InvalidOrder, # TRADING_DISABLED Trading is disabled on account or asset
372
+ '300021': AccountSuspended, # {"code":300021,"message":"Trading disabled for self account.","reason":"TRADING_DISABLED"}
372
373
  '300031': InvalidOrder, # NO_MARKET_PRICE No market price for market type order trading
373
374
  '310001': InsufficientFunds, # INVALID_MARGIN_BALANCE No enough margin balance
374
375
  '310002': InvalidOrder, # INVALID_MARGIN_ACCOUNT Not a valid account for margin trading
@@ -2,7 +2,7 @@
2
2
 
3
3
  # -----------------------------------------------------------------------------
4
4
 
5
- __version__ = '4.2.99'
5
+ __version__ = '4.3.1'
6
6
 
7
7
  # -----------------------------------------------------------------------------
8
8
 
@@ -8,7 +8,7 @@ from ccxt.abstract.binance import ImplicitAPI
8
8
  import asyncio
9
9
  import hashlib
10
10
  import json
11
- from ccxt.base.types import Balances, Currencies, Currency, Greeks, Int, Leverage, Leverages, MarginMode, MarginModes, MarginModification, Market, MarketInterface, Num, Option, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFeeInterface, TradingFees, Transaction, TransferEntry
11
+ from ccxt.base.types import Balances, Conversion, Currencies, Currency, Greeks, Int, Leverage, Leverages, MarginMode, MarginModes, MarginModification, Market, MarketInterface, Num, Option, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFeeInterface, TradingFees, Transaction, TransferEntry
12
12
  from typing import List
13
13
  from ccxt.base.errors import ExchangeError
14
14
  from ccxt.base.errors import AuthenticationError
@@ -63,6 +63,7 @@ class binance(Exchange, ImplicitAPI):
63
63
  'cancelOrders': True, # contract only
64
64
  'closeAllPositions': False,
65
65
  'closePosition': False, # exchange specific closePosition parameter for binance createOrder is not synonymous with how CCXT uses closePositions
66
+ 'createConvertTrade': True,
66
67
  'createDepositAddress': False,
67
68
  'createLimitBuyOrder': True,
68
69
  'createLimitSellOrder': True,
@@ -11636,3 +11637,56 @@ class binance(Exchange, ImplicitAPI):
11636
11637
  'created': None,
11637
11638
  }
11638
11639
  return result
11640
+
11641
+ async def create_convert_trade(self, id: str, fromCode: str, toCode: str, amount: Num = None, params={}) -> Conversion:
11642
+ """
11643
+ convert from one currency to another
11644
+ :see: https://binance-docs.github.io/apidocs/spot/en/#busd-convert-trade
11645
+ :param str id: the id of the trade that you want to make
11646
+ :param str fromCode: the currency that you want to sell and convert from
11647
+ :param str toCode: the currency that you want to buy and convert into
11648
+ :param float [amount]: how much you want to trade in units of the from currency
11649
+ :param dict [params]: extra parameters specific to the exchange API endpoint
11650
+ :returns dict: a `conversion structure <https://docs.ccxt.com/#/?id=conversion-structure>`
11651
+ """
11652
+ await self.load_markets()
11653
+ request = {
11654
+ 'clientTranId': id,
11655
+ 'asset': fromCode,
11656
+ 'targetAsset': toCode,
11657
+ 'amount': amount,
11658
+ }
11659
+ response = await self.sapiPostAssetConvertTransfer(self.extend(request, params))
11660
+ #
11661
+ # {
11662
+ # "tranId": 118263407119,
11663
+ # "status": "S"
11664
+ # }
11665
+ #
11666
+ fromCurrency = self.currency(fromCode)
11667
+ toCurrency = self.currency(toCode)
11668
+ return self.parse_conversion(response, fromCurrency, toCurrency)
11669
+
11670
+ def parse_conversion(self, conversion, fromCurrency: Currency = None, toCurrency: Currency = None) -> Conversion:
11671
+ #
11672
+ # createConvertTrade
11673
+ #
11674
+ # {
11675
+ # "tranId": 118263407119,
11676
+ # "status": "S"
11677
+ # }
11678
+ #
11679
+ fromCode = self.safe_currency_code(None, fromCurrency)
11680
+ toCode = self.safe_currency_code(None, toCurrency)
11681
+ return {
11682
+ 'info': conversion,
11683
+ 'timestamp': None,
11684
+ 'datetime': None,
11685
+ 'id': self.safe_string(conversion, 'tranId'),
11686
+ 'fromCurrency': fromCode,
11687
+ 'fromAmount': None,
11688
+ 'toCurrency': toCode,
11689
+ 'toAmount': None,
11690
+ 'price': None,
11691
+ 'fee': None,
11692
+ }
@@ -59,6 +59,7 @@ class bitget(Exchange, ImplicitAPI):
59
59
  'cancelOrders': True,
60
60
  'closeAllPositions': True,
61
61
  'closePosition': True,
62
+ 'createConvertTrade': True,
62
63
  'createDepositAddress': False,
63
64
  'createMarketBuyOrderWithCost': True,
64
65
  'createMarketOrderWithCost': False,
@@ -7867,8 +7868,8 @@ class bitget(Exchange, ImplicitAPI):
7867
7868
  """
7868
7869
  await self.load_markets()
7869
7870
  request = {
7870
- 'fromCoin': fromCode.upper(),
7871
- 'toCoin': toCode.upper(),
7871
+ 'fromCoin': fromCode,
7872
+ 'toCoin': toCode,
7872
7873
  'fromCoinSize': self.number_to_string(amount),
7873
7874
  }
7874
7875
  response = await self.privateConvertGetV2ConvertQuotedPrice(self.extend(request, params))
@@ -7895,6 +7896,54 @@ class bitget(Exchange, ImplicitAPI):
7895
7896
  toCurrency = self.currency(toCurrencyId)
7896
7897
  return self.parse_conversion(data, fromCurrency, toCurrency)
7897
7898
 
7899
+ async def create_convert_trade(self, id: str, fromCode: str, toCode: str, amount: Num = None, params={}) -> Conversion:
7900
+ """
7901
+ convert from one currency to another
7902
+ :see: https://www.bitget.com/api-doc/common/convert/Trade
7903
+ :param str id: the id of the trade that you want to make
7904
+ :param str fromCode: the currency that you want to sell and convert from
7905
+ :param str toCode: the currency that you want to buy and convert into
7906
+ :param float amount: how much you want to trade in units of the from currency
7907
+ :param dict [params]: extra parameters specific to the exchange API endpoint
7908
+ :param str params['price']: the price of the conversion, obtained from fetchConvertQuote()
7909
+ :param str params['toAmount']: the amount you want to trade in units of the toCurrency, obtained from fetchConvertQuote()
7910
+ :returns dict: a `conversion structure <https://docs.ccxt.com/#/?id=conversion-structure>`
7911
+ """
7912
+ await self.load_markets()
7913
+ price = self.safe_string_2(params, 'price', 'cnvtPrice')
7914
+ if price is None:
7915
+ raise ArgumentsRequired(self.id + ' createConvertTrade() requires a price parameter')
7916
+ toAmount = self.safe_string_2(params, 'toAmount', 'toCoinSize')
7917
+ if toAmount is None:
7918
+ raise ArgumentsRequired(self.id + ' createConvertTrade() requires a toAmount parameter')
7919
+ params = self.omit(params, ['price', 'toAmount'])
7920
+ request = {
7921
+ 'traceId': id,
7922
+ 'fromCoin': fromCode,
7923
+ 'toCoin': toCode,
7924
+ 'fromCoinSize': self.number_to_string(amount),
7925
+ 'toCoinSize': toAmount,
7926
+ 'cnvtPrice': price,
7927
+ }
7928
+ response = await self.privateConvertPostV2ConvertTrade(self.extend(request, params))
7929
+ #
7930
+ # {
7931
+ # "code": "00000",
7932
+ # "msg": "success",
7933
+ # "requestTime": 1712123746203,
7934
+ # "data": {
7935
+ # "cnvtPrice": "0.99940076",
7936
+ # "toCoin": "USDC",
7937
+ # "toCoinSize": "4.99700379",
7938
+ # "ts": "1712123746217"
7939
+ # }
7940
+ # }
7941
+ #
7942
+ data = self.safe_dict(response, 'data', {})
7943
+ toCurrencyId = self.safe_string(data, 'toCoin', toCode)
7944
+ toCurrency = self.currency(toCurrencyId)
7945
+ return self.parse_conversion(data, None, toCurrency)
7946
+
7898
7947
  def parse_conversion(self, conversion, fromCurrency: Currency = None, toCurrency: Currency = None) -> Conversion:
7899
7948
  #
7900
7949
  # fetchConvertQuote
@@ -7909,6 +7958,15 @@ class bitget(Exchange, ImplicitAPI):
7909
7958
  # "fee": "0"
7910
7959
  # }
7911
7960
  #
7961
+ # createConvertTrade
7962
+ #
7963
+ # {
7964
+ # "cnvtPrice": "0.99940076",
7965
+ # "toCoin": "USDC",
7966
+ # "toCoinSize": "4.99700379",
7967
+ # "ts": "1712123746217"
7968
+ # }
7969
+ #
7912
7970
  timestamp = self.safe_integer(conversion, 'ts')
7913
7971
  fromCoin = self.safe_string(conversion, 'fromCoin')
7914
7972
  fromCode = self.safe_currency_code(fromCoin, fromCurrency)
@@ -4998,7 +4998,7 @@ class bybit(Exchange, ImplicitAPI):
4998
4998
  coin = self.safe_string(result, 'coin')
4999
4999
  currency = self.currency(coin)
5000
5000
  parsed = self.parse_deposit_addresses(chains, [currency['code']], False, {
5001
- 'currency': currency['id'],
5001
+ 'currency': currency['code'],
5002
5002
  })
5003
5003
  return self.index_by(parsed, 'network')
5004
5004
 
@@ -617,54 +617,52 @@ class coinex(Exchange, ImplicitAPI):
617
617
  async def fetch_markets(self, params={}) -> List[Market]:
618
618
  """
619
619
  retrieves data on all markets for coinex
620
- :see: https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot001_market002_all_market_info
621
- :see: https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures001_http006_market_list
620
+ :see: https://docs.coinex.com/api/v2/spot/market/http/list-market
621
+ :see: https://docs.coinex.com/api/v2/futures/market/http/list-market
622
622
  :param dict [params]: extra parameters specific to the exchange API endpoint
623
623
  :returns dict[]: an array of objects representing market data
624
624
  """
625
- promises = [
625
+ promisesUnresolved = [
626
626
  self.fetch_spot_markets(params),
627
627
  self.fetch_contract_markets(params),
628
628
  ]
629
- promises = await asyncio.gather(*promises)
629
+ promises = await asyncio.gather(*promisesUnresolved)
630
630
  spotMarkets = promises[0]
631
631
  swapMarkets = promises[1]
632
632
  return self.array_concat(spotMarkets, swapMarkets)
633
633
 
634
634
  async def fetch_spot_markets(self, params):
635
- response = await self.v1PublicGetMarketInfo(params)
635
+ response = await self.v2PublicGetSpotMarket(params)
636
636
  #
637
637
  # {
638
638
  # "code": 0,
639
- # "data": {
640
- # "WAVESBTC": {
641
- # "name": "WAVESBTC",
642
- # "min_amount": "1",
643
- # "maker_fee_rate": "0.001",
644
- # "taker_fee_rate": "0.001",
645
- # "pricing_name": "BTC",
646
- # "pricing_decimal": 8,
647
- # "trading_name": "WAVES",
648
- # "trading_decimal": 8
649
- # }
650
- # }
639
+ # "data": [
640
+ # {
641
+ # "base_ccy": "SORA",
642
+ # "base_ccy_precision": 8,
643
+ # "is_amm_available": True,
644
+ # "is_margin_available": False,
645
+ # "maker_fee_rate": "0.003",
646
+ # "market": "SORAUSDT",
647
+ # "min_amount": "500",
648
+ # "quote_ccy": "USDT",
649
+ # "quote_ccy_precision": 6,
650
+ # "taker_fee_rate": "0.003"
651
+ # },
652
+ # ],
653
+ # "message": "OK"
651
654
  # }
652
655
  #
653
- markets = self.safe_value(response, 'data', {})
656
+ markets = self.safe_list(response, 'data', [])
654
657
  result = []
655
- keys = list(markets.keys())
656
- for i in range(0, len(keys)):
657
- key = keys[i]
658
- market = markets[key]
659
- id = self.safe_string(market, 'name')
660
- tradingName = self.safe_string(market, 'trading_name')
661
- baseId = tradingName
662
- quoteId = self.safe_string(market, 'pricing_name')
658
+ for i in range(0, len(markets)):
659
+ market = markets[i]
660
+ id = self.safe_string(market, 'market')
661
+ baseId = self.safe_string(market, 'base_ccy')
662
+ quoteId = self.safe_string(market, 'quote_ccy')
663
663
  base = self.safe_currency_code(baseId)
664
664
  quote = self.safe_currency_code(quoteId)
665
665
  symbol = base + '/' + quote
666
- if tradingName == id:
667
- symbol = id
668
666
  result.append({
669
667
  'id': id,
670
668
  'symbol': symbol,
@@ -692,8 +690,8 @@ class coinex(Exchange, ImplicitAPI):
692
690
  'strike': None,
693
691
  'optionType': None,
694
692
  'precision': {
695
- 'amount': self.parse_number(self.parse_precision(self.safe_string(market, 'trading_decimal'))),
696
- 'price': self.parse_number(self.parse_precision(self.safe_string(market, 'pricing_decimal'))),
693
+ 'amount': self.parse_number(self.parse_precision(self.safe_string(market, 'base_ccy_precision'))),
694
+ 'price': self.parse_number(self.parse_precision(self.safe_string(market, 'quote_ccy_precision'))),
697
695
  },
698
696
  'limits': {
699
697
  'leverage': {
@@ -719,45 +717,43 @@ class coinex(Exchange, ImplicitAPI):
719
717
  return result
720
718
 
721
719
  async def fetch_contract_markets(self, params):
722
- response = await self.v1PerpetualPublicGetMarketList(params)
720
+ response = await self.v2PublicGetFuturesMarket(params)
723
721
  #
724
722
  # {
725
723
  # "code": 0,
726
724
  # "data": [
727
725
  # {
728
- # "name": "BTCUSD",
729
- # "type": 2, # 1: USDT-M Contracts, 2: Coin-M Contracts
730
- # "leverages": ["3", "5", "8", "10", "15", "20", "30", "50", "100"],
731
- # "stock": "BTC",
732
- # "money": "USD",
733
- # "fee_prec": 5,
734
- # "stock_prec": 8,
735
- # "money_prec": 1,
736
- # "amount_prec": 0,
737
- # "amount_min": "10",
738
- # "multiplier": "1",
739
- # "tick_size": "0.1", # Min. Price Increment
740
- # "available": True
726
+ # "base_ccy": "BTC",
727
+ # "base_ccy_precision": 8,
728
+ # "contract_type": "inverse",
729
+ # "leverage": ["1","2","3","5","8","10","15","20","30","50","100"],
730
+ # "maker_fee_rate": "0",
731
+ # "market": "BTCUSD",
732
+ # "min_amount": "10",
733
+ # "open_interest_volume": "2566879",
734
+ # "quote_ccy": "USD",
735
+ # "quote_ccy_precision": 2,
736
+ # "taker_fee_rate": "0"
741
737
  # },
742
738
  # ],
743
739
  # "message": "OK"
744
740
  # }
745
741
  #
746
- markets = self.safe_value(response, 'data', [])
742
+ markets = self.safe_list(response, 'data', [])
747
743
  result = []
748
744
  for i in range(0, len(markets)):
749
745
  entry = markets[i]
750
746
  fees = self.fees
751
- leverages = self.safe_value(entry, 'leverages', [])
752
- subType = self.safe_integer(entry, 'type')
753
- linear = (subType == 1)
754
- inverse = (subType == 2)
755
- id = self.safe_string(entry, 'name')
756
- baseId = self.safe_string(entry, 'stock')
757
- quoteId = self.safe_string(entry, 'money')
747
+ leverages = self.safe_list(entry, 'leverage', [])
748
+ subType = self.safe_string(entry, 'contract_type')
749
+ linear = (subType == 'linear')
750
+ inverse = (subType == 'inverse')
751
+ id = self.safe_string(entry, 'market')
752
+ baseId = self.safe_string(entry, 'base_ccy')
753
+ quoteId = self.safe_string(entry, 'quote_ccy')
758
754
  base = self.safe_currency_code(baseId)
759
755
  quote = self.safe_currency_code(quoteId)
760
- settleId = 'USDT' if (subType == 1) else baseId
756
+ settleId = 'USDT' if (subType == 'linear') else baseId
761
757
  settle = self.safe_currency_code(settleId)
762
758
  symbol = base + '/' + quote + ':' + settle
763
759
  leveragesLength = len(leverages)
@@ -776,20 +772,20 @@ class coinex(Exchange, ImplicitAPI):
776
772
  'swap': True,
777
773
  'future': False,
778
774
  'option': False,
779
- 'active': self.safe_value(entry, 'available'),
775
+ 'active': None,
780
776
  'contract': True,
781
777
  'linear': linear,
782
778
  'inverse': inverse,
783
779
  'taker': fees['trading']['taker'],
784
780
  'maker': fees['trading']['maker'],
785
- 'contractSize': self.safe_number(entry, 'multiplier'),
781
+ 'contractSize': self.parse_number('1'),
786
782
  'expiry': None,
787
783
  'expiryDatetime': None,
788
784
  'strike': None,
789
785
  'optionType': None,
790
786
  'precision': {
791
- 'amount': self.parse_number(self.parse_precision(self.safe_string(entry, 'amount_prec'))),
792
- 'price': self.parse_number(self.parse_precision(self.safe_string(entry, 'money_prec'))),
787
+ 'amount': self.parse_number(self.parse_precision(self.safe_string(entry, 'base_ccy_precision'))),
788
+ 'price': self.parse_number(self.parse_precision(self.safe_string(entry, 'quote_ccy_precision'))),
793
789
  },
794
790
  'limits': {
795
791
  'leverage': {
@@ -797,7 +793,7 @@ class coinex(Exchange, ImplicitAPI):
797
793
  'max': self.safe_number(leverages, leveragesLength - 1),
798
794
  },
799
795
  'amount': {
800
- 'min': self.safe_number(entry, 'amount_min'),
796
+ 'min': self.safe_number(entry, 'min_amount'),
801
797
  'max': None,
802
798
  },
803
799
  'price': {
@@ -1207,10 +1207,10 @@ class kucoin(Exchange, ImplicitAPI):
1207
1207
  # }
1208
1208
  #
1209
1209
  responses = await asyncio.gather(*promises)
1210
- currenciesResponse = self.safe_value(responses, 0, {})
1211
- currenciesData = self.safe_value(currenciesResponse, 'data', [])
1212
- additionalResponse = self.safe_value(responses, 1, {})
1213
- additionalData = self.safe_value(additionalResponse, 'data', [])
1210
+ currenciesResponse = self.safe_dict(responses, 0, {})
1211
+ currenciesData = self.safe_list(currenciesResponse, 'data', [])
1212
+ additionalResponse = self.safe_dict(responses, 1, {})
1213
+ additionalData = self.safe_list(additionalResponse, 'data', [])
1214
1214
  additionalDataGrouped = self.group_by(additionalData, 'currency')
1215
1215
  result = {}
1216
1216
  for i in range(0, len(currenciesData)):
@@ -1222,7 +1222,7 @@ class kucoin(Exchange, ImplicitAPI):
1222
1222
  isDepositEnabled = None
1223
1223
  networks = {}
1224
1224
  chains = self.safe_list(entry, 'chains', [])
1225
- extraChainsData = self.index_by(self.safe_value(additionalDataGrouped, id, []), 'chain')
1225
+ extraChainsData = self.index_by(self.safe_list(additionalDataGrouped, id, []), 'chain')
1226
1226
  rawPrecision = self.safe_string(entry, 'precision')
1227
1227
  precision = self.parse_number(self.parse_precision(rawPrecision))
1228
1228
  chainsLength = len(chains)
@@ -1350,7 +1350,7 @@ class kucoin(Exchange, ImplicitAPI):
1350
1350
  if networkCode is not None:
1351
1351
  request['chain'] = self.network_code_to_id(networkCode).lower()
1352
1352
  response = await self.privateGetWithdrawalsQuotas(self.extend(request, params))
1353
- data = self.safe_value(response, 'data')
1353
+ data = self.safe_dict(response, 'data', {})
1354
1354
  withdrawFees = {}
1355
1355
  withdrawFees[code] = self.safe_number(data, 'withdrawMinFee')
1356
1356
  return {
ccxt/async_support/okx.py CHANGED
@@ -59,6 +59,7 @@ class okx(Exchange, ImplicitAPI):
59
59
  'cancelOrders': True,
60
60
  'closeAllPositions': False,
61
61
  'closePosition': True,
62
+ 'createConvertTrade': True,
62
63
  'createDepositAddress': False,
63
64
  'createMarketBuyOrderWithCost': True,
64
65
  'createMarketSellOrderWithCost': True,
@@ -7151,6 +7152,57 @@ class okx(Exchange, ImplicitAPI):
7151
7152
  toCurrency = self.currency(toCurrencyId)
7152
7153
  return self.parse_conversion(result, fromCurrency, toCurrency)
7153
7154
 
7155
+ async def create_convert_trade(self, id: str, fromCode: str, toCode: str, amount: Num = None, params={}) -> Conversion:
7156
+ """
7157
+ convert from one currency to another
7158
+ :see: https://www.okx.com/docs-v5/en/#funding-account-rest-api-convert-trade
7159
+ :param str id: the id of the trade that you want to make
7160
+ :param str fromCode: the currency that you want to sell and convert from
7161
+ :param str toCode: the currency that you want to buy and convert into
7162
+ :param float [amount]: how much you want to trade in units of the from currency
7163
+ :param dict [params]: extra parameters specific to the exchange API endpoint
7164
+ :returns dict: a `conversion structure <https://docs.ccxt.com/#/?id=conversion-structure>`
7165
+ """
7166
+ await self.load_markets()
7167
+ request = {
7168
+ 'quoteId': id,
7169
+ 'baseCcy': fromCode,
7170
+ 'quoteCcy': toCode,
7171
+ 'szCcy': fromCode,
7172
+ 'sz': self.number_to_string(amount),
7173
+ 'side': 'sell',
7174
+ }
7175
+ response = await self.privatePostAssetConvertTrade(self.extend(request, params))
7176
+ #
7177
+ # {
7178
+ # "code": "0",
7179
+ # "data": [
7180
+ # {
7181
+ # "baseCcy": "ETH",
7182
+ # "clTReqId": "",
7183
+ # "fillBaseSz": "0.01023052",
7184
+ # "fillPx": "2932.40104429",
7185
+ # "fillQuoteSz": "30",
7186
+ # "instId": "ETH-USDT",
7187
+ # "quoteCcy": "USDT",
7188
+ # "quoteId": "quoterETH-USDT16461885104612381",
7189
+ # "side": "buy",
7190
+ # "state": "fullyFilled",
7191
+ # "tradeId": "trader16461885203381437",
7192
+ # "ts": "1646188520338"
7193
+ # }
7194
+ # ],
7195
+ # "msg": ""
7196
+ # }
7197
+ #
7198
+ data = self.safe_list(response, 'data', [])
7199
+ result = self.safe_dict(data, 0, {})
7200
+ fromCurrencyId = self.safe_string(result, 'baseCcy', fromCode)
7201
+ fromCurrency = self.currency(fromCurrencyId)
7202
+ toCurrencyId = self.safe_string(result, 'quoteCcy', toCode)
7203
+ toCurrency = self.currency(toCurrencyId)
7204
+ return self.parse_conversion(result, fromCurrency, toCurrency)
7205
+
7154
7206
  def parse_conversion(self, conversion, fromCurrency: Currency = None, toCurrency: Currency = None) -> Conversion:
7155
7207
  #
7156
7208
  # fetchConvertQuote
@@ -7171,7 +7223,24 @@ class okx(Exchange, ImplicitAPI):
7171
7223
  # "ttlMs": "10000"
7172
7224
  # }
7173
7225
  #
7174
- timestamp = self.safe_integer(conversion, 'quoteTime')
7226
+ # createConvertTrade
7227
+ #
7228
+ # {
7229
+ # "baseCcy": "ETH",
7230
+ # "clTReqId": "",
7231
+ # "fillBaseSz": "0.01023052",
7232
+ # "fillPx": "2932.40104429",
7233
+ # "fillQuoteSz": "30",
7234
+ # "instId": "ETH-USDT",
7235
+ # "quoteCcy": "USDT",
7236
+ # "quoteId": "quoterETH-USDT16461885104612381",
7237
+ # "side": "buy",
7238
+ # "state": "fullyFilled",
7239
+ # "tradeId": "trader16461885203381437",
7240
+ # "ts": "1646188520338"
7241
+ # }
7242
+ #
7243
+ timestamp = self.safe_integer_2(conversion, 'quoteTime', 'ts')
7175
7244
  fromCoin = self.safe_string(conversion, 'baseCcy')
7176
7245
  fromCode = self.safe_currency_code(fromCoin, fromCurrency)
7177
7246
  to = self.safe_string(conversion, 'quoteCcy')
@@ -7180,12 +7249,12 @@ class okx(Exchange, ImplicitAPI):
7180
7249
  'info': conversion,
7181
7250
  'timestamp': timestamp,
7182
7251
  'datetime': self.iso8601(timestamp),
7183
- 'id': self.safe_string(conversion, 'clQReqId'),
7252
+ 'id': self.safe_string_n(conversion, ['clQReqId', 'tradeId', 'quoteId']),
7184
7253
  'fromCurrency': fromCode,
7185
- 'fromAmount': self.safe_number(conversion, 'baseSz'),
7254
+ 'fromAmount': self.safe_number_2(conversion, 'baseSz', 'fillBaseSz'),
7186
7255
  'toCurrency': toCode,
7187
- 'toAmount': self.safe_number(conversion, 'quoteSz'),
7188
- 'price': self.safe_number(conversion, 'cnvtPx'),
7256
+ 'toAmount': self.safe_number_2(conversion, 'quoteSz', 'fillQuoteSz'),
7257
+ 'price': self.safe_number_2(conversion, 'cnvtPx', 'fillPx'),
7189
7258
  'fee': None,
7190
7259
  }
7191
7260
 
ccxt/async_support/woo.py CHANGED
@@ -45,6 +45,7 @@ class woo(Exchange, ImplicitAPI):
45
45
  'cancelWithdraw': False, # exchange have that endpoint disabled atm, but was once implemented in ccxt per old docs: https://kronosresearch.github.io/wootrade-documents/#cancel-withdraw-request
46
46
  'closeAllPositions': False,
47
47
  'closePosition': False,
48
+ 'createConvertTrade': True,
48
49
  'createDepositAddress': False,
49
50
  'createMarketBuyOrderWithCost': True,
50
51
  'createMarketOrder': False,
@@ -2823,6 +2824,35 @@ class woo(Exchange, ImplicitAPI):
2823
2824
  toCurrency = self.currency(toCurrencyId)
2824
2825
  return self.parse_conversion(data, fromCurrency, toCurrency)
2825
2826
 
2827
+ async def create_convert_trade(self, id: str, fromCode: str, toCode: str, amount: Num = None, params={}) -> Conversion:
2828
+ """
2829
+ convert from one currency to another
2830
+ :see: https://docs.woo.org/#send-quote-rft
2831
+ :param str id: the id of the trade that you want to make
2832
+ :param str fromCode: the currency that you want to sell and convert from
2833
+ :param str toCode: the currency that you want to buy and convert into
2834
+ :param float [amount]: how much you want to trade in units of the from currency
2835
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2836
+ :returns dict: a `conversion structure <https://docs.ccxt.com/#/?id=conversion-structure>`
2837
+ """
2838
+ await self.load_markets()
2839
+ request = {
2840
+ 'quoteId': id,
2841
+ }
2842
+ response = await self.v3PrivatePostConvertRft(self.extend(request, params))
2843
+ #
2844
+ # {
2845
+ # "success": True,
2846
+ # "data": {
2847
+ # "quoteId": 123123123,
2848
+ # "counterPartyId": "",
2849
+ # "rftAccepted": 1 # 1 -> success; 2 -> processing; 3 -> fail
2850
+ # }
2851
+ # }
2852
+ #
2853
+ data = self.safe_dict(response, 'data', {})
2854
+ return self.parse_conversion(data)
2855
+
2826
2856
  def parse_conversion(self, conversion, fromCurrency: Currency = None, toCurrency: Currency = None) -> Conversion:
2827
2857
  #
2828
2858
  # fetchConvertQuote
@@ -2839,6 +2869,14 @@ class woo(Exchange, ImplicitAPI):
2839
2869
  # "message": 1659084466000
2840
2870
  # }
2841
2871
  #
2872
+ # createConvertTrade
2873
+ #
2874
+ # {
2875
+ # "quoteId": 123123123,
2876
+ # "counterPartyId": "",
2877
+ # "rftAccepted": 1 # 1 -> success; 2 -> processing; 3 -> fail
2878
+ # }
2879
+ #
2842
2880
  timestamp = self.safe_integer(conversion, 'expireTimestamp')
2843
2881
  fromCoin = self.safe_string(conversion, 'sellToken')
2844
2882
  fromCode = self.safe_currency_code(fromCoin, fromCurrency)
ccxt/base/exchange.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # -----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.2.99'
7
+ __version__ = '4.3.1'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10