ccxt 4.3.62__py2.py3-none-any.whl → 4.3.64__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 (74) hide show
  1. ccxt/__init__.py +2 -1
  2. ccxt/abstract/binance.py +5 -5
  3. ccxt/abstract/binancecoinm.py +5 -5
  4. ccxt/abstract/binanceus.py +5 -5
  5. ccxt/abstract/binanceusdm.py +5 -5
  6. ccxt/abstract/cryptocom.py +11 -0
  7. ccxt/abstract/kucoin.py +1 -0
  8. ccxt/abstract/kucoinfutures.py +1 -0
  9. ccxt/abstract/woo.py +3 -0
  10. ccxt/ace.py +33 -15
  11. ccxt/alpaca.py +1 -0
  12. ccxt/async_support/__init__.py +2 -1
  13. ccxt/async_support/ace.py +33 -15
  14. ccxt/async_support/alpaca.py +1 -0
  15. ccxt/async_support/base/exchange.py +4 -4
  16. ccxt/async_support/binance.py +6 -9
  17. ccxt/async_support/bingx.py +534 -152
  18. ccxt/async_support/bitfinex.py +1 -1
  19. ccxt/async_support/bitfinex2.py +1 -1
  20. ccxt/async_support/coinbaseinternational.py +1 -1
  21. ccxt/async_support/cryptocom.py +17 -2
  22. ccxt/async_support/independentreserve.py +103 -1
  23. ccxt/async_support/kucoin.py +2 -0
  24. ccxt/async_support/mercado.py +5 -1
  25. ccxt/async_support/whitebit.py +1 -1
  26. ccxt/async_support/woo.py +321 -81
  27. ccxt/async_support/xt.py +3 -3
  28. ccxt/async_support/yobit.py +1 -1
  29. ccxt/async_support/zonda.py +1 -1
  30. ccxt/base/errors.py +8 -1
  31. ccxt/base/exchange.py +11 -5
  32. ccxt/binance.py +6 -9
  33. ccxt/bingx.py +534 -152
  34. ccxt/bitfinex.py +1 -1
  35. ccxt/bitfinex2.py +1 -1
  36. ccxt/coinbaseinternational.py +1 -1
  37. ccxt/cryptocom.py +17 -2
  38. ccxt/independentreserve.py +103 -1
  39. ccxt/kucoin.py +2 -0
  40. ccxt/mercado.py +5 -1
  41. ccxt/pro/__init__.py +1 -1
  42. ccxt/pro/binance.py +56 -35
  43. ccxt/pro/bitfinex2.py +6 -4
  44. ccxt/pro/bitget.py +5 -2
  45. ccxt/pro/bitmart.py +3 -3
  46. ccxt/pro/bitvavo.py +1 -1
  47. ccxt/pro/bybit.py +41 -18
  48. ccxt/pro/cryptocom.py +7 -2
  49. ccxt/pro/gate.py +7 -4
  50. ccxt/pro/gemini.py +4 -2
  51. ccxt/pro/htx.py +5 -1
  52. ccxt/pro/independentreserve.py +6 -4
  53. ccxt/pro/kraken.py +79 -6
  54. ccxt/pro/okx.py +5 -5
  55. ccxt/pro/onetrading.py +3 -2
  56. ccxt/pro/oxfun.py +1 -1
  57. ccxt/pro/poloniexfutures.py +5 -2
  58. ccxt/pro/vertex.py +3 -2
  59. ccxt/pro/woo.py +2 -1
  60. ccxt/pro/woofipro.py +3 -2
  61. ccxt/test/tests_async.py +3 -3
  62. ccxt/test/tests_helpers.py +1 -1
  63. ccxt/test/tests_init.py +3 -3
  64. ccxt/test/tests_sync.py +3 -3
  65. ccxt/whitebit.py +1 -1
  66. ccxt/woo.py +321 -81
  67. ccxt/xt.py +3 -3
  68. ccxt/yobit.py +1 -1
  69. ccxt/zonda.py +1 -1
  70. {ccxt-4.3.62.dist-info → ccxt-4.3.64.dist-info}/METADATA +4 -4
  71. {ccxt-4.3.62.dist-info → ccxt-4.3.64.dist-info}/RECORD +74 -74
  72. {ccxt-4.3.62.dist-info → ccxt-4.3.64.dist-info}/LICENSE.txt +0 -0
  73. {ccxt-4.3.62.dist-info → ccxt-4.3.64.dist-info}/WHEEL +0 -0
  74. {ccxt-4.3.62.dist-info → ccxt-4.3.64.dist-info}/top_level.txt +0 -0
ccxt/pro/gate.py CHANGED
@@ -14,7 +14,7 @@ from ccxt.base.errors import AuthenticationError
14
14
  from ccxt.base.errors import ArgumentsRequired
15
15
  from ccxt.base.errors import BadRequest
16
16
  from ccxt.base.errors import NotSupported
17
- from ccxt.base.errors import InvalidNonce
17
+ from ccxt.base.errors import ChecksumError
18
18
  from ccxt.base.precise import Precise
19
19
 
20
20
 
@@ -105,6 +105,7 @@ class gate(ccxt.async_support.gate):
105
105
  'interval': '100ms',
106
106
  'snapshotDelay': 10, # how many deltas to cache before fetching a snapshot
107
107
  'snapshotMaxRetries': 3,
108
+ 'checksum': True,
108
109
  },
109
110
  'watchBalance': {
110
111
  'settle': 'usdt', # or btc
@@ -460,10 +461,12 @@ class gate(ccxt.async_support.gate):
460
461
  elif nonce >= deltaStart - 1:
461
462
  self.handle_delta(storedOrderBook, delta)
462
463
  else:
463
- error = InvalidNonce(self.id + ' orderbook update has a nonce bigger than u')
464
464
  del client.subscriptions[messageHash]
465
465
  del self.orderbooks[symbol]
466
- client.reject(error, messageHash)
466
+ checksum = self.handle_option('watchOrderBook', 'checksum', True)
467
+ if checksum:
468
+ error = ChecksumError(self.id + ' ' + self.orderbook_checksum_message(symbol))
469
+ client.reject(error, messageHash)
467
470
  client.resolve(storedOrderBook, messageHash)
468
471
 
469
472
  def get_cache_index(self, orderBook, cache):
@@ -1192,7 +1195,7 @@ class gate(ccxt.async_support.gate):
1192
1195
  elif event == 'finish':
1193
1196
  status = self.safe_string(parsed, 'status')
1194
1197
  if status is None:
1195
- left = self.safe_number(info, 'left')
1198
+ left = self.safe_integer(info, 'left')
1196
1199
  parsed['status'] = 'closed' if (left == 0) else 'canceled'
1197
1200
  stored.append(parsed)
1198
1201
  symbol = parsed['symbol']
ccxt/pro/gemini.py CHANGED
@@ -11,6 +11,7 @@ from ccxt.async_support.base.ws.client import Client
11
11
  from typing import List
12
12
  from ccxt.base.errors import ExchangeError
13
13
  from ccxt.base.errors import NotSupported
14
+ from ccxt.base.precise import Precise
14
15
 
15
16
 
16
17
  class gemini(ccxt.async_support.gemini):
@@ -445,9 +446,10 @@ class gemini(ccxt.async_support.gemini):
445
446
  entry = rawBidAskChanges[i]
446
447
  rawSide = self.safe_string(entry, 'side')
447
448
  price = self.safe_number(entry, 'price')
448
- size = self.safe_number(entry, 'remaining')
449
- if size == 0:
449
+ sizeString = self.safe_string(entry, 'remaining')
450
+ if Precise.string_eq(sizeString, '0'):
450
451
  continue
452
+ size = self.parse_number(sizeString)
451
453
  if rawSide == 'bid':
452
454
  currentBidAsk['bid'] = price
453
455
  currentBidAsk['bidVolume'] = size
ccxt/pro/htx.py CHANGED
@@ -16,6 +16,7 @@ from ccxt.base.errors import BadRequest
16
16
  from ccxt.base.errors import BadSymbol
17
17
  from ccxt.base.errors import NetworkError
18
18
  from ccxt.base.errors import InvalidNonce
19
+ from ccxt.base.errors import ChecksumError
19
20
 
20
21
 
21
22
  class htx(ccxt.async_support.htx):
@@ -109,6 +110,7 @@ class htx(ccxt.async_support.htx):
109
110
  'api': 'api', # or api-aws for clients hosted on AWS
110
111
  'watchOrderBook': {
111
112
  'maxRetries': 3,
113
+ 'checksum': True,
112
114
  },
113
115
  'ws': {
114
116
  'gunzip': True,
@@ -549,7 +551,9 @@ class htx(ccxt.async_support.htx):
549
551
  orderbook.reset(snapshot)
550
552
  orderbook['nonce'] = version
551
553
  if (prevSeqNum is not None) and prevSeqNum > orderbook['nonce']:
552
- raise InvalidNonce(self.id + ' watchOrderBook() received a mesage out of order')
554
+ checksum = self.handle_option('watchOrderBook', 'checksum', True)
555
+ if checksum:
556
+ raise ChecksumError(self.id + ' ' + self.orderbook_checksum_message(symbol))
553
557
  spotConditon = market['spot'] and (prevSeqNum == orderbook['nonce'])
554
558
  nonSpotCondition = market['contract'] and (version - 1 == orderbook['nonce'])
555
559
  if spotConditon or nonSpotCondition:
@@ -9,7 +9,7 @@ from ccxt.base.types import Int, OrderBook, Trade
9
9
  from ccxt.async_support.base.ws.client import Client
10
10
  from typing import List
11
11
  from ccxt.base.errors import NotSupported
12
- from ccxt.base.errors import InvalidNonce
12
+ from ccxt.base.errors import ChecksumError
13
13
 
14
14
 
15
15
  class independentreserve(ccxt.async_support.independentreserve):
@@ -33,7 +33,9 @@ class independentreserve(ccxt.async_support.independentreserve):
33
33
  },
34
34
  },
35
35
  'options': {
36
- 'checksum': False, # TODO: currently only working for snapshot
36
+ 'watchOrderBook': {
37
+ 'checksum': True, # TODO: currently only working for snapshot
38
+ },
37
39
  },
38
40
  'streaming': {
39
41
  },
@@ -196,7 +198,7 @@ class independentreserve(ccxt.async_support.independentreserve):
196
198
  self.handle_deltas(orderbook['bids'], bids)
197
199
  orderbook['timestamp'] = timestamp
198
200
  orderbook['datetime'] = self.iso8601(timestamp)
199
- checksum = self.safe_bool(self.options, 'checksum', True)
201
+ checksum = self.handle_option('watchOrderBook', 'checksum', True)
200
202
  if checksum and receivedSnapshot:
201
203
  storedAsks = orderbook['asks']
202
204
  storedBids = orderbook['bids']
@@ -212,7 +214,7 @@ class independentreserve(ccxt.async_support.independentreserve):
212
214
  calculatedChecksum = self.crc32(payload, True)
213
215
  responseChecksum = self.safe_integer(orderBook, 'Crc32')
214
216
  if calculatedChecksum != responseChecksum:
215
- error = InvalidNonce(self.id + ' invalid checksum')
217
+ error = ChecksumError(self.id + ' ' + self.orderbook_checksum_message(symbol))
216
218
  del client.subscriptions[messageHash]
217
219
  del self.orderbooks[symbol]
218
220
  client.reject(error, messageHash)
ccxt/pro/kraken.py CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  import ccxt.async_support
7
7
  from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById, ArrayCacheByTimestamp
8
- from ccxt.base.types import Int, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade
8
+ from ccxt.base.types import Balances, Int, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade
9
9
  from ccxt.async_support.base.ws.client import Client
10
10
  from typing import List
11
11
  from ccxt.base.errors import ExchangeError
@@ -20,7 +20,7 @@ from ccxt.base.errors import OrderNotFound
20
20
  from ccxt.base.errors import NotSupported
21
21
  from ccxt.base.errors import RateLimitExceeded
22
22
  from ccxt.base.errors import ExchangeNotAvailable
23
- from ccxt.base.errors import InvalidNonce
23
+ from ccxt.base.errors import ChecksumError
24
24
  from ccxt.base.precise import Precise
25
25
 
26
26
 
@@ -30,7 +30,7 @@ class kraken(ccxt.async_support.kraken):
30
30
  return self.deep_extend(super(kraken, self).describe(), {
31
31
  'has': {
32
32
  'ws': True,
33
- 'watchBalance': False, # no such type of subscription 2021-01-05
33
+ 'watchBalance': True,
34
34
  'watchMyTrades': True,
35
35
  'watchOHLCV': True,
36
36
  'watchOrderBook': True,
@@ -53,6 +53,7 @@ class kraken(ccxt.async_support.kraken):
53
53
  'ws': {
54
54
  'public': 'wss://ws.kraken.com',
55
55
  'private': 'wss://ws-auth.kraken.com',
56
+ 'privateV2': 'wss://ws-auth.kraken.com/v2',
56
57
  'beta': 'wss://beta-ws.kraken.com',
57
58
  'beta-private': 'wss://beta-ws-auth.kraken.com',
58
59
  },
@@ -66,7 +67,9 @@ class kraken(ccxt.async_support.kraken):
66
67
  'OHLCVLimit': 1000,
67
68
  'ordersLimit': 1000,
68
69
  'symbolsByOrderId': {},
69
- 'checksum': True,
70
+ 'watchOrderBook': {
71
+ 'checksum': True,
72
+ },
70
73
  },
71
74
  'exceptions': {
72
75
  'ws': {
@@ -715,7 +718,7 @@ class kraken(ccxt.async_support.kraken):
715
718
  example = self.safe_value(b, 0)
716
719
  # don't remove self line or I will poop on your face
717
720
  orderbook.limit()
718
- checksum = self.safe_bool(self.options, 'checksum', True)
721
+ checksum = self.handle_option('watchOrderBook', 'checksum', True)
719
722
  if checksum:
720
723
  priceString = self.safe_string(example, 0)
721
724
  amountString = self.safe_string(example, 1)
@@ -734,7 +737,7 @@ class kraken(ccxt.async_support.kraken):
734
737
  payload = ''.join(payloadArray)
735
738
  localChecksum = self.crc32(payload, False)
736
739
  if localChecksum != c:
737
- error = InvalidNonce(self.id + ' invalid checksum')
740
+ error = ChecksumError(self.id + ' ' + self.orderbook_checksum_message(symbol))
738
741
  del client.subscriptions[messageHash]
739
742
  del self.orderbooks[symbol]
740
743
  client.reject(error, messageHash)
@@ -1247,6 +1250,68 @@ class kraken(ccxt.async_support.kraken):
1247
1250
  url = self.urls['api']['ws']['public']
1248
1251
  return await self.watch_multiple(url, messageHashes, self.deep_extend(request, params), messageHashes, subscriptionArgs)
1249
1252
 
1253
+ async def watch_balance(self, params={}) -> Balances:
1254
+ """
1255
+ watch balance and get the amount of funds available for trading or funds locked in orders
1256
+ :see: https://docs.kraken.com/api/docs/websocket-v2/balances
1257
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1258
+ :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
1259
+ """
1260
+ await self.load_markets()
1261
+ token = await self.authenticate()
1262
+ messageHash = 'balances'
1263
+ url = self.urls['api']['ws']['privateV2']
1264
+ requestId = self.request_id()
1265
+ subscribe: dict = {
1266
+ 'method': 'subscribe',
1267
+ 'req_id': requestId,
1268
+ 'params': {
1269
+ 'channel': 'balances',
1270
+ 'token': token,
1271
+ },
1272
+ }
1273
+ request = self.deep_extend(subscribe, params)
1274
+ return await self.watch(url, messageHash, request, messageHash)
1275
+
1276
+ def handle_balance(self, client: Client, message):
1277
+ #
1278
+ # {
1279
+ # "channel": "balances",
1280
+ # "data": [
1281
+ # {
1282
+ # "asset": "BTC",
1283
+ # "asset_class": "currency",
1284
+ # "balance": 1.2,
1285
+ # "wallets": [
1286
+ # {
1287
+ # "type": "spot",
1288
+ # "id": "main",
1289
+ # "balance": 1.2
1290
+ # }
1291
+ # ]
1292
+ # }
1293
+ # ],
1294
+ # "type": "snapshot",
1295
+ # "sequence": 1
1296
+ # }
1297
+ #
1298
+ data = self.safe_list(message, 'data', [])
1299
+ result: dict = {'info': message}
1300
+ for i in range(0, len(data)):
1301
+ currencyId = self.safe_string(data[i], 'asset')
1302
+ code = self.safe_currency_code(currencyId)
1303
+ account = self.account()
1304
+ eq = self.safe_string(data[i], 'balance')
1305
+ account['total'] = eq
1306
+ result[code] = account
1307
+ type = 'spot'
1308
+ balance = self.safe_balance(result)
1309
+ oldBalance = self.safe_value(self.balance, type, {})
1310
+ newBalance = self.deep_extend(oldBalance, balance)
1311
+ self.balance[type] = self.safe_balance(newBalance)
1312
+ channel = self.safe_string(message, 'channel')
1313
+ client.resolve(self.balance[type], channel)
1314
+
1250
1315
  def get_message_hash(self, unifiedElementName: str, subChannelName: Str = None, symbol: Str = None):
1251
1316
  # unifiedElementName can be : orderbook, trade, ticker, bidask ...
1252
1317
  # subChannelName only applies to channel that needs specific variation(i.e. depth_50, depth_100..) to be selected
@@ -1340,6 +1405,14 @@ class kraken(ccxt.async_support.kraken):
1340
1405
  if method is not None:
1341
1406
  method(client, message, subscription)
1342
1407
  else:
1408
+ channel = self.safe_string(message, 'channel')
1409
+ if channel is not None:
1410
+ methods: dict = {
1411
+ 'balances': self.handle_balance,
1412
+ }
1413
+ method = self.safe_value(methods, channel)
1414
+ if method is not None:
1415
+ method(client, message)
1343
1416
  if self.handle_error_message(client, message):
1344
1417
  event = self.safe_string(message, 'event')
1345
1418
  methods: dict = {
ccxt/pro/okx.py CHANGED
@@ -13,7 +13,7 @@ from ccxt.base.errors import ExchangeError
13
13
  from ccxt.base.errors import AuthenticationError
14
14
  from ccxt.base.errors import ArgumentsRequired
15
15
  from ccxt.base.errors import BadRequest
16
- from ccxt.base.errors import InvalidNonce
16
+ from ccxt.base.errors import ChecksumError
17
17
 
18
18
 
19
19
  class okx(ccxt.async_support.okx):
@@ -56,6 +56,7 @@ class okx(ccxt.async_support.okx):
56
56
  },
57
57
  'options': {
58
58
  'watchOrderBook': {
59
+ 'checksum': True,
59
60
  #
60
61
  # bbo-tbt
61
62
  # 1. Newly added channel that sends tick-by-tick Level 1 data
@@ -103,7 +104,6 @@ class okx(ccxt.async_support.okx):
103
104
  'ws': {
104
105
  # 'inflate': True,
105
106
  },
106
- 'checksum': True,
107
107
  },
108
108
  'streaming': {
109
109
  # okex does not support built-in ws protocol-level ping-pong
@@ -861,7 +861,7 @@ class okx(ccxt.async_support.okx):
861
861
  self.handle_deltas(storedBids, bids)
862
862
  marketId = self.safe_string(message, 'instId')
863
863
  symbol = self.safe_symbol(marketId)
864
- checksum = self.safe_bool(self.options, 'checksum', True)
864
+ checksum = self.handle_option('watchOrderBook', 'checksum', True)
865
865
  if checksum:
866
866
  asksLength = len(storedAsks)
867
867
  bidsLength = len(storedBids)
@@ -877,7 +877,7 @@ class okx(ccxt.async_support.okx):
877
877
  responseChecksum = self.safe_integer(message, 'checksum')
878
878
  localChecksum = self.crc32(payload, True)
879
879
  if responseChecksum != localChecksum:
880
- error = InvalidNonce(self.id + ' invalid checksum')
880
+ error = ChecksumError(self.id + ' ' + self.orderbook_checksum_message(symbol))
881
881
  del client.subscriptions[messageHash]
882
882
  del self.orderbooks[symbol]
883
883
  client.reject(error, messageHash)
@@ -1645,7 +1645,7 @@ class okx(ccxt.async_support.okx):
1645
1645
  :param dict [params]: extra parameters specific to the exchange API endpoint
1646
1646
  :returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1647
1647
  """
1648
- idsLength = len(ids)
1648
+ idsLength: number = len(ids)
1649
1649
  if idsLength > 20:
1650
1650
  raise BadRequest(self.id + ' cancelOrdersWs() accepts up to 20 ids at a time')
1651
1651
  if symbol is None:
ccxt/pro/onetrading.py CHANGED
@@ -10,6 +10,7 @@ from ccxt.async_support.base.ws.client import Client
10
10
  from typing import List
11
11
  from ccxt.base.errors import ExchangeError
12
12
  from ccxt.base.errors import NotSupported
13
+ from ccxt.base.precise import Precise
13
14
 
14
15
 
15
16
  class onetrading(ccxt.async_support.onetrading):
@@ -934,9 +935,9 @@ class onetrading(ccxt.async_support.onetrading):
934
935
  previousOrderArray = self.filter_by_array(self.orders, 'id', orderId, False)
935
936
  previousOrder = self.safe_value(previousOrderArray, 0, {})
936
937
  symbol = previousOrder['symbol']
937
- filled = self.safe_number(update, 'filled_amount')
938
+ filled = self.safe_string(update, 'filled_amount')
938
939
  status = self.parse_ws_order_status(updateType)
939
- if updateType == 'ORDER_CLOSED' and filled == 0:
940
+ if updateType == 'ORDER_CLOSED' and Precise.string_eq(filled, '0'):
940
941
  status = 'canceled'
941
942
  orderObject: dict = {
942
943
  'id': orderId,
ccxt/pro/oxfun.py CHANGED
@@ -854,7 +854,7 @@ class oxfun(ccxt.async_support.oxfun):
854
854
  :param dict [params]: extra parameters specific to the exchange API endpoint
855
855
  :returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
856
856
  """
857
- idsLength = len(ids)
857
+ idsLength: number = len(ids)
858
858
  if idsLength > 20:
859
859
  raise BadRequest(self.id + ' cancelOrdersWs() accepts up to 20 ids at a time')
860
860
  if symbol is None:
@@ -10,7 +10,7 @@ from ccxt.async_support.base.ws.client import Client
10
10
  from typing import List
11
11
  from ccxt.base.errors import AuthenticationError
12
12
  from ccxt.base.errors import BadRequest
13
- from ccxt.base.errors import InvalidNonce
13
+ from ccxt.base.errors import ChecksumError
14
14
 
15
15
 
16
16
  class poloniexfutures(ccxt.async_support.poloniexfutures):
@@ -57,6 +57,7 @@ class poloniexfutures(ccxt.async_support.poloniexfutures):
57
57
  'method': '/contractMarket/level2', # can also be '/contractMarket/level3v2'
58
58
  'snapshotDelay': 5,
59
59
  'snapshotMaxRetries': 3,
60
+ 'checksum': True,
60
61
  },
61
62
  'streamLimit': 5, # called tunnels by poloniexfutures docs
62
63
  'streamBySubscriptionsHash': {},
@@ -822,7 +823,9 @@ class poloniexfutures(ccxt.async_support.poloniexfutures):
822
823
  if nonce > sequence:
823
824
  return
824
825
  if nonce != lastSequence:
825
- raise InvalidNonce(self.id + ' watchOrderBook received an out-of-order nonce')
826
+ checksum = self.handle_option('watchOrderBook', 'checksum', True)
827
+ if checksum:
828
+ raise ChecksumError(self.id + ' ' + self.orderbook_checksum_message(''))
826
829
  changes = self.safe_list(delta, 'changes')
827
830
  for i in range(0, len(changes)):
828
831
  change = changes[i]
ccxt/pro/vertex.py CHANGED
@@ -798,9 +798,10 @@ class vertex(ccxt.async_support.vertex):
798
798
  #
799
799
  marketId = self.safe_string(order, 'product_id')
800
800
  timestamp = self.parse_to_int(Precise.string_div(self.safe_string(order, 'timestamp'), '1000000'))
801
- remaining = self.parse_to_numeric(self.convertFromX18(self.safe_string(order, 'amount')))
801
+ remainingString = self.convertFromX18(self.safe_string(order, 'amount'))
802
+ remaining = self.parse_to_numeric(remainingString)
802
803
  status = self.parse_ws_order_status(self.safe_string(order, 'reason'))
803
- if remaining == 0 and status == 'open':
804
+ if Precise.string_eq(remainingString, '0') and status == 'open':
804
805
  status = 'closed'
805
806
  market = self.safe_market(marketId, market)
806
807
  symbol = market['symbol']
ccxt/pro/woo.py CHANGED
@@ -638,9 +638,10 @@ class woo(ccxt.async_support.woo):
638
638
  'cost': self.safe_string(order, 'totalFee'),
639
639
  'currency': self.safe_string(order, 'feeAsset'),
640
640
  }
641
+ priceString = self.safe_string(order, 'price')
641
642
  price = self.safe_number(order, 'price')
642
643
  avgPrice = self.safe_number(order, 'avgPrice')
643
- if (price == 0) and (avgPrice is not None):
644
+ if Precise.string_eq(priceString, '0') and (avgPrice is not None):
644
645
  price = avgPrice
645
646
  amount = self.safe_float(order, 'quantity')
646
647
  side = self.safe_string_lower(order, 'side')
ccxt/pro/woofipro.py CHANGED
@@ -363,7 +363,7 @@ class woofipro(ccxt.async_support.woofipro):
363
363
  :param int [since]: the earliest time in ms to fetch trades for
364
364
  :param int [limit]: the maximum number of trade structures to retrieve
365
365
  :param dict [params]: extra parameters specific to the exchange API endpoint
366
- :returns dict[]: a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure
366
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
367
367
  """
368
368
  await self.load_markets()
369
369
  market = self.market(symbol)
@@ -686,9 +686,10 @@ class woofipro(ccxt.async_support.woofipro):
686
686
  'cost': self.safe_string(order, 'totalFee'),
687
687
  'currency': self.safe_string(order, 'feeAsset'),
688
688
  }
689
+ priceString = self.safe_string(order, 'price')
689
690
  price = self.safe_number(order, 'price')
690
691
  avgPrice = self.safe_number(order, 'avgPrice')
691
- if (price == 0) and (avgPrice is not None):
692
+ if Precise.string_eq(priceString, '0') and (avgPrice is not None):
692
693
  price = avgPrice
693
694
  amount = self.safe_string(order, 'quantity')
694
695
  side = self.safe_string_lower(order, 'side')
ccxt/test/tests_async.py CHANGED
@@ -818,7 +818,7 @@ class testMainClass(baseMainTestClass):
818
818
  new_input.append(current)
819
819
  return new_input
820
820
 
821
- async def test_method_statically(self, exchange, method, data, type, skip_keys):
821
+ async def test_request_statically(self, exchange, method, data, type, skip_keys):
822
822
  output = None
823
823
  request_url = None
824
824
  try:
@@ -850,7 +850,7 @@ class testMainClass(baseMainTestClass):
850
850
  unified_result_sync = call_exchange_method_dynamically_sync(exchange, method, self.sanitize_data_input(data['input']))
851
851
  self.assert_static_response_output(mocked_exchange, skip_keys, unified_result_sync, expected_result)
852
852
  except Exception as e:
853
- self.request_tests_failed = True
853
+ self.response_tests_failed = True
854
854
  error_message = '[' + self.lang + '][STATIC_RESPONSE_TEST_FAILURE]' + '[' + self.exchange_hint(exchange) + ']' + '[' + method + ']' + '[' + data['description'] + ']' + str(e)
855
855
  dump('[TEST_FAILURE]' + error_message)
856
856
  set_fetch_response(exchange, None) # reset state
@@ -929,7 +929,7 @@ class testMainClass(baseMainTestClass):
929
929
  continue
930
930
  type = exchange.safe_string(exchange_data, 'outputType')
931
931
  skip_keys = exchange.safe_value(exchange_data, 'skipKeys', [])
932
- await self.test_method_statically(exchange, method, result, type, skip_keys)
932
+ await self.test_request_statically(exchange, method, result, type, skip_keys)
933
933
  # reset options
934
934
  # exchange.options = exchange.deepExtend (oldExchangeOptions, {});
935
935
  exchange.extend_exchange_options(exchange.deep_extend(old_exchange_options, {}))
@@ -73,7 +73,6 @@ parser.add_argument('--requestTests', action='store_true', help='run response te
73
73
  parser.add_argument('--sync', action='store_true', help='is sync')
74
74
  parser.add_argument('--baseTests', action='store_true', help='is base tests')
75
75
  parser.add_argument('--exchangeTests', action='store_true', help='is exchange tests')
76
- parser.add_argument('--nonce', type=int, help='integer')
77
76
  parser.add_argument('exchange', type=str, help='exchange id in lowercase', nargs='?')
78
77
  parser.add_argument('symbol', type=str, help='symbol in uppercase', nargs='?')
79
78
  parser.parse_args(namespace=argv)
@@ -279,6 +278,7 @@ def set_fetch_response(exchange: ccxt.Exchange, data):
279
278
  return exchange
280
279
 
281
280
 
281
+ argvExchange = argv.exchange
282
282
  argvSymbol = argv.symbol if argv.symbol and '/' in argv.symbol else None
283
283
  # in python, we check it through "symbol" arg (as opposed to JS/PHP) because argvs were already built above
284
284
  argvMethod = argv.symbol if argv.symbol and '()' in argv.symbol else None
ccxt/test/tests_init.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
- from tests_helpers import get_cli_arg_value, is_synchronous, argv, argvSymbol, argvMethod
3
+ from tests_helpers import get_cli_arg_value, is_synchronous, argvExchange, argvSymbol, argvMethod
4
4
 
5
5
  try:
6
6
  import asyncio
@@ -29,7 +29,7 @@ if (isBaseTests):
29
29
  # ###### exchange tests #######
30
30
  if (is_synchronous):
31
31
  from tests_sync import testMainClass as testMainClassSync
32
- testMainClassSync().init(argv.exchange, argvSymbol, argvMethod)
32
+ testMainClassSync().init(argvExchange, argvSymbol, argvMethod)
33
33
  else:
34
34
  from tests_async import testMainClass as testMainClassAsync
35
- asyncio.run(testMainClassAsync().init(argv.exchange, argvSymbol, argvMethod))
35
+ asyncio.run(testMainClassAsync().init(argvExchange, argvSymbol, argvMethod))
ccxt/test/tests_sync.py CHANGED
@@ -815,7 +815,7 @@ class testMainClass(baseMainTestClass):
815
815
  new_input.append(current)
816
816
  return new_input
817
817
 
818
- def test_method_statically(self, exchange, method, data, type, skip_keys):
818
+ def test_request_statically(self, exchange, method, data, type, skip_keys):
819
819
  output = None
820
820
  request_url = None
821
821
  try:
@@ -847,7 +847,7 @@ class testMainClass(baseMainTestClass):
847
847
  unified_result_sync = call_exchange_method_dynamically_sync(exchange, method, self.sanitize_data_input(data['input']))
848
848
  self.assert_static_response_output(mocked_exchange, skip_keys, unified_result_sync, expected_result)
849
849
  except Exception as e:
850
- self.request_tests_failed = True
850
+ self.response_tests_failed = True
851
851
  error_message = '[' + self.lang + '][STATIC_RESPONSE_TEST_FAILURE]' + '[' + self.exchange_hint(exchange) + ']' + '[' + method + ']' + '[' + data['description'] + ']' + str(e)
852
852
  dump('[TEST_FAILURE]' + error_message)
853
853
  set_fetch_response(exchange, None) # reset state
@@ -926,7 +926,7 @@ class testMainClass(baseMainTestClass):
926
926
  continue
927
927
  type = exchange.safe_string(exchange_data, 'outputType')
928
928
  skip_keys = exchange.safe_value(exchange_data, 'skipKeys', [])
929
- self.test_method_statically(exchange, method, result, type, skip_keys)
929
+ self.test_request_statically(exchange, method, result, type, skip_keys)
930
930
  # reset options
931
931
  # exchange.options = exchange.deepExtend (oldExchangeOptions, {});
932
932
  exchange.extend_exchange_options(exchange.deep_extend(old_exchange_options, {}))
ccxt/whitebit.py CHANGED
@@ -2404,7 +2404,7 @@ class whitebit(Exchange, ImplicitAPI):
2404
2404
  records = self.safe_list(response, 'records')
2405
2405
  return self.parse_transactions(records, currency, since, limit)
2406
2406
 
2407
- def is_fiat(self, currency):
2407
+ def is_fiat(self, currency: str):
2408
2408
  fiatCurrencies = self.safe_value(self.options, 'fiatCurrencies', [])
2409
2409
  return self.in_array(currency, fiatCurrencies)
2410
2410