ccxt 4.3.44__py2.py3-none-any.whl → 4.3.46__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.
Files changed (56) hide show
  1. ccxt/__init__.py +3 -1
  2. ccxt/abstract/binance.py +2 -0
  3. ccxt/abstract/binancecoinm.py +2 -0
  4. ccxt/abstract/binanceus.py +2 -0
  5. ccxt/abstract/binanceusdm.py +2 -0
  6. ccxt/abstract/bitstamp.py +18 -2
  7. ccxt/abstract/kucoin.py +14 -0
  8. ccxt/abstract/kucoinfutures.py +14 -0
  9. ccxt/abstract/mexc.py +2 -0
  10. ccxt/abstract/oxfun.py +34 -0
  11. ccxt/async_support/__init__.py +3 -1
  12. ccxt/async_support/base/exchange.py +1 -1
  13. ccxt/async_support/binance.py +2 -0
  14. ccxt/async_support/bingx.py +26 -18
  15. ccxt/async_support/bitmart.py +4 -0
  16. ccxt/async_support/bitstamp.py +18 -2
  17. ccxt/async_support/bitteam.py +6 -8
  18. ccxt/async_support/coinmetro.py +9 -18
  19. ccxt/async_support/hyperliquid.py +31 -23
  20. ccxt/async_support/idex.py +1 -0
  21. ccxt/async_support/kucoin.py +27 -1
  22. ccxt/async_support/luno.py +9 -1
  23. ccxt/async_support/mexc.py +8 -6
  24. ccxt/async_support/okx.py +1 -0
  25. ccxt/async_support/oxfun.py +2773 -0
  26. ccxt/async_support/tokocrypto.py +9 -11
  27. ccxt/async_support/wavesexchange.py +119 -105
  28. ccxt/async_support/woofipro.py +1 -0
  29. ccxt/async_support/xt.py +1 -1
  30. ccxt/base/exchange.py +1 -1
  31. ccxt/binance.py +2 -0
  32. ccxt/bingx.py +26 -18
  33. ccxt/bitmart.py +4 -0
  34. ccxt/bitstamp.py +18 -2
  35. ccxt/bitteam.py +6 -8
  36. ccxt/coinmetro.py +9 -18
  37. ccxt/hyperliquid.py +31 -23
  38. ccxt/idex.py +1 -0
  39. ccxt/kucoin.py +27 -1
  40. ccxt/luno.py +9 -1
  41. ccxt/mexc.py +8 -6
  42. ccxt/okx.py +1 -0
  43. ccxt/oxfun.py +2772 -0
  44. ccxt/pro/__init__.py +3 -1
  45. ccxt/pro/binanceus.py +0 -8
  46. ccxt/pro/oxfun.py +950 -0
  47. ccxt/test/test_async.py +17 -1
  48. ccxt/test/test_sync.py +17 -1
  49. ccxt/tokocrypto.py +9 -11
  50. ccxt/wavesexchange.py +119 -105
  51. ccxt/woofipro.py +1 -0
  52. ccxt/xt.py +1 -1
  53. {ccxt-4.3.44.dist-info → ccxt-4.3.46.dist-info}/METADATA +131 -131
  54. {ccxt-4.3.44.dist-info → ccxt-4.3.46.dist-info}/RECORD +56 -52
  55. {ccxt-4.3.44.dist-info → ccxt-4.3.46.dist-info}/WHEEL +0 -0
  56. {ccxt-4.3.44.dist-info → ccxt-4.3.46.dist-info}/top_level.txt +0 -0
@@ -31,7 +31,7 @@ from ccxt.base.errors import OnMaintenance
31
31
  from ccxt.base.errors import InvalidNonce
32
32
  from ccxt.base.errors import RequestTimeout
33
33
  from ccxt.base.decimal_to_precision import TRUNCATE
34
- from ccxt.base.decimal_to_precision import DECIMAL_PLACES
34
+ from ccxt.base.decimal_to_precision import TICK_SIZE
35
35
  from ccxt.base.precise import Precise
36
36
 
37
37
 
@@ -234,7 +234,7 @@ class tokocrypto(Exchange, ImplicitAPI):
234
234
  'maker': self.parse_number('0.0075'), # 0.1% trading fee, zero fees for all trading pairs before November 1
235
235
  },
236
236
  },
237
- 'precisionMode': DECIMAL_PLACES,
237
+ 'precisionMode': TICK_SIZE,
238
238
  'options': {
239
239
  # 'fetchTradesMethod': 'binanceGetTrades', # binanceGetTrades, binanceGetAggTrades
240
240
  'createMarketBuyOrderRequiresPrice': True,
@@ -734,10 +734,10 @@ class tokocrypto(Exchange, ImplicitAPI):
734
734
  'strike': None,
735
735
  'optionType': None,
736
736
  'precision': {
737
- 'amount': self.safe_integer(market, 'quantityPrecision'),
738
- 'price': self.safe_integer(market, 'pricePrecision'),
739
- 'base': self.safe_integer(market, 'baseAssetPrecision'),
740
- 'quote': self.safe_integer(market, 'quotePrecision'),
737
+ 'amount': self.parse_number(self.parse_precision(self.safe_string(market, 'quantityPrecision'))),
738
+ 'price': self.parse_number(self.parse_precision(self.safe_string(market, 'pricePrecision'))),
739
+ 'base': self.parse_number(self.parse_precision(self.safe_string(market, 'baseAssetPrecision'))),
740
+ 'quote': self.parse_number(self.parse_precision(self.safe_string(market, 'quotePrecision'))),
741
741
  },
742
742
  'limits': {
743
743
  'leverage': {
@@ -762,8 +762,7 @@ class tokocrypto(Exchange, ImplicitAPI):
762
762
  }
763
763
  if 'PRICE_FILTER' in filtersByType:
764
764
  filter = self.safe_value(filtersByType, 'PRICE_FILTER', {})
765
- tickSize = self.safe_string(filter, 'tickSize')
766
- entry['precision']['price'] = self.precision_from_string(tickSize)
765
+ entry['precision']['price'] = self.safe_number(filter, 'tickSize')
767
766
  # PRICE_FILTER reports zero values for maxPrice
768
767
  # since they updated filter types in November 2018
769
768
  # https://github.com/ccxt/ccxt/issues/4286
@@ -772,11 +771,10 @@ class tokocrypto(Exchange, ImplicitAPI):
772
771
  'min': self.safe_number(filter, 'minPrice'),
773
772
  'max': self.safe_number(filter, 'maxPrice'),
774
773
  }
775
- entry['precision']['price'] = self.precision_from_string(filter['tickSize'])
774
+ entry['precision']['price'] = filter['tickSize']
776
775
  if 'LOT_SIZE' in filtersByType:
777
776
  filter = self.safe_value(filtersByType, 'LOT_SIZE', {})
778
- stepSize = self.safe_string(filter, 'stepSize')
779
- entry['precision']['amount'] = self.precision_from_string(stepSize)
777
+ entry['precision']['amount'] = self.safe_number(filter, 'stepSize')
780
778
  entry['limits']['amount'] = {
781
779
  'min': self.safe_number(filter, 'minQty'),
782
780
  'max': self.safe_number(filter, 'maxQty'),
@@ -21,7 +21,7 @@ from ccxt.base.errors import InvalidOrder
21
21
  from ccxt.base.errors import OrderNotFound
22
22
  from ccxt.base.errors import DuplicateOrderId
23
23
  from ccxt.base.errors import ExchangeNotAvailable
24
- from ccxt.base.decimal_to_precision import DECIMAL_PLACES
24
+ from ccxt.base.decimal_to_precision import TICK_SIZE
25
25
  from ccxt.base.precise import Precise
26
26
 
27
27
 
@@ -34,6 +34,7 @@ class wavesexchange(Exchange, ImplicitAPI):
34
34
  'countries': ['CH'], # Switzerland
35
35
  'certified': False,
36
36
  'pro': False,
37
+ 'dex': True,
37
38
  'has': {
38
39
  'CORS': None,
39
40
  'spot': True,
@@ -329,9 +330,9 @@ class wavesexchange(Exchange, ImplicitAPI):
329
330
  },
330
331
  },
331
332
  'currencies': {
332
- 'WX': self.safe_currency_structure({'id': 'EMAMLxDnv3xiz8RXg8Btj33jcEw3wLczL3JKYYmuubpc', 'numericId': None, 'code': 'WX', 'precision': self.parse_to_int('8')}),
333
+ 'WX': self.safe_currency_structure({'id': 'EMAMLxDnv3xiz8RXg8Btj33jcEw3wLczL3JKYYmuubpc', 'numericId': None, 'code': 'WX', 'precision': self.parse_number('1e-8')}),
333
334
  },
334
- 'precisionMode': DECIMAL_PLACES,
335
+ 'precisionMode': TICK_SIZE,
335
336
  'options': {
336
337
  'allowedCandles': 1440,
337
338
  'accessToken': None,
@@ -342,7 +343,7 @@ class wavesexchange(Exchange, ImplicitAPI):
342
343
  'wavesAddress': None,
343
344
  'withdrawFeeUSDN': 7420,
344
345
  'withdrawFeeWAVES': 100000,
345
- 'wavesPrecision': 8,
346
+ 'wavesPrecision': 1e-8,
346
347
  'messagePrefix': 'W', # W for production, T for testnet
347
348
  'networks': {
348
349
  'ERC20': 'ETH',
@@ -390,8 +391,8 @@ class wavesexchange(Exchange, ImplicitAPI):
390
391
  async def get_fees_for_asset(self, symbol: str, side, amount, price, params={}):
391
392
  await self.load_markets()
392
393
  market = self.market(symbol)
393
- amount = self.custom_amount_to_precision(symbol, amount)
394
- price = self.custom_price_to_precision(symbol, price)
394
+ amount = self.to_real_symbol_amount(symbol, amount)
395
+ price = self.to_real_symbol_price(symbol, price)
395
396
  request = self.extend({
396
397
  'baseId': market['baseId'],
397
398
  'quoteId': market['quoteId'],
@@ -422,7 +423,7 @@ class wavesexchange(Exchange, ImplicitAPI):
422
423
  matcherFee = self.safe_string(mode, 'matcherFee')
423
424
  feeAssetId = self.safe_string(mode, 'feeAssetId')
424
425
  feeAsset = self.safe_currency_code(feeAssetId)
425
- adjustedMatcherFee = self.currency_from_precision(feeAsset, matcherFee)
426
+ adjustedMatcherFee = self.from_real_currency_amount(feeAsset, matcherFee)
426
427
  amountAsString = self.number_to_string(amount)
427
428
  priceAsString = self.number_to_string(price)
428
429
  feeCost = self.fee_to_precision(symbol, self.parse_number(adjustedMatcherFee))
@@ -570,8 +571,8 @@ class wavesexchange(Exchange, ImplicitAPI):
570
571
  'strike': None,
571
572
  'optionType': None,
572
573
  'precision': {
573
- 'amount': self.safe_integer(entry, 'amountAssetDecimals'),
574
- 'price': self.safe_integer(entry, 'priceAssetDecimals'),
574
+ 'amount': self.parse_number(self.parse_precision(self.safe_string(entry, 'amountAssetDecimals'))),
575
+ 'price': self.parse_number(self.parse_precision(self.safe_string(entry, 'priceAssetDecimals'))),
575
576
  },
576
577
  'limits': {
577
578
  'leverage': {
@@ -625,12 +626,11 @@ class wavesexchange(Exchange, ImplicitAPI):
625
626
 
626
627
  def parse_order_book_side(self, bookSide, market=None, limit: Int = None):
627
628
  precision = market['precision']
628
- wavesPrecision = self.safe_string(self.options, 'wavesPrecision', '8')
629
- amountPrecision = '1e' + self.number_to_string(precision['amount'])
630
- amountPrecisionString = self.number_to_string(precision['amount'])
631
- pricePrecisionString = self.number_to_string(precision['price'])
632
- difference = Precise.string_sub(amountPrecisionString, pricePrecisionString)
633
- pricePrecision = '1e' + Precise.string_sub(wavesPrecision, difference)
629
+ wavesPrecision = self.safe_string(self.options, 'wavesPrecision', '1e-8')
630
+ amountPrecisionString = self.safe_string(precision, 'amount')
631
+ pricePrecisionString = self.safe_string(precision, 'price')
632
+ difference = Precise.string_div(amountPrecisionString, pricePrecisionString)
633
+ pricePrecision = Precise.string_div(wavesPrecision, difference)
634
634
  result = []
635
635
  for i in range(0, len(bookSide)):
636
636
  entry = bookSide[i]
@@ -639,9 +639,9 @@ class wavesexchange(Exchange, ImplicitAPI):
639
639
  price = None
640
640
  amount = None
641
641
  if (pricePrecision is not None) and (entryPrice is not None):
642
- price = Precise.string_div(entryPrice, pricePrecision)
643
- if (amountPrecision is not None) and (entryAmount is not None):
644
- amount = Precise.string_div(entryAmount, amountPrecision)
642
+ price = Precise.string_mul(entryPrice, pricePrecision)
643
+ if (amountPrecisionString is not None) and (entryAmount is not None):
644
+ amount = Precise.string_mul(entryAmount, amountPrecisionString)
645
645
  if (limit is not None) and (i > limit):
646
646
  break
647
647
  result.append([
@@ -1171,50 +1171,35 @@ class wavesexchange(Exchange, ImplicitAPI):
1171
1171
  return ''
1172
1172
  return currencyId
1173
1173
 
1174
- def custom_price_to_precision(self, symbol, price):
1175
- market = self.markets[symbol]
1176
- wavesPrecision = self.safe_string(self.options, 'wavesPrecision', '8')
1177
- amount = self.number_to_string(market['precision']['amount'])
1178
- precisionPrice = self.number_to_string(market['precision']['price'])
1179
- difference = Precise.string_sub(amount, precisionPrice)
1180
- precision = Precise.string_sub(wavesPrecision, difference)
1181
- pricePrecision = self.to_precision(price, str(precision))
1182
- return self.parse_to_int(float(pricePrecision))
1183
-
1184
- def custom_amount_to_precision(self, symbol, amount):
1185
- amountPrecision = self.number_to_string(self.to_precision(amount, self.number_to_string(self.markets[symbol]['precision']['amount'])))
1186
- return self.parse_to_int(float(amountPrecision))
1174
+ def to_real_currency_amount(self, code: str, amount: float, networkCode=None):
1175
+ currency = self.currency(code)
1176
+ stringValue = Precise.string_div(self.number_to_string(amount), self.safe_string(currency, 'precision'))
1177
+ return int(stringValue)
1187
1178
 
1188
- def custom_currency_to_precision(self, code, amount, networkCode=None):
1189
- amountPrecision = self.number_to_string(self.to_precision(amount, self.currencies[code]['precision']))
1190
- return self.parse_to_int(float(amountPrecision))
1179
+ def from_real_currency_amount(self, code: str, amountString: str):
1180
+ if not (code in self.currencies):
1181
+ return amountString
1182
+ currency = self.currency(code)
1183
+ precisionAmount = self.safe_string(currency, 'precision')
1184
+ return Precise.string_mul(amountString, precisionAmount)
1191
1185
 
1192
- def from_precision(self, amount, scale):
1193
- if amount is None:
1194
- return None
1195
- precise = Precise(amount)
1196
- precise.decimals = self.sum(precise.decimals, scale)
1197
- precise.reduce()
1198
- return str(precise)
1186
+ def to_real_symbol_price(self, symbol: str, price: float):
1187
+ market = self.market(symbol)
1188
+ stringValue = Precise.string_div(self.number_to_string(price), self.safe_string(market['precision'], 'price'))
1189
+ return int(stringValue)
1199
1190
 
1200
- def to_precision(self, amount, scale):
1201
- amountString = self.number_to_string(amount)
1202
- precise = Precise(amountString)
1203
- # precise.decimals should be integer
1204
- precise.decimals = self.parse_to_int(Precise.string_sub(self.number_to_string(precise.decimals), self.number_to_string(scale)))
1205
- precise.reduce()
1206
- stringValue = str(precise)
1207
- return stringValue
1191
+ def from_real_symbol_price(self, symbol: str, priceString: str):
1192
+ market = self.markets[symbol]
1193
+ return Precise.string_mul(priceString, self.safe_string(market['precision'], 'price'))
1208
1194
 
1209
- def currency_from_precision(self, currency, amount):
1210
- scale = self.currencies[currency]['precision']
1211
- return self.from_precision(amount, scale)
1195
+ def to_real_symbol_amount(self, symbol: str, amount: float):
1196
+ market = self.market(symbol)
1197
+ stringValue = Precise.string_div(self.number_to_string(amount), self.safe_string(market['precision'], 'amount'))
1198
+ return int(stringValue)
1212
1199
 
1213
- def price_from_precision(self, symbol, price):
1200
+ def from_real_symbol_amount(self, symbol: str, amountString: str):
1214
1201
  market = self.markets[symbol]
1215
- wavesPrecision = self.safe_integer(self.options, 'wavesPrecision', 8)
1216
- scale = self.sum(wavesPrecision, market['precision']['price']) - market['precision']['amount']
1217
- return self.from_precision(price, scale)
1202
+ return Precise.string_mul(amountString, market['precision']['amount'])
1218
1203
 
1219
1204
  def safe_get_dynamic(self, settings):
1220
1205
  orderFee = self.safe_value(settings, 'orderFee')
@@ -1288,26 +1273,26 @@ class wavesexchange(Exchange, ImplicitAPI):
1288
1273
  raise InvalidOrder(self.id + ' asset fee must be ' + baseFeeAsset + ' or ' + discountFeeAsset)
1289
1274
  matcherFeeAsset = self.safe_currency_code(matcherFeeAssetId)
1290
1275
  rawMatcherFee = baseMatcherFee if (matcherFeeAssetId == baseFeeAssetId) else discountMatcherFee
1291
- floatMatcherFee = float(self.currency_from_precision(matcherFeeAsset, rawMatcherFee))
1276
+ floatMatcherFee = float(self.from_real_currency_amount(matcherFeeAsset, rawMatcherFee))
1292
1277
  if (matcherFeeAsset in balances) and (balances[matcherFeeAsset]['free'] >= floatMatcherFee):
1293
1278
  matcherFee = int(rawMatcherFee)
1294
1279
  else:
1295
1280
  raise InsufficientFunds(self.id + ' not enough funds of the selected asset fee')
1281
+ floatBaseMatcherFee = self.from_real_currency_amount(baseFeeAsset, baseMatcherFee)
1282
+ floatDiscountMatcherFee = self.from_real_currency_amount(discountFeeAsset, discountMatcherFee)
1296
1283
  if matcherFeeAssetId is None:
1297
1284
  # try to the pay the fee using the base first then discount asset
1298
- floatBaseMatcherFee = float(self.currency_from_precision(baseFeeAsset, baseMatcherFee))
1299
- if (baseFeeAsset in balances) and (balances[baseFeeAsset]['free'] >= floatBaseMatcherFee):
1285
+ if (baseFeeAsset in balances) and (balances[baseFeeAsset]['free'] >= float(floatBaseMatcherFee)):
1300
1286
  matcherFeeAssetId = baseFeeAssetId
1301
1287
  matcherFee = int(baseMatcherFee)
1302
1288
  else:
1303
- floatDiscountMatcherFee = float(self.currency_from_precision(discountFeeAsset, discountMatcherFee))
1304
- if (discountFeeAsset in balances) and (balances[discountFeeAsset]['free'] >= floatDiscountMatcherFee):
1289
+ if (discountFeeAsset in balances) and (balances[discountFeeAsset]['free'] >= float(floatDiscountMatcherFee)):
1305
1290
  matcherFeeAssetId = discountFeeAssetId
1306
1291
  matcherFee = int(discountMatcherFee)
1307
1292
  if matcherFeeAssetId is None:
1308
- raise InsufficientFunds(self.id + ' not enough funds on none of the eligible asset fees')
1309
- amount = self.custom_amount_to_precision(symbol, amount)
1310
- price = self.custom_price_to_precision(symbol, price)
1293
+ raise InsufficientFunds(self.id + ' not enough funds on none of the eligible asset fees: ' + baseFeeAsset + ' ' + floatBaseMatcherFee + ' or ' + discountFeeAsset + ' ' + floatDiscountMatcherFee)
1294
+ amount = self.to_real_symbol_amount(symbol, amount)
1295
+ price = self.to_real_symbol_price(symbol, price)
1311
1296
  assetPair: dict = {
1312
1297
  'amountAsset': amountAsset,
1313
1298
  'priceAsset': priceAsset,
@@ -1345,7 +1330,7 @@ class wavesexchange(Exchange, ImplicitAPI):
1345
1330
  'c': {
1346
1331
  't': 'sp',
1347
1332
  'v': {
1348
- 'p': self.custom_price_to_precision(symbol, stopPrice),
1333
+ 'p': self.to_real_symbol_price(symbol, stopPrice),
1349
1334
  },
1350
1335
  },
1351
1336
  }
@@ -1671,23 +1656,23 @@ class wavesexchange(Exchange, ImplicitAPI):
1671
1656
  elif market is not None:
1672
1657
  symbol = market['symbol']
1673
1658
  amountCurrency = self.safe_currency_code(self.safe_string(assetPair, 'amountAsset', 'WAVES'))
1674
- price = self.price_from_precision(symbol, priceString)
1675
- amount = self.currency_from_precision(amountCurrency, amountString)
1676
- filled = self.currency_from_precision(amountCurrency, filledString)
1677
- average = self.price_from_precision(symbol, self.safe_string(order, 'avgWeighedPrice'))
1659
+ price = self.from_real_symbol_price(symbol, priceString)
1660
+ amount = self.from_real_currency_amount(amountCurrency, amountString)
1661
+ filled = self.from_real_currency_amount(amountCurrency, filledString)
1662
+ average = self.from_real_symbol_price(symbol, self.safe_string(order, 'avgWeighedPrice'))
1678
1663
  status = self.parse_order_status(self.safe_string(order, 'status'))
1679
1664
  fee = None
1680
1665
  if 'type' in order:
1681
- currency = self.safe_currency_code(self.safe_string(order, 'feeAsset'))
1666
+ code = self.safe_currency_code(self.safe_string(order, 'feeAsset'))
1682
1667
  fee = {
1683
- 'currency': currency,
1684
- 'fee': self.parse_number(self.currency_from_precision(currency, self.safe_string(order, 'filledFee'))),
1668
+ 'currency': code,
1669
+ 'fee': self.parse_number(self.from_real_currency_amount(code, self.safe_string(order, 'filledFee'))),
1685
1670
  }
1686
1671
  else:
1687
- currency = self.safe_currency_code(self.safe_string(order, 'matcherFeeAssetId', 'WAVES'))
1672
+ code = self.safe_currency_code(self.safe_string(order, 'matcherFeeAssetId', 'WAVES'))
1688
1673
  fee = {
1689
- 'currency': currency,
1690
- 'fee': self.parse_number(self.currency_from_precision(currency, self.safe_string(order, 'matcherFee'))),
1674
+ 'currency': code,
1675
+ 'fee': self.parse_number(self.from_real_currency_amount(code, self.safe_string(order, 'matcherFee'))),
1691
1676
  }
1692
1677
  triggerPrice = None
1693
1678
  attachment = self.safe_string(order, 'attachment')
@@ -1802,16 +1787,14 @@ class wavesexchange(Exchange, ImplicitAPI):
1802
1787
  issueTransaction = self.safe_value(entry, 'issueTransaction')
1803
1788
  currencyId = self.safe_string(entry, 'assetId')
1804
1789
  balance = self.safe_string(entry, 'balance')
1805
- if issueTransaction is None:
1806
- assetIds.append(currencyId)
1807
- nonStandardBalances.append(balance)
1808
- continue
1809
- decimals = self.safe_integer(issueTransaction, 'decimals')
1810
- code = None
1811
- if currencyId in self.currencies_by_id:
1790
+ currencyExists = (currencyId in self.currencies_by_id)
1791
+ if currencyExists:
1812
1792
  code = self.safe_currency_code(currencyId)
1813
1793
  result[code] = self.account()
1814
- result[code]['total'] = self.from_precision(balance, decimals)
1794
+ result[code]['total'] = self.from_real_currency_amount(code, balance)
1795
+ elif issueTransaction is None:
1796
+ assetIds.append(currencyId)
1797
+ nonStandardBalances.append(balance)
1815
1798
  nonStandardAssets = len(assetIds)
1816
1799
  if nonStandardAssets:
1817
1800
  requestInner: dict = {
@@ -1823,11 +1806,11 @@ class wavesexchange(Exchange, ImplicitAPI):
1823
1806
  entry = data[i]
1824
1807
  balance = nonStandardBalances[i]
1825
1808
  inner = self.safe_value(entry, 'data')
1826
- decimals = self.safe_integer(inner, 'precision')
1809
+ precision = self.parse_precision(self.safe_string(inner, 'precision'))
1827
1810
  ticker = self.safe_string(inner, 'ticker')
1828
1811
  code = self.safe_currency_code(ticker)
1829
1812
  result[code] = self.account()
1830
- result[code]['total'] = self.from_precision(balance, decimals)
1813
+ result[code]['total'] = Precise.string_mul(balance, precision)
1831
1814
  currentTimestamp = self.milliseconds()
1832
1815
  byteArray = [
1833
1816
  self.base58_to_binary(self.apiKey),
@@ -1850,10 +1833,7 @@ class wavesexchange(Exchange, ImplicitAPI):
1850
1833
  if not (code in result):
1851
1834
  result[code] = self.account()
1852
1835
  amount = self.safe_string(reservedBalance, currencyId)
1853
- if code in self.currencies:
1854
- result[code]['used'] = self.currency_from_precision(code, amount)
1855
- else:
1856
- result[code]['used'] = amount
1836
+ result[code]['used'] = self.from_real_currency_amount(code, amount)
1857
1837
  wavesRequest: dict = {
1858
1838
  'address': wavesAddress,
1859
1839
  }
@@ -1863,17 +1843,21 @@ class wavesexchange(Exchange, ImplicitAPI):
1863
1843
  # "confirmations": 0,
1864
1844
  # "balance": 909085978
1865
1845
  # }
1866
- result['WAVES'] = self.safe_value(result, 'WAVES', {})
1867
- result['WAVES']['total'] = self.currency_from_precision('WAVES', self.safe_string(wavesTotal, 'balance'))
1868
- codes = list(result.keys())
1869
- for i in range(0, len(codes)):
1870
- code = codes[i]
1871
- if self.safe_value(result[code], 'used') is None:
1872
- result[code]['used'] = '0'
1846
+ result['WAVES'] = self.safe_value(result, 'WAVES', self.account())
1847
+ result['WAVES']['total'] = self.from_real_currency_amount('WAVES', self.safe_string(wavesTotal, 'balance'))
1848
+ result = self.set_undefined_balances_to_zero(result)
1873
1849
  result['timestamp'] = timestamp
1874
1850
  result['datetime'] = self.iso8601(timestamp)
1875
1851
  return self.safe_balance(result)
1876
1852
 
1853
+ def set_undefined_balances_to_zero(self, balances, key='used'):
1854
+ codes = list(balances.keys())
1855
+ for i in range(0, len(codes)):
1856
+ code = codes[i]
1857
+ if self.safe_value(balances[code], 'used') is None:
1858
+ balances[code][key] = '0'
1859
+ return balances
1860
+
1877
1861
  async def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
1878
1862
  """
1879
1863
  fetch all trades made by the user
@@ -2374,7 +2358,7 @@ class wavesexchange(Exchange, ImplicitAPI):
2374
2358
  feeAssetId = 'WAVES'
2375
2359
  type = 4 # transfer
2376
2360
  version = 2
2377
- amountInteger = self.custom_currency_to_precision(code, amount)
2361
+ amountInteger = self.to_real_currency_amount(code, amount)
2378
2362
  currency = self.currency(code)
2379
2363
  timestamp = self.milliseconds()
2380
2364
  byteArray = [
@@ -2434,18 +2418,45 @@ class wavesexchange(Exchange, ImplicitAPI):
2434
2418
  # "amount": 0
2435
2419
  # }
2436
2420
  #
2421
+ # withdraw new:
2422
+ # {
2423
+ # type: "4",
2424
+ # id: "2xnWTqG9ar7jEDrLxfbVyyspPZ6XZNrrw9ai9sQ81Eya",
2425
+ # fee: "100000",
2426
+ # feeAssetId: null,
2427
+ # timestamp: "1715786263807",
2428
+ # version: "2",
2429
+ # sender: "3P81LLX1kk2CSJC9L8C2enxdHB7XvnSGAEE",
2430
+ # senderPublicKey: "DdmzmXf9mty1FBE8AdVGnrncVLEAzP4gR4nWoTFAJoXz",
2431
+ # proofs: ["RyoKwdSYv3EqotJCYftfFM9JE2j1ZpDRxKwYfiRhLAFeyNp6VfJUXNDS884XfeCeHeNypNmTCZt5NYR1ekyjCX3",],
2432
+ # recipient: "3P9tXxu38a8tgewNEKFzourVxeqHd11ppOc",
2433
+ # assetId: null,
2434
+ # feeAsset: null,
2435
+ # amount: "2000000",
2436
+ # attachment: "",
2437
+ # }
2438
+ #
2437
2439
  currency = self.safe_currency(None, currency)
2440
+ code = currency['code']
2441
+ typeRaw = self.safe_string(transaction, 'type')
2442
+ type = 'withdraw' if (typeRaw == '4') else 'deposit'
2443
+ amount = self.parse_number(self.from_real_currency_amount(code, self.safe_string(transaction, 'amount')))
2444
+ feeString = self.safe_string(transaction, 'fee')
2445
+ feeAssetId = self.safe_string(transaction, 'feeAssetId', 'WAVES')
2446
+ feeCode = self.safe_currency_code(feeAssetId)
2447
+ feeAmount = self.parse_number(self.from_real_currency_amount(feeCode, feeString))
2448
+ timestamp = self.safe_integer(transaction, 'timestamp')
2438
2449
  return {
2439
- 'id': None,
2450
+ 'id': self.safe_string(transaction, 'id'),
2440
2451
  'txid': None,
2441
- 'timestamp': None,
2442
- 'datetime': None,
2452
+ 'timestamp': timestamp,
2453
+ 'datetime': self.iso8601(timestamp),
2443
2454
  'network': None,
2444
- 'addressFrom': None,
2455
+ 'addressFrom': self.safe_string(transaction, 'sender'),
2445
2456
  'address': None,
2446
- 'addressTo': None,
2447
- 'amount': None,
2448
- 'type': None,
2457
+ 'addressTo': self.safe_string(transaction, 'recipient'),
2458
+ 'amount': amount,
2459
+ 'type': type,
2449
2460
  'currency': currency['code'],
2450
2461
  'status': None,
2451
2462
  'updated': None,
@@ -2454,6 +2465,9 @@ class wavesexchange(Exchange, ImplicitAPI):
2454
2465
  'tagTo': None,
2455
2466
  'comment': None,
2456
2467
  'internal': None,
2457
- 'fee': None,
2468
+ 'fee': {
2469
+ 'currency': feeCode,
2470
+ 'cost': feeAmount,
2471
+ },
2458
2472
  'info': transaction,
2459
2473
  }
@@ -32,6 +32,7 @@ class woofipro(Exchange, ImplicitAPI):
32
32
  'version': 'v1',
33
33
  'certified': True,
34
34
  'pro': True,
35
+ 'dex': True,
35
36
  'hostname': 'dex.woo.org',
36
37
  'has': {
37
38
  'CORS': None,
ccxt/async_support/xt.py CHANGED
@@ -39,7 +39,7 @@ class xt(Exchange, ImplicitAPI):
39
39
  # futures 1000 times per minute for each single IP -> Otherwise account locked for 10min
40
40
  'rateLimit': 100,
41
41
  'version': 'v4',
42
- 'certified': True,
42
+ 'certified': False,
43
43
  'pro': False,
44
44
  'has': {
45
45
  'CORS': False,
ccxt/base/exchange.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # -----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.3.44'
7
+ __version__ = '4.3.46'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
 
ccxt/binance.py CHANGED
@@ -1010,6 +1010,8 @@ class binance(Exchange, ImplicitAPI):
1010
1010
  'post': {
1011
1011
  'order/oco': 0.2,
1012
1012
  'orderList/oco': 0.2,
1013
+ 'orderList/oto': 0.2,
1014
+ 'orderList/otoco': 0.2,
1013
1015
  'sor/order': 0.2,
1014
1016
  'sor/order/test': 0.2,
1015
1017
  'order': 0.2,
ccxt/bingx.py CHANGED
@@ -21,7 +21,7 @@ from ccxt.base.errors import OrderNotFound
21
21
  from ccxt.base.errors import NotSupported
22
22
  from ccxt.base.errors import OperationFailed
23
23
  from ccxt.base.errors import DDoSProtection
24
- from ccxt.base.decimal_to_precision import DECIMAL_PLACES
24
+ from ccxt.base.decimal_to_precision import TICK_SIZE
25
25
  from ccxt.base.precise import Precise
26
26
 
27
27
 
@@ -399,7 +399,7 @@ class bingx(Exchange, ImplicitAPI):
399
399
  '1w': '1w',
400
400
  '1M': '1M',
401
401
  },
402
- 'precisionMode': DECIMAL_PLACES,
402
+ 'precisionMode': TICK_SIZE,
403
403
  'exceptions': {
404
404
  'exact': {
405
405
  '400': BadRequest,
@@ -615,18 +615,26 @@ class bingx(Exchange, ImplicitAPI):
615
615
  # "msg": "",
616
616
  # "data": [
617
617
  # {
618
- # "contractId": "100",
619
- # "symbol": "BTC-USDT",
620
- # "size": "0.0001",
621
- # "quantityPrecision": 4,
622
- # "pricePrecision": 1,
623
- # "feeRate": 0.0005,
624
- # "tradeMinLimit": 1,
625
- # "maxLongLeverage": 150,
626
- # "maxShortLeverage": 150,
627
- # "currency": "USDT",
628
- # "asset": "BTC",
629
- # "status": 1
618
+ # "contractId": "100",
619
+ # "symbol": "BTC-USDT",
620
+ # "size": "0.0001",
621
+ # "quantityPrecision": "4",
622
+ # "pricePrecision": "1",
623
+ # "feeRate": "0.0005",
624
+ # "makerFeeRate": "0.0002",
625
+ # "takerFeeRate": "0.0005",
626
+ # "tradeMinLimit": "0",
627
+ # "tradeMinQuantity": "0.0001",
628
+ # "tradeMinUSDT": "2",
629
+ # "maxLongLeverage": "125",
630
+ # "maxShortLeverage": "125",
631
+ # "currency": "USDT",
632
+ # "asset": "BTC",
633
+ # "status": "1",
634
+ # "apiStateOpen": "true",
635
+ # "apiStateClose": "true",
636
+ # "ensureTrigger": True,
637
+ # "triggerFeeRate": "0.00020000"
630
638
  # },
631
639
  # ...
632
640
  # ]
@@ -644,12 +652,12 @@ class bingx(Exchange, ImplicitAPI):
644
652
  quote = self.safe_currency_code(quoteId)
645
653
  currency = self.safe_string(market, 'currency')
646
654
  settle = self.safe_currency_code(currency)
647
- pricePrecision = self.safe_integer(market, 'pricePrecision')
655
+ pricePrecision = self.safe_number(market, 'tickSize')
648
656
  if pricePrecision is None:
649
- pricePrecision = self.precision_from_string(self.safe_string(market, 'tickSize'))
650
- quantityPrecision = self.safe_integer(market, 'quantityPrecision')
657
+ pricePrecision = self.parse_number(self.parse_precision(self.safe_string(market, 'pricePrecision')))
658
+ quantityPrecision = self.safe_number(market, 'stepSize')
651
659
  if quantityPrecision is None:
652
- quantityPrecision = self.precision_from_string(self.safe_string(market, 'stepSize'))
660
+ quantityPrecision = self.parse_number(self.parse_precision(self.safe_string(market, 'quantityPrecision')))
653
661
  type = 'swap' if (settle is not None) else 'spot'
654
662
  spot = type == 'spot'
655
663
  swap = type == 'swap'
ccxt/bitmart.py CHANGED
@@ -2594,6 +2594,10 @@ class bitmart(Exchange, ImplicitAPI):
2594
2594
  request['type'] = 'limit_maker'
2595
2595
  if ioc:
2596
2596
  request['type'] = 'ioc'
2597
+ clientOrderId = self.safe_string(params, 'clientOrderId')
2598
+ if clientOrderId is not None:
2599
+ params = self.omit(params, 'clientOrderId')
2600
+ request['client_order_id'] = clientOrderId
2597
2601
  return self.extend(request, params)
2598
2602
 
2599
2603
  def cancel_order(self, id: str, symbol: Str = None, params={}):
ccxt/bitstamp.py CHANGED
@@ -232,7 +232,7 @@ class bitstamp(Exchange, ImplicitAPI):
232
232
  'uni_withdrawal/': 1,
233
233
  'uni_address/': 1,
234
234
  'yfi_withdrawal/': 1,
235
- 'yfi_address': 1,
235
+ 'yfi_address/': 1,
236
236
  'audio_withdrawal/': 1,
237
237
  'audio_address/': 1,
238
238
  'crv_withdrawal/': 1,
@@ -241,7 +241,7 @@ class bitstamp(Exchange, ImplicitAPI):
241
241
  'algo_address/': 1,
242
242
  'comp_withdrawal/': 1,
243
243
  'comp_address/': 1,
244
- 'grt_withdrawal': 1,
244
+ 'grt_withdrawal/': 1,
245
245
  'grt_address/': 1,
246
246
  'usdt_withdrawal/': 1,
247
247
  'usdt_address/': 1,
@@ -379,6 +379,22 @@ class bitstamp(Exchange, ImplicitAPI):
379
379
  'vchf_address/': 1,
380
380
  'veur_withdrawal/': 1,
381
381
  'veur_address/': 1,
382
+ 'truf_withdrawal/': 1,
383
+ 'truf_address/': 1,
384
+ 'wif_withdrawal/': 1,
385
+ 'wif_address/': 1,
386
+ 'smt_withdrawal/': 1,
387
+ 'smt_address/': 1,
388
+ 'sui_withdrawal/': 1,
389
+ 'sui_address/': 1,
390
+ 'jup_withdrawal/': 1,
391
+ 'jup_address/': 1,
392
+ 'ondo_withdrawal/': 1,
393
+ 'ondo_address/': 1,
394
+ 'boba_withdrawal/': 1,
395
+ 'boba_address/': 1,
396
+ 'pyth_withdrawal/': 1,
397
+ 'pyth_address/': 1,
382
398
  },
383
399
  },
384
400
  },