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
ccxt/test/test_async.py CHANGED
@@ -1274,7 +1274,7 @@ class testMainClass(baseMainTestClass):
1274
1274
  # -----------------------------------------------------------------------------
1275
1275
  # --- Init of brokerId tests functions-----------------------------------------
1276
1276
  # -----------------------------------------------------------------------------
1277
- promises = [self.test_binance(), self.test_okx(), self.test_cryptocom(), self.test_bybit(), self.test_kucoin(), self.test_kucoinfutures(), self.test_bitget(), self.test_mexc(), self.test_htx(), self.test_woo(), self.test_bitmart(), self.test_coinex(), self.test_bingx(), self.test_phemex(), self.test_blofin(), self.test_hyperliquid(), self.test_coinbaseinternational(), self.test_coinbase_advanced(), self.test_woofi_pro(), self.test_xt()]
1277
+ promises = [self.test_binance(), self.test_okx(), self.test_cryptocom(), self.test_bybit(), self.test_kucoin(), self.test_kucoinfutures(), self.test_bitget(), self.test_mexc(), self.test_htx(), self.test_woo(), self.test_bitmart(), self.test_coinex(), self.test_bingx(), self.test_phemex(), self.test_blofin(), self.test_hyperliquid(), self.test_coinbaseinternational(), self.test_coinbase_advanced(), self.test_woofi_pro(), self.test_oxfun(), self.test_xt()]
1278
1278
  await asyncio.gather(*promises)
1279
1279
  success_message = '[' + self.lang + '][TEST_SUCCESS] brokerId tests passed.'
1280
1280
  dump('[INFO]' + success_message)
@@ -1602,6 +1602,22 @@ class testMainClass(baseMainTestClass):
1602
1602
  await close(exchange)
1603
1603
  return True
1604
1604
 
1605
+ async def test_oxfun(self):
1606
+ exchange = self.init_offline_exchange('oxfun')
1607
+ exchange.secret = 'secretsecretsecretsecretsecretsecretsecrets'
1608
+ id = 1000
1609
+ await exchange.load_markets()
1610
+ request = None
1611
+ try:
1612
+ await exchange.create_order('BTC/USD:OX', 'limit', 'buy', 1, 20000)
1613
+ except Exception as e:
1614
+ request = json_parse(exchange.last_request_body)
1615
+ orders = request['orders']
1616
+ first = orders[0]
1617
+ broker_id = first['source']
1618
+ assert broker_id == id, 'oxfun - id: ' + str(id) + ' different from broker_id: ' + str(broker_id)
1619
+ return True
1620
+
1605
1621
  async def test_xt(self):
1606
1622
  exchange = self.init_offline_exchange('xt')
1607
1623
  id = 'CCXT'
ccxt/test/test_sync.py CHANGED
@@ -1273,7 +1273,7 @@ class testMainClass(baseMainTestClass):
1273
1273
  # -----------------------------------------------------------------------------
1274
1274
  # --- Init of brokerId tests functions-----------------------------------------
1275
1275
  # -----------------------------------------------------------------------------
1276
- promises = [self.test_binance(), self.test_okx(), self.test_cryptocom(), self.test_bybit(), self.test_kucoin(), self.test_kucoinfutures(), self.test_bitget(), self.test_mexc(), self.test_htx(), self.test_woo(), self.test_bitmart(), self.test_coinex(), self.test_bingx(), self.test_phemex(), self.test_blofin(), self.test_hyperliquid(), self.test_coinbaseinternational(), self.test_coinbase_advanced(), self.test_woofi_pro(), self.test_xt()]
1276
+ promises = [self.test_binance(), self.test_okx(), self.test_cryptocom(), self.test_bybit(), self.test_kucoin(), self.test_kucoinfutures(), self.test_bitget(), self.test_mexc(), self.test_htx(), self.test_woo(), self.test_bitmart(), self.test_coinex(), self.test_bingx(), self.test_phemex(), self.test_blofin(), self.test_hyperliquid(), self.test_coinbaseinternational(), self.test_coinbase_advanced(), self.test_woofi_pro(), self.test_oxfun(), self.test_xt()]
1277
1277
  (promises)
1278
1278
  success_message = '[' + self.lang + '][TEST_SUCCESS] brokerId tests passed.'
1279
1279
  dump('[INFO]' + success_message)
@@ -1601,6 +1601,22 @@ class testMainClass(baseMainTestClass):
1601
1601
  close(exchange)
1602
1602
  return True
1603
1603
 
1604
+ def test_oxfun(self):
1605
+ exchange = self.init_offline_exchange('oxfun')
1606
+ exchange.secret = 'secretsecretsecretsecretsecretsecretsecrets'
1607
+ id = 1000
1608
+ exchange.load_markets()
1609
+ request = None
1610
+ try:
1611
+ exchange.create_order('BTC/USD:OX', 'limit', 'buy', 1, 20000)
1612
+ except Exception as e:
1613
+ request = json_parse(exchange.last_request_body)
1614
+ orders = request['orders']
1615
+ first = orders[0]
1616
+ broker_id = first['source']
1617
+ assert broker_id == id, 'oxfun - id: ' + str(id) + ' different from broker_id: ' + str(broker_id)
1618
+ return True
1619
+
1604
1620
  def test_xt(self):
1605
1621
  exchange = self.init_offline_exchange('xt')
1606
1622
  id = 'CCXT'
ccxt/tokocrypto.py CHANGED
@@ -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'),
ccxt/wavesexchange.py CHANGED
@@ -20,7 +20,7 @@ from ccxt.base.errors import InvalidOrder
20
20
  from ccxt.base.errors import OrderNotFound
21
21
  from ccxt.base.errors import DuplicateOrderId
22
22
  from ccxt.base.errors import ExchangeNotAvailable
23
- from ccxt.base.decimal_to_precision import DECIMAL_PLACES
23
+ from ccxt.base.decimal_to_precision import TICK_SIZE
24
24
  from ccxt.base.precise import Precise
25
25
 
26
26
 
@@ -33,6 +33,7 @@ class wavesexchange(Exchange, ImplicitAPI):
33
33
  'countries': ['CH'], # Switzerland
34
34
  'certified': False,
35
35
  'pro': False,
36
+ 'dex': True,
36
37
  'has': {
37
38
  'CORS': None,
38
39
  'spot': True,
@@ -328,9 +329,9 @@ class wavesexchange(Exchange, ImplicitAPI):
328
329
  },
329
330
  },
330
331
  'currencies': {
331
- 'WX': self.safe_currency_structure({'id': 'EMAMLxDnv3xiz8RXg8Btj33jcEw3wLczL3JKYYmuubpc', 'numericId': None, 'code': 'WX', 'precision': self.parse_to_int('8')}),
332
+ 'WX': self.safe_currency_structure({'id': 'EMAMLxDnv3xiz8RXg8Btj33jcEw3wLczL3JKYYmuubpc', 'numericId': None, 'code': 'WX', 'precision': self.parse_number('1e-8')}),
332
333
  },
333
- 'precisionMode': DECIMAL_PLACES,
334
+ 'precisionMode': TICK_SIZE,
334
335
  'options': {
335
336
  'allowedCandles': 1440,
336
337
  'accessToken': None,
@@ -341,7 +342,7 @@ class wavesexchange(Exchange, ImplicitAPI):
341
342
  'wavesAddress': None,
342
343
  'withdrawFeeUSDN': 7420,
343
344
  'withdrawFeeWAVES': 100000,
344
- 'wavesPrecision': 8,
345
+ 'wavesPrecision': 1e-8,
345
346
  'messagePrefix': 'W', # W for production, T for testnet
346
347
  'networks': {
347
348
  'ERC20': 'ETH',
@@ -389,8 +390,8 @@ class wavesexchange(Exchange, ImplicitAPI):
389
390
  def get_fees_for_asset(self, symbol: str, side, amount, price, params={}):
390
391
  self.load_markets()
391
392
  market = self.market(symbol)
392
- amount = self.custom_amount_to_precision(symbol, amount)
393
- price = self.custom_price_to_precision(symbol, price)
393
+ amount = self.to_real_symbol_amount(symbol, amount)
394
+ price = self.to_real_symbol_price(symbol, price)
394
395
  request = self.extend({
395
396
  'baseId': market['baseId'],
396
397
  'quoteId': market['quoteId'],
@@ -421,7 +422,7 @@ class wavesexchange(Exchange, ImplicitAPI):
421
422
  matcherFee = self.safe_string(mode, 'matcherFee')
422
423
  feeAssetId = self.safe_string(mode, 'feeAssetId')
423
424
  feeAsset = self.safe_currency_code(feeAssetId)
424
- adjustedMatcherFee = self.currency_from_precision(feeAsset, matcherFee)
425
+ adjustedMatcherFee = self.from_real_currency_amount(feeAsset, matcherFee)
425
426
  amountAsString = self.number_to_string(amount)
426
427
  priceAsString = self.number_to_string(price)
427
428
  feeCost = self.fee_to_precision(symbol, self.parse_number(adjustedMatcherFee))
@@ -569,8 +570,8 @@ class wavesexchange(Exchange, ImplicitAPI):
569
570
  'strike': None,
570
571
  'optionType': None,
571
572
  'precision': {
572
- 'amount': self.safe_integer(entry, 'amountAssetDecimals'),
573
- 'price': self.safe_integer(entry, 'priceAssetDecimals'),
573
+ 'amount': self.parse_number(self.parse_precision(self.safe_string(entry, 'amountAssetDecimals'))),
574
+ 'price': self.parse_number(self.parse_precision(self.safe_string(entry, 'priceAssetDecimals'))),
574
575
  },
575
576
  'limits': {
576
577
  'leverage': {
@@ -624,12 +625,11 @@ class wavesexchange(Exchange, ImplicitAPI):
624
625
 
625
626
  def parse_order_book_side(self, bookSide, market=None, limit: Int = None):
626
627
  precision = market['precision']
627
- wavesPrecision = self.safe_string(self.options, 'wavesPrecision', '8')
628
- amountPrecision = '1e' + self.number_to_string(precision['amount'])
629
- amountPrecisionString = self.number_to_string(precision['amount'])
630
- pricePrecisionString = self.number_to_string(precision['price'])
631
- difference = Precise.string_sub(amountPrecisionString, pricePrecisionString)
632
- pricePrecision = '1e' + Precise.string_sub(wavesPrecision, difference)
628
+ wavesPrecision = self.safe_string(self.options, 'wavesPrecision', '1e-8')
629
+ amountPrecisionString = self.safe_string(precision, 'amount')
630
+ pricePrecisionString = self.safe_string(precision, 'price')
631
+ difference = Precise.string_div(amountPrecisionString, pricePrecisionString)
632
+ pricePrecision = Precise.string_div(wavesPrecision, difference)
633
633
  result = []
634
634
  for i in range(0, len(bookSide)):
635
635
  entry = bookSide[i]
@@ -638,9 +638,9 @@ class wavesexchange(Exchange, ImplicitAPI):
638
638
  price = None
639
639
  amount = None
640
640
  if (pricePrecision is not None) and (entryPrice is not None):
641
- price = Precise.string_div(entryPrice, pricePrecision)
642
- if (amountPrecision is not None) and (entryAmount is not None):
643
- amount = Precise.string_div(entryAmount, amountPrecision)
641
+ price = Precise.string_mul(entryPrice, pricePrecision)
642
+ if (amountPrecisionString is not None) and (entryAmount is not None):
643
+ amount = Precise.string_mul(entryAmount, amountPrecisionString)
644
644
  if (limit is not None) and (i > limit):
645
645
  break
646
646
  result.append([
@@ -1170,50 +1170,35 @@ class wavesexchange(Exchange, ImplicitAPI):
1170
1170
  return ''
1171
1171
  return currencyId
1172
1172
 
1173
- def custom_price_to_precision(self, symbol, price):
1174
- market = self.markets[symbol]
1175
- wavesPrecision = self.safe_string(self.options, 'wavesPrecision', '8')
1176
- amount = self.number_to_string(market['precision']['amount'])
1177
- precisionPrice = self.number_to_string(market['precision']['price'])
1178
- difference = Precise.string_sub(amount, precisionPrice)
1179
- precision = Precise.string_sub(wavesPrecision, difference)
1180
- pricePrecision = self.to_precision(price, str(precision))
1181
- return self.parse_to_int(float(pricePrecision))
1182
-
1183
- def custom_amount_to_precision(self, symbol, amount):
1184
- amountPrecision = self.number_to_string(self.to_precision(amount, self.number_to_string(self.markets[symbol]['precision']['amount'])))
1185
- return self.parse_to_int(float(amountPrecision))
1173
+ def to_real_currency_amount(self, code: str, amount: float, networkCode=None):
1174
+ currency = self.currency(code)
1175
+ stringValue = Precise.string_div(self.number_to_string(amount), self.safe_string(currency, 'precision'))
1176
+ return int(stringValue)
1186
1177
 
1187
- def custom_currency_to_precision(self, code, amount, networkCode=None):
1188
- amountPrecision = self.number_to_string(self.to_precision(amount, self.currencies[code]['precision']))
1189
- return self.parse_to_int(float(amountPrecision))
1178
+ def from_real_currency_amount(self, code: str, amountString: str):
1179
+ if not (code in self.currencies):
1180
+ return amountString
1181
+ currency = self.currency(code)
1182
+ precisionAmount = self.safe_string(currency, 'precision')
1183
+ return Precise.string_mul(amountString, precisionAmount)
1190
1184
 
1191
- def from_precision(self, amount, scale):
1192
- if amount is None:
1193
- return None
1194
- precise = Precise(amount)
1195
- precise.decimals = self.sum(precise.decimals, scale)
1196
- precise.reduce()
1197
- return str(precise)
1185
+ def to_real_symbol_price(self, symbol: str, price: float):
1186
+ market = self.market(symbol)
1187
+ stringValue = Precise.string_div(self.number_to_string(price), self.safe_string(market['precision'], 'price'))
1188
+ return int(stringValue)
1198
1189
 
1199
- def to_precision(self, amount, scale):
1200
- amountString = self.number_to_string(amount)
1201
- precise = Precise(amountString)
1202
- # precise.decimals should be integer
1203
- precise.decimals = self.parse_to_int(Precise.string_sub(self.number_to_string(precise.decimals), self.number_to_string(scale)))
1204
- precise.reduce()
1205
- stringValue = str(precise)
1206
- return stringValue
1190
+ def from_real_symbol_price(self, symbol: str, priceString: str):
1191
+ market = self.markets[symbol]
1192
+ return Precise.string_mul(priceString, self.safe_string(market['precision'], 'price'))
1207
1193
 
1208
- def currency_from_precision(self, currency, amount):
1209
- scale = self.currencies[currency]['precision']
1210
- return self.from_precision(amount, scale)
1194
+ def to_real_symbol_amount(self, symbol: str, amount: float):
1195
+ market = self.market(symbol)
1196
+ stringValue = Precise.string_div(self.number_to_string(amount), self.safe_string(market['precision'], 'amount'))
1197
+ return int(stringValue)
1211
1198
 
1212
- def price_from_precision(self, symbol, price):
1199
+ def from_real_symbol_amount(self, symbol: str, amountString: str):
1213
1200
  market = self.markets[symbol]
1214
- wavesPrecision = self.safe_integer(self.options, 'wavesPrecision', 8)
1215
- scale = self.sum(wavesPrecision, market['precision']['price']) - market['precision']['amount']
1216
- return self.from_precision(price, scale)
1201
+ return Precise.string_mul(amountString, market['precision']['amount'])
1217
1202
 
1218
1203
  def safe_get_dynamic(self, settings):
1219
1204
  orderFee = self.safe_value(settings, 'orderFee')
@@ -1287,26 +1272,26 @@ class wavesexchange(Exchange, ImplicitAPI):
1287
1272
  raise InvalidOrder(self.id + ' asset fee must be ' + baseFeeAsset + ' or ' + discountFeeAsset)
1288
1273
  matcherFeeAsset = self.safe_currency_code(matcherFeeAssetId)
1289
1274
  rawMatcherFee = baseMatcherFee if (matcherFeeAssetId == baseFeeAssetId) else discountMatcherFee
1290
- floatMatcherFee = float(self.currency_from_precision(matcherFeeAsset, rawMatcherFee))
1275
+ floatMatcherFee = float(self.from_real_currency_amount(matcherFeeAsset, rawMatcherFee))
1291
1276
  if (matcherFeeAsset in balances) and (balances[matcherFeeAsset]['free'] >= floatMatcherFee):
1292
1277
  matcherFee = int(rawMatcherFee)
1293
1278
  else:
1294
1279
  raise InsufficientFunds(self.id + ' not enough funds of the selected asset fee')
1280
+ floatBaseMatcherFee = self.from_real_currency_amount(baseFeeAsset, baseMatcherFee)
1281
+ floatDiscountMatcherFee = self.from_real_currency_amount(discountFeeAsset, discountMatcherFee)
1295
1282
  if matcherFeeAssetId is None:
1296
1283
  # try to the pay the fee using the base first then discount asset
1297
- floatBaseMatcherFee = float(self.currency_from_precision(baseFeeAsset, baseMatcherFee))
1298
- if (baseFeeAsset in balances) and (balances[baseFeeAsset]['free'] >= floatBaseMatcherFee):
1284
+ if (baseFeeAsset in balances) and (balances[baseFeeAsset]['free'] >= float(floatBaseMatcherFee)):
1299
1285
  matcherFeeAssetId = baseFeeAssetId
1300
1286
  matcherFee = int(baseMatcherFee)
1301
1287
  else:
1302
- floatDiscountMatcherFee = float(self.currency_from_precision(discountFeeAsset, discountMatcherFee))
1303
- if (discountFeeAsset in balances) and (balances[discountFeeAsset]['free'] >= floatDiscountMatcherFee):
1288
+ if (discountFeeAsset in balances) and (balances[discountFeeAsset]['free'] >= float(floatDiscountMatcherFee)):
1304
1289
  matcherFeeAssetId = discountFeeAssetId
1305
1290
  matcherFee = int(discountMatcherFee)
1306
1291
  if matcherFeeAssetId is None:
1307
- raise InsufficientFunds(self.id + ' not enough funds on none of the eligible asset fees')
1308
- amount = self.custom_amount_to_precision(symbol, amount)
1309
- price = self.custom_price_to_precision(symbol, price)
1292
+ raise InsufficientFunds(self.id + ' not enough funds on none of the eligible asset fees: ' + baseFeeAsset + ' ' + floatBaseMatcherFee + ' or ' + discountFeeAsset + ' ' + floatDiscountMatcherFee)
1293
+ amount = self.to_real_symbol_amount(symbol, amount)
1294
+ price = self.to_real_symbol_price(symbol, price)
1310
1295
  assetPair: dict = {
1311
1296
  'amountAsset': amountAsset,
1312
1297
  'priceAsset': priceAsset,
@@ -1344,7 +1329,7 @@ class wavesexchange(Exchange, ImplicitAPI):
1344
1329
  'c': {
1345
1330
  't': 'sp',
1346
1331
  'v': {
1347
- 'p': self.custom_price_to_precision(symbol, stopPrice),
1332
+ 'p': self.to_real_symbol_price(symbol, stopPrice),
1348
1333
  },
1349
1334
  },
1350
1335
  }
@@ -1670,23 +1655,23 @@ class wavesexchange(Exchange, ImplicitAPI):
1670
1655
  elif market is not None:
1671
1656
  symbol = market['symbol']
1672
1657
  amountCurrency = self.safe_currency_code(self.safe_string(assetPair, 'amountAsset', 'WAVES'))
1673
- price = self.price_from_precision(symbol, priceString)
1674
- amount = self.currency_from_precision(amountCurrency, amountString)
1675
- filled = self.currency_from_precision(amountCurrency, filledString)
1676
- average = self.price_from_precision(symbol, self.safe_string(order, 'avgWeighedPrice'))
1658
+ price = self.from_real_symbol_price(symbol, priceString)
1659
+ amount = self.from_real_currency_amount(amountCurrency, amountString)
1660
+ filled = self.from_real_currency_amount(amountCurrency, filledString)
1661
+ average = self.from_real_symbol_price(symbol, self.safe_string(order, 'avgWeighedPrice'))
1677
1662
  status = self.parse_order_status(self.safe_string(order, 'status'))
1678
1663
  fee = None
1679
1664
  if 'type' in order:
1680
- currency = self.safe_currency_code(self.safe_string(order, 'feeAsset'))
1665
+ code = self.safe_currency_code(self.safe_string(order, 'feeAsset'))
1681
1666
  fee = {
1682
- 'currency': currency,
1683
- 'fee': self.parse_number(self.currency_from_precision(currency, self.safe_string(order, 'filledFee'))),
1667
+ 'currency': code,
1668
+ 'fee': self.parse_number(self.from_real_currency_amount(code, self.safe_string(order, 'filledFee'))),
1684
1669
  }
1685
1670
  else:
1686
- currency = self.safe_currency_code(self.safe_string(order, 'matcherFeeAssetId', 'WAVES'))
1671
+ code = self.safe_currency_code(self.safe_string(order, 'matcherFeeAssetId', 'WAVES'))
1687
1672
  fee = {
1688
- 'currency': currency,
1689
- 'fee': self.parse_number(self.currency_from_precision(currency, self.safe_string(order, 'matcherFee'))),
1673
+ 'currency': code,
1674
+ 'fee': self.parse_number(self.from_real_currency_amount(code, self.safe_string(order, 'matcherFee'))),
1690
1675
  }
1691
1676
  triggerPrice = None
1692
1677
  attachment = self.safe_string(order, 'attachment')
@@ -1801,16 +1786,14 @@ class wavesexchange(Exchange, ImplicitAPI):
1801
1786
  issueTransaction = self.safe_value(entry, 'issueTransaction')
1802
1787
  currencyId = self.safe_string(entry, 'assetId')
1803
1788
  balance = self.safe_string(entry, 'balance')
1804
- if issueTransaction is None:
1805
- assetIds.append(currencyId)
1806
- nonStandardBalances.append(balance)
1807
- continue
1808
- decimals = self.safe_integer(issueTransaction, 'decimals')
1809
- code = None
1810
- if currencyId in self.currencies_by_id:
1789
+ currencyExists = (currencyId in self.currencies_by_id)
1790
+ if currencyExists:
1811
1791
  code = self.safe_currency_code(currencyId)
1812
1792
  result[code] = self.account()
1813
- result[code]['total'] = self.from_precision(balance, decimals)
1793
+ result[code]['total'] = self.from_real_currency_amount(code, balance)
1794
+ elif issueTransaction is None:
1795
+ assetIds.append(currencyId)
1796
+ nonStandardBalances.append(balance)
1814
1797
  nonStandardAssets = len(assetIds)
1815
1798
  if nonStandardAssets:
1816
1799
  requestInner: dict = {
@@ -1822,11 +1805,11 @@ class wavesexchange(Exchange, ImplicitAPI):
1822
1805
  entry = data[i]
1823
1806
  balance = nonStandardBalances[i]
1824
1807
  inner = self.safe_value(entry, 'data')
1825
- decimals = self.safe_integer(inner, 'precision')
1808
+ precision = self.parse_precision(self.safe_string(inner, 'precision'))
1826
1809
  ticker = self.safe_string(inner, 'ticker')
1827
1810
  code = self.safe_currency_code(ticker)
1828
1811
  result[code] = self.account()
1829
- result[code]['total'] = self.from_precision(balance, decimals)
1812
+ result[code]['total'] = Precise.string_mul(balance, precision)
1830
1813
  currentTimestamp = self.milliseconds()
1831
1814
  byteArray = [
1832
1815
  self.base58_to_binary(self.apiKey),
@@ -1849,10 +1832,7 @@ class wavesexchange(Exchange, ImplicitAPI):
1849
1832
  if not (code in result):
1850
1833
  result[code] = self.account()
1851
1834
  amount = self.safe_string(reservedBalance, currencyId)
1852
- if code in self.currencies:
1853
- result[code]['used'] = self.currency_from_precision(code, amount)
1854
- else:
1855
- result[code]['used'] = amount
1835
+ result[code]['used'] = self.from_real_currency_amount(code, amount)
1856
1836
  wavesRequest: dict = {
1857
1837
  'address': wavesAddress,
1858
1838
  }
@@ -1862,17 +1842,21 @@ class wavesexchange(Exchange, ImplicitAPI):
1862
1842
  # "confirmations": 0,
1863
1843
  # "balance": 909085978
1864
1844
  # }
1865
- result['WAVES'] = self.safe_value(result, 'WAVES', {})
1866
- result['WAVES']['total'] = self.currency_from_precision('WAVES', self.safe_string(wavesTotal, 'balance'))
1867
- codes = list(result.keys())
1868
- for i in range(0, len(codes)):
1869
- code = codes[i]
1870
- if self.safe_value(result[code], 'used') is None:
1871
- result[code]['used'] = '0'
1845
+ result['WAVES'] = self.safe_value(result, 'WAVES', self.account())
1846
+ result['WAVES']['total'] = self.from_real_currency_amount('WAVES', self.safe_string(wavesTotal, 'balance'))
1847
+ result = self.set_undefined_balances_to_zero(result)
1872
1848
  result['timestamp'] = timestamp
1873
1849
  result['datetime'] = self.iso8601(timestamp)
1874
1850
  return self.safe_balance(result)
1875
1851
 
1852
+ def set_undefined_balances_to_zero(self, balances, key='used'):
1853
+ codes = list(balances.keys())
1854
+ for i in range(0, len(codes)):
1855
+ code = codes[i]
1856
+ if self.safe_value(balances[code], 'used') is None:
1857
+ balances[code][key] = '0'
1858
+ return balances
1859
+
1876
1860
  def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
1877
1861
  """
1878
1862
  fetch all trades made by the user
@@ -2373,7 +2357,7 @@ class wavesexchange(Exchange, ImplicitAPI):
2373
2357
  feeAssetId = 'WAVES'
2374
2358
  type = 4 # transfer
2375
2359
  version = 2
2376
- amountInteger = self.custom_currency_to_precision(code, amount)
2360
+ amountInteger = self.to_real_currency_amount(code, amount)
2377
2361
  currency = self.currency(code)
2378
2362
  timestamp = self.milliseconds()
2379
2363
  byteArray = [
@@ -2433,18 +2417,45 @@ class wavesexchange(Exchange, ImplicitAPI):
2433
2417
  # "amount": 0
2434
2418
  # }
2435
2419
  #
2420
+ # withdraw new:
2421
+ # {
2422
+ # type: "4",
2423
+ # id: "2xnWTqG9ar7jEDrLxfbVyyspPZ6XZNrrw9ai9sQ81Eya",
2424
+ # fee: "100000",
2425
+ # feeAssetId: null,
2426
+ # timestamp: "1715786263807",
2427
+ # version: "2",
2428
+ # sender: "3P81LLX1kk2CSJC9L8C2enxdHB7XvnSGAEE",
2429
+ # senderPublicKey: "DdmzmXf9mty1FBE8AdVGnrncVLEAzP4gR4nWoTFAJoXz",
2430
+ # proofs: ["RyoKwdSYv3EqotJCYftfFM9JE2j1ZpDRxKwYfiRhLAFeyNp6VfJUXNDS884XfeCeHeNypNmTCZt5NYR1ekyjCX3",],
2431
+ # recipient: "3P9tXxu38a8tgewNEKFzourVxeqHd11ppOc",
2432
+ # assetId: null,
2433
+ # feeAsset: null,
2434
+ # amount: "2000000",
2435
+ # attachment: "",
2436
+ # }
2437
+ #
2436
2438
  currency = self.safe_currency(None, currency)
2439
+ code = currency['code']
2440
+ typeRaw = self.safe_string(transaction, 'type')
2441
+ type = 'withdraw' if (typeRaw == '4') else 'deposit'
2442
+ amount = self.parse_number(self.from_real_currency_amount(code, self.safe_string(transaction, 'amount')))
2443
+ feeString = self.safe_string(transaction, 'fee')
2444
+ feeAssetId = self.safe_string(transaction, 'feeAssetId', 'WAVES')
2445
+ feeCode = self.safe_currency_code(feeAssetId)
2446
+ feeAmount = self.parse_number(self.from_real_currency_amount(feeCode, feeString))
2447
+ timestamp = self.safe_integer(transaction, 'timestamp')
2437
2448
  return {
2438
- 'id': None,
2449
+ 'id': self.safe_string(transaction, 'id'),
2439
2450
  'txid': None,
2440
- 'timestamp': None,
2441
- 'datetime': None,
2451
+ 'timestamp': timestamp,
2452
+ 'datetime': self.iso8601(timestamp),
2442
2453
  'network': None,
2443
- 'addressFrom': None,
2454
+ 'addressFrom': self.safe_string(transaction, 'sender'),
2444
2455
  'address': None,
2445
- 'addressTo': None,
2446
- 'amount': None,
2447
- 'type': None,
2456
+ 'addressTo': self.safe_string(transaction, 'recipient'),
2457
+ 'amount': amount,
2458
+ 'type': type,
2448
2459
  'currency': currency['code'],
2449
2460
  'status': None,
2450
2461
  'updated': None,
@@ -2453,6 +2464,9 @@ class wavesexchange(Exchange, ImplicitAPI):
2453
2464
  'tagTo': None,
2454
2465
  'comment': None,
2455
2466
  'internal': None,
2456
- 'fee': None,
2467
+ 'fee': {
2468
+ 'currency': feeCode,
2469
+ 'cost': feeAmount,
2470
+ },
2457
2471
  'info': transaction,
2458
2472
  }
ccxt/woofipro.py CHANGED
@@ -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/xt.py CHANGED
@@ -38,7 +38,7 @@ class xt(Exchange, ImplicitAPI):
38
38
  # futures 1000 times per minute for each single IP -> Otherwise account locked for 10min
39
39
  'rateLimit': 100,
40
40
  'version': 'v4',
41
- 'certified': True,
41
+ 'certified': False,
42
42
  'pro': False,
43
43
  'has': {
44
44
  'CORS': False,