ccxt 4.3.65__py2.py3-none-any.whl → 4.3.67__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ccxt/__init__.py +1 -1
- ccxt/abstract/bingx.py +7 -0
- ccxt/async_support/__init__.py +1 -1
- ccxt/async_support/base/exchange.py +1 -1
- ccxt/async_support/base/ws/fast_client.py +2 -1
- ccxt/async_support/base/ws/future.py +13 -2
- ccxt/async_support/bingx.py +147 -19
- ccxt/async_support/bithumb.py +60 -17
- ccxt/async_support/hyperliquid.py +60 -7
- ccxt/async_support/kraken.py +25 -0
- ccxt/async_support/whitebit.py +1 -1
- ccxt/async_support/zonda.py +1 -1
- ccxt/base/exchange.py +10 -10
- ccxt/bingx.py +147 -19
- ccxt/bithumb.py +59 -17
- ccxt/hyperliquid.py +60 -7
- ccxt/kraken.py +25 -0
- ccxt/pro/__init__.py +1 -1
- ccxt/pro/bitget.py +1 -1
- ccxt/pro/bybit.py +1 -1
- ccxt/pro/coinone.py +1 -1
- ccxt/pro/currencycom.py +1 -1
- ccxt/pro/hollaex.py +1 -1
- ccxt/pro/hyperliquid.py +103 -3
- ccxt/pro/kucoin.py +1 -1
- ccxt/pro/kucoinfutures.py +1 -1
- ccxt/pro/mexc.py +1 -1
- ccxt/pro/okcoin.py +1 -1
- ccxt/pro/okx.py +21 -9
- ccxt/pro/oxfun.py +1 -1
- ccxt/pro/p2b.py +1 -1
- ccxt/pro/poloniex.py +1 -1
- ccxt/pro/whitebit.py +1 -1
- ccxt/test/tests_async.py +58 -28
- ccxt/test/tests_helpers.py +8 -1
- ccxt/test/tests_sync.py +58 -28
- ccxt/whitebit.py +1 -1
- ccxt/zonda.py +1 -1
- {ccxt-4.3.65.dist-info → ccxt-4.3.67.dist-info}/METADATA +5 -4
- {ccxt-4.3.65.dist-info → ccxt-4.3.67.dist-info}/RECORD +43 -43
- {ccxt-4.3.65.dist-info → ccxt-4.3.67.dist-info}/LICENSE.txt +0 -0
- {ccxt-4.3.65.dist-info → ccxt-4.3.67.dist-info}/WHEEL +0 -0
- {ccxt-4.3.65.dist-info → ccxt-4.3.67.dist-info}/top_level.txt +0 -0
ccxt/pro/currencycom.py
CHANGED
ccxt/pro/hollaex.py
CHANGED
@@ -546,7 +546,7 @@ class hollaex(ccxt.async_support.hollaex):
|
|
546
546
|
if method is not None:
|
547
547
|
method(client, message)
|
548
548
|
|
549
|
-
def ping(self, client):
|
549
|
+
def ping(self, client: Client):
|
550
550
|
# hollaex does not support built-in ws protocol-level ping-pong
|
551
551
|
return {'op': 'ping'}
|
552
552
|
|
ccxt/pro/hyperliquid.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, Market, Order, OrderBook, Str, Trade
|
8
|
+
from ccxt.base.types import Int, Market, Order, OrderBook, 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
|
@@ -23,7 +23,7 @@ class hyperliquid(ccxt.async_support.hyperliquid):
|
|
23
23
|
'watchOrderBook': True,
|
24
24
|
'watchOrders': True,
|
25
25
|
'watchTicker': False,
|
26
|
-
'watchTickers':
|
26
|
+
'watchTickers': True,
|
27
27
|
'watchTrades': True,
|
28
28
|
'watchPosition': False,
|
29
29
|
},
|
@@ -123,6 +123,29 @@ class hyperliquid(ccxt.async_support.hyperliquid):
|
|
123
123
|
messageHash = 'orderbook:' + symbol
|
124
124
|
client.resolve(orderbook, messageHash)
|
125
125
|
|
126
|
+
async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
|
127
|
+
"""
|
128
|
+
watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
|
129
|
+
:param str[] symbols: unified symbol of the market to fetch the ticker for
|
130
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
131
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
132
|
+
"""
|
133
|
+
await self.load_markets()
|
134
|
+
symbols = self.market_symbols(symbols, None, True)
|
135
|
+
messageHash = 'tickers'
|
136
|
+
url = self.urls['api']['ws']['public']
|
137
|
+
request: dict = {
|
138
|
+
'method': 'subscribe',
|
139
|
+
'subscription': {
|
140
|
+
'type': 'webData2', # allMids
|
141
|
+
'user': '0x0000000000000000000000000000000000000000',
|
142
|
+
},
|
143
|
+
}
|
144
|
+
tickers = await self.watch(url, messageHash, self.extend(request, params), messageHash)
|
145
|
+
if self.newUpdates:
|
146
|
+
return self.filter_by_array_tickers(tickers, 'symbol', symbols)
|
147
|
+
return self.tickers
|
148
|
+
|
126
149
|
async def watch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
127
150
|
"""
|
128
151
|
watches information on multiple trades made by the user
|
@@ -154,6 +177,82 @@ class hyperliquid(ccxt.async_support.hyperliquid):
|
|
154
177
|
limit = trades.getLimit(symbol, limit)
|
155
178
|
return self.filter_by_symbol_since_limit(trades, symbol, since, limit, True)
|
156
179
|
|
180
|
+
def handle_ws_tickers(self, client: Client, message):
|
181
|
+
#
|
182
|
+
# {
|
183
|
+
# "channel": "webData2",
|
184
|
+
# "data": {
|
185
|
+
# "meta": {
|
186
|
+
# "universe": [
|
187
|
+
# {
|
188
|
+
# "szDecimals": 5,
|
189
|
+
# "name": "BTC",
|
190
|
+
# "maxLeverage": 50,
|
191
|
+
# "onlyIsolated": False
|
192
|
+
# },
|
193
|
+
# ...
|
194
|
+
# ],
|
195
|
+
# },
|
196
|
+
# "assetCtxs": [
|
197
|
+
# {
|
198
|
+
# "funding": "0.00003005",
|
199
|
+
# "openInterest": "2311.50778",
|
200
|
+
# "prevDayPx": "63475.0",
|
201
|
+
# "dayNtlVlm": "468043329.64289033",
|
202
|
+
# "premium": "0.00094264",
|
203
|
+
# "oraclePx": "64712.0",
|
204
|
+
# "markPx": "64774.0",
|
205
|
+
# "midPx": "64773.5",
|
206
|
+
# "impactPxs": [
|
207
|
+
# "64773.0",
|
208
|
+
# "64774.0"
|
209
|
+
# ]
|
210
|
+
# },
|
211
|
+
# ...
|
212
|
+
# ],
|
213
|
+
# "spotAssetCtxs": [
|
214
|
+
# {
|
215
|
+
# "prevDayPx": "0.20937",
|
216
|
+
# "dayNtlVlm": "11188888.61984999",
|
217
|
+
# "markPx": "0.19722",
|
218
|
+
# "midPx": "0.197145",
|
219
|
+
# "circulatingSupply": "598760557.12072003",
|
220
|
+
# "coin": "PURR/USDC"
|
221
|
+
# },
|
222
|
+
# ...
|
223
|
+
# ],
|
224
|
+
# }
|
225
|
+
# }
|
226
|
+
#
|
227
|
+
# spot
|
228
|
+
rawData = self.safe_dict(message, 'data', {})
|
229
|
+
spotAssets = self.safe_list(rawData, 'spotAssetCtxs', [])
|
230
|
+
parsedTickers = []
|
231
|
+
for i in range(0, len(spotAssets)):
|
232
|
+
assetObject = spotAssets[i]
|
233
|
+
marketId = self.safe_string(assetObject, 'coin')
|
234
|
+
market = self.safe_market(marketId, None, None, 'spot')
|
235
|
+
ticker = self.parse_ws_ticker(assetObject, market)
|
236
|
+
parsedTickers.append(ticker)
|
237
|
+
# perpetuals
|
238
|
+
meta = self.safe_dict(rawData, 'meta', {})
|
239
|
+
universe = self.safe_list(meta, 'universe', [])
|
240
|
+
assetCtxs = self.safe_list(rawData, 'assetCtxs', [])
|
241
|
+
for i in range(0, len(universe)):
|
242
|
+
data = self.extend(
|
243
|
+
self.safe_dict(universe, i, {}),
|
244
|
+
self.safe_dict(assetCtxs, i, {})
|
245
|
+
)
|
246
|
+
id = data['name'] + '/USDC:USDC'
|
247
|
+
market = self.safe_market(id, None, None, 'swap')
|
248
|
+
ticker = self.parse_ws_ticker(data, market)
|
249
|
+
parsedTickers.append(ticker)
|
250
|
+
tickers = self.index_by(parsedTickers, 'symbol')
|
251
|
+
client.resolve(tickers, 'tickers')
|
252
|
+
|
253
|
+
def parse_ws_ticker(self, rawTicker, market: Market = None) -> Ticker:
|
254
|
+
return self.parse_ticker(rawTicker, market)
|
255
|
+
|
157
256
|
def handle_my_trades(self, client: Client, message):
|
158
257
|
#
|
159
258
|
# {
|
@@ -497,6 +596,7 @@ class hyperliquid(ccxt.async_support.hyperliquid):
|
|
497
596
|
'candle': self.handle_ohlcv,
|
498
597
|
'orderUpdates': self.handle_order,
|
499
598
|
'userFills': self.handle_my_trades,
|
599
|
+
'webData2': self.handle_ws_tickers,
|
500
600
|
}
|
501
601
|
exacMethod = self.safe_value(methods, topic)
|
502
602
|
if exacMethod is not None:
|
@@ -510,7 +610,7 @@ class hyperliquid(ccxt.async_support.hyperliquid):
|
|
510
610
|
method(client, message)
|
511
611
|
return
|
512
612
|
|
513
|
-
def ping(self, client):
|
613
|
+
def ping(self, client: Client):
|
514
614
|
return {
|
515
615
|
'method': 'ping',
|
516
616
|
}
|
ccxt/pro/kucoin.py
CHANGED
@@ -1155,7 +1155,7 @@ class kucoin(ccxt.async_support.kucoin):
|
|
1155
1155
|
if method is not None:
|
1156
1156
|
method(client, message)
|
1157
1157
|
|
1158
|
-
def ping(self, client):
|
1158
|
+
def ping(self, client: Client):
|
1159
1159
|
# kucoin does not support built-in ws protocol-level ping-pong
|
1160
1160
|
# instead it requires a custom json-based text ping-pong
|
1161
1161
|
# https://docs.kucoin.com/#ping
|
ccxt/pro/kucoinfutures.py
CHANGED
@@ -1035,7 +1035,7 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
|
|
1035
1035
|
else:
|
1036
1036
|
return elementName + 's@all'
|
1037
1037
|
|
1038
|
-
def ping(self, client):
|
1038
|
+
def ping(self, client: Client):
|
1039
1039
|
# kucoin does not support built-in ws protocol-level ping-pong
|
1040
1040
|
# instead it requires a custom json-based text ping-pong
|
1041
1041
|
# https://docs.kucoin.com/#ping
|
ccxt/pro/mexc.py
CHANGED
ccxt/pro/okcoin.py
CHANGED
@@ -573,7 +573,7 @@ class okcoin(ccxt.async_support.okcoin):
|
|
573
573
|
client.resolve(message, 'authenticated')
|
574
574
|
return message
|
575
575
|
|
576
|
-
def ping(self, client):
|
576
|
+
def ping(self, client: Client):
|
577
577
|
# okex does not support built-in ws protocol-level ping-pong
|
578
578
|
# instead it requires custom text-based ping-pong
|
579
579
|
return 'ping'
|
ccxt/pro/okx.py
CHANGED
@@ -13,6 +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
17
|
from ccxt.base.errors import ChecksumError
|
17
18
|
|
18
19
|
|
@@ -836,7 +837,7 @@ class okx(ccxt.async_support.okx):
|
|
836
837
|
for i in range(0, len(deltas)):
|
837
838
|
self.handle_delta(bookside, deltas[i])
|
838
839
|
|
839
|
-
def handle_order_book_message(self, client: Client, message, orderbook, messageHash):
|
840
|
+
def handle_order_book_message(self, client: Client, message, orderbook, messageHash, market=None):
|
840
841
|
#
|
841
842
|
# {
|
842
843
|
# "asks": [
|
@@ -851,6 +852,9 @@ class okx(ccxt.async_support.okx):
|
|
851
852
|
# ],
|
852
853
|
# "instId": "BTC-USDT",
|
853
854
|
# "ts": "1626537446491"
|
855
|
+
# "checksum": -855196043,
|
856
|
+
# "prevSeqId": 123456,
|
857
|
+
# "seqId": 123457
|
854
858
|
# }
|
855
859
|
#
|
856
860
|
asks = self.safe_value(message, 'asks', [])
|
@@ -860,9 +864,12 @@ class okx(ccxt.async_support.okx):
|
|
860
864
|
self.handle_deltas(storedAsks, asks)
|
861
865
|
self.handle_deltas(storedBids, bids)
|
862
866
|
marketId = self.safe_string(message, 'instId')
|
863
|
-
symbol = self.safe_symbol(marketId)
|
867
|
+
symbol = self.safe_symbol(marketId, market)
|
864
868
|
checksum = self.handle_option('watchOrderBook', 'checksum', True)
|
869
|
+
seqId = self.safe_integer(message, 'seqId')
|
865
870
|
if checksum:
|
871
|
+
prevSeqId = self.safe_integer(message, 'prevSeqId')
|
872
|
+
nonce = orderbook['nonce']
|
866
873
|
asksLength = len(storedAsks)
|
867
874
|
bidsLength = len(storedBids)
|
868
875
|
payloadArray = []
|
@@ -876,12 +883,17 @@ class okx(ccxt.async_support.okx):
|
|
876
883
|
payload = ':'.join(payloadArray)
|
877
884
|
responseChecksum = self.safe_integer(message, 'checksum')
|
878
885
|
localChecksum = self.crc32(payload, True)
|
886
|
+
error = None
|
887
|
+
if prevSeqId != -1 and nonce != prevSeqId:
|
888
|
+
error = InvalidNonce(self.id + ' watchOrderBook received invalid nonce')
|
879
889
|
if responseChecksum != localChecksum:
|
880
890
|
error = ChecksumError(self.id + ' ' + self.orderbook_checksum_message(symbol))
|
891
|
+
if error is not None:
|
881
892
|
del client.subscriptions[messageHash]
|
882
893
|
del self.orderbooks[symbol]
|
883
894
|
client.reject(error, messageHash)
|
884
895
|
timestamp = self.safe_integer(message, 'ts')
|
896
|
+
orderbook['nonce'] = seqId
|
885
897
|
orderbook['timestamp'] = timestamp
|
886
898
|
orderbook['datetime'] = self.iso8601(timestamp)
|
887
899
|
return orderbook
|
@@ -1001,7 +1013,7 @@ class okx(ccxt.async_support.okx):
|
|
1001
1013
|
orderbook = self.orderbooks[symbol]
|
1002
1014
|
for i in range(0, len(data)):
|
1003
1015
|
update = data[i]
|
1004
|
-
self.handle_order_book_message(client, update, orderbook, messageHash)
|
1016
|
+
self.handle_order_book_message(client, update, orderbook, messageHash, market)
|
1005
1017
|
client.resolve(orderbook, messageHash)
|
1006
1018
|
elif (channel == 'books5') or (channel == 'bbo-tbt'):
|
1007
1019
|
if not (symbol in self.orderbooks):
|
@@ -1528,7 +1540,7 @@ class okx(ccxt.async_support.okx):
|
|
1528
1540
|
await self.load_markets()
|
1529
1541
|
await self.authenticate()
|
1530
1542
|
url = self.get_url('private', 'private')
|
1531
|
-
messageHash = str(self.
|
1543
|
+
messageHash = str(self.milliseconds())
|
1532
1544
|
op = None
|
1533
1545
|
op, params = self.handle_option_and_params(params, 'createOrderWs', 'op', 'batch-orders')
|
1534
1546
|
args = self.create_order_request(symbol, type, side, amount, price, params)
|
@@ -1593,7 +1605,7 @@ class okx(ccxt.async_support.okx):
|
|
1593
1605
|
await self.load_markets()
|
1594
1606
|
await self.authenticate()
|
1595
1607
|
url = self.get_url('private', 'private')
|
1596
|
-
messageHash = str(self.
|
1608
|
+
messageHash = str(self.milliseconds())
|
1597
1609
|
op = None
|
1598
1610
|
op, params = self.handle_option_and_params(params, 'editOrderWs', 'op', 'amend-order')
|
1599
1611
|
args = self.edit_order_request(id, symbol, type, side, amount, price, params)
|
@@ -1619,7 +1631,7 @@ class okx(ccxt.async_support.okx):
|
|
1619
1631
|
await self.load_markets()
|
1620
1632
|
await self.authenticate()
|
1621
1633
|
url = self.get_url('private', 'private')
|
1622
|
-
messageHash = str(self.
|
1634
|
+
messageHash = str(self.milliseconds())
|
1623
1635
|
clientOrderId = self.safe_string_2(params, 'clOrdId', 'clientOrderId')
|
1624
1636
|
params = self.omit(params, ['clientOrderId', 'clOrdId'])
|
1625
1637
|
arg: dict = {
|
@@ -1653,7 +1665,7 @@ class okx(ccxt.async_support.okx):
|
|
1653
1665
|
await self.load_markets()
|
1654
1666
|
await self.authenticate()
|
1655
1667
|
url = self.get_url('private', 'private')
|
1656
|
-
messageHash = str(self.
|
1668
|
+
messageHash = str(self.milliseconds())
|
1657
1669
|
args = []
|
1658
1670
|
for i in range(0, idsLength):
|
1659
1671
|
arg: dict = {
|
@@ -1684,7 +1696,7 @@ class okx(ccxt.async_support.okx):
|
|
1684
1696
|
if market['type'] != 'option':
|
1685
1697
|
raise BadRequest(self.id + 'cancelAllOrdersWs is only applicable to Option in Portfolio Margin mode, and MMP privilege is required.')
|
1686
1698
|
url = self.get_url('private', 'private')
|
1687
|
-
messageHash = str(self.
|
1699
|
+
messageHash = str(self.milliseconds())
|
1688
1700
|
request: dict = {
|
1689
1701
|
'id': messageHash,
|
1690
1702
|
'op': 'mass-cancel',
|
@@ -1728,7 +1740,7 @@ class okx(ccxt.async_support.okx):
|
|
1728
1740
|
future = self.safe_value(client.futures, 'authenticated')
|
1729
1741
|
future.resolve(True)
|
1730
1742
|
|
1731
|
-
def ping(self, client):
|
1743
|
+
def ping(self, client: Client):
|
1732
1744
|
# OKX does not support the built-in WebSocket protocol-level ping-pong.
|
1733
1745
|
# Instead, it requires a custom text-based ping-pong mechanism.
|
1734
1746
|
return 'ping'
|
ccxt/pro/oxfun.py
CHANGED
@@ -914,7 +914,7 @@ class oxfun(ccxt.async_support.oxfun):
|
|
914
914
|
if messageHash in client.subscriptions:
|
915
915
|
del client.subscriptions[messageHash]
|
916
916
|
|
917
|
-
def ping(self, client):
|
917
|
+
def ping(self, client: Client):
|
918
918
|
return 'ping'
|
919
919
|
|
920
920
|
def handle_pong(self, client: Client, message):
|
ccxt/pro/p2b.py
CHANGED
@@ -388,7 +388,7 @@ class p2b(ccxt.async_support.p2b):
|
|
388
388
|
raise ExchangeError(self.id + ' error: ' + self.json(error))
|
389
389
|
return False
|
390
390
|
|
391
|
-
def ping(self, client):
|
391
|
+
def ping(self, client: Client):
|
392
392
|
"""
|
393
393
|
:see: https://github.com/P2B-team/P2B-WSS-Public/blob/main/wss_documentation.md#ping
|
394
394
|
* @param client
|
ccxt/pro/poloniex.py
CHANGED
ccxt/pro/whitebit.py
CHANGED
ccxt/test/tests_async.py
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
import asyncio
|
4
4
|
|
5
5
|
|
6
|
-
from tests_helpers import
|
6
|
+
from tests_helpers import AuthenticationError, NotSupported, InvalidProxySettings, ExchangeNotAvailable, OperationFailed, OnMaintenance, get_cli_arg_value, baseMainTestClass, dump, json_parse, json_stringify, convert_ascii, io_file_exists, io_file_read, io_dir_read, call_method, call_method_sync, call_exchange_method_dynamically, call_exchange_method_dynamically_sync, exception_message, exit_script, get_exchange_prop, set_exchange_prop, init_exchange, get_test_files_sync, get_test_files, set_fetch_response, is_null_value, close # noqa: F401
|
7
7
|
|
8
8
|
class testMainClass(baseMainTestClass):
|
9
9
|
def parse_cli_args(self):
|
@@ -72,7 +72,10 @@ class testMainClass(baseMainTestClass):
|
|
72
72
|
async def import_files(self, exchange):
|
73
73
|
properties = list(exchange.has.keys())
|
74
74
|
properties.append('loadMarkets')
|
75
|
-
|
75
|
+
if self.is_synchronous:
|
76
|
+
self.test_files = get_test_files_sync(properties, self.ws_tests)
|
77
|
+
else:
|
78
|
+
self.test_files = await get_test_files(properties, self.ws_tests)
|
76
79
|
|
77
80
|
def load_credentials_from_env(self, exchange):
|
78
81
|
exchange_id = exchange.id
|
@@ -192,7 +195,10 @@ class testMainClass(baseMainTestClass):
|
|
192
195
|
if self.info:
|
193
196
|
args_stringified = '(' + exchange.json(args) + ')' # args.join() breaks when we provide a list of symbols or multidimensional array; "args.toString()" breaks bcz of "array to string conversion"
|
194
197
|
dump(self.add_padding('[INFO] TESTING', 25), self.exchange_hint(exchange), method_name, args_stringified)
|
195
|
-
|
198
|
+
if self.is_synchronous:
|
199
|
+
call_method_sync(self.test_files, method_name, exchange, skipped_properties_for_method, args)
|
200
|
+
else:
|
201
|
+
await call_method(self.test_files, method_name, exchange, skipped_properties_for_method, args)
|
196
202
|
if self.info:
|
197
203
|
dump(self.add_padding('[INFO] TESTING DONE', 25), self.exchange_hint(exchange), method_name)
|
198
204
|
# add to the list of successed tests
|
@@ -587,7 +593,7 @@ class testMainClass(baseMainTestClass):
|
|
587
593
|
if exception is not None:
|
588
594
|
error_message = '[TEST_FAILURE] Failed ' + proxy_test_name + ' : ' + exception_message(exception)
|
589
595
|
# temporary comment the below, because c# transpilation failure
|
590
|
-
# throw new
|
596
|
+
# throw new Exchange Error (errorMessage.toString ());
|
591
597
|
dump('[TEST_WARNING]' + str(error_message))
|
592
598
|
|
593
599
|
async def start_test(self, exchange, symbol):
|
@@ -599,16 +605,19 @@ class testMainClass(baseMainTestClass):
|
|
599
605
|
try:
|
600
606
|
result = await self.load_exchange(exchange)
|
601
607
|
if not result:
|
602
|
-
|
608
|
+
if not self.is_synchronous:
|
609
|
+
await close(exchange)
|
603
610
|
return
|
604
611
|
# if (exchange.id === 'binance') {
|
605
612
|
# # we test proxies functionality just for one random exchange on each build, because proxy functionality is not exchange-specific, instead it's all done from base methods, so just one working sample would mean it works for all ccxt exchanges
|
606
613
|
# # await this.testProxies (exchange);
|
607
614
|
# }
|
608
615
|
await self.test_exchange(exchange, symbol)
|
609
|
-
|
616
|
+
if not self.is_synchronous:
|
617
|
+
await close(exchange)
|
610
618
|
except Exception as e:
|
611
|
-
|
619
|
+
if not self.is_synchronous:
|
620
|
+
await close(exchange)
|
612
621
|
raise e
|
613
622
|
|
614
623
|
def assert_static_error(self, cond, message, calculated_output, stored_output, key=None):
|
@@ -1076,7 +1085,8 @@ class testMainClass(baseMainTestClass):
|
|
1076
1085
|
assert client_order_id_swap.startswith(swap_id_string), 'binance - swap clientOrderId: ' + client_order_id_swap + ' does not start with swapId' + swap_id_string
|
1077
1086
|
client_order_id_inverse = swap_inverse_order_request['newClientOrderId']
|
1078
1087
|
assert client_order_id_inverse.startswith(swap_id_string), 'binance - swap clientOrderIdInverse: ' + client_order_id_inverse + ' does not start with swapId' + swap_id_string
|
1079
|
-
|
1088
|
+
if not self.is_synchronous:
|
1089
|
+
await close(exchange)
|
1080
1090
|
return True
|
1081
1091
|
|
1082
1092
|
async def test_okx(self):
|
@@ -1101,7 +1111,8 @@ class testMainClass(baseMainTestClass):
|
|
1101
1111
|
assert client_order_id_swap.startswith(id_string), 'okx - swap clientOrderId: ' + client_order_id_swap + ' does not start with id: ' + id_string
|
1102
1112
|
swap_tag = swap_order_request[0]['tag']
|
1103
1113
|
assert swap_tag == id, 'okx - id: ' + id + ' different from swap tag: ' + swap_tag
|
1104
|
-
|
1114
|
+
if not self.is_synchronous:
|
1115
|
+
await close(exchange)
|
1105
1116
|
return True
|
1106
1117
|
|
1107
1118
|
async def test_cryptocom(self):
|
@@ -1115,7 +1126,8 @@ class testMainClass(baseMainTestClass):
|
|
1115
1126
|
request = json_parse(exchange.last_request_body)
|
1116
1127
|
broker_id = request['params']['broker_id']
|
1117
1128
|
assert broker_id == id, 'cryptocom - id: ' + id + ' different from broker_id: ' + broker_id
|
1118
|
-
|
1129
|
+
if not self.is_synchronous:
|
1130
|
+
await close(exchange)
|
1119
1131
|
return True
|
1120
1132
|
|
1121
1133
|
async def test_bybit(self):
|
@@ -1129,7 +1141,8 @@ class testMainClass(baseMainTestClass):
|
|
1129
1141
|
# we expect an error here, we're only interested in the headers
|
1130
1142
|
req_headers = exchange.last_request_headers
|
1131
1143
|
assert req_headers['Referer'] == id, 'bybit - id: ' + id + ' not in headers.'
|
1132
|
-
|
1144
|
+
if not self.is_synchronous:
|
1145
|
+
await close(exchange)
|
1133
1146
|
return True
|
1134
1147
|
|
1135
1148
|
async def test_kucoin(self):
|
@@ -1146,7 +1159,8 @@ class testMainClass(baseMainTestClass):
|
|
1146
1159
|
req_headers = exchange.last_request_headers
|
1147
1160
|
id = 'ccxt'
|
1148
1161
|
assert req_headers['KC-API-PARTNER'] == id, 'kucoin - id: ' + id + ' not in headers.'
|
1149
|
-
|
1162
|
+
if not self.is_synchronous:
|
1163
|
+
await close(exchange)
|
1150
1164
|
return True
|
1151
1165
|
|
1152
1166
|
async def test_kucoinfutures(self):
|
@@ -1162,7 +1176,8 @@ class testMainClass(baseMainTestClass):
|
|
1162
1176
|
except Exception as e:
|
1163
1177
|
req_headers = exchange.last_request_headers
|
1164
1178
|
assert req_headers['KC-API-PARTNER'] == id, 'kucoinfutures - id: ' + id + ' not in headers.'
|
1165
|
-
|
1179
|
+
if not self.is_synchronous:
|
1180
|
+
await close(exchange)
|
1166
1181
|
return True
|
1167
1182
|
|
1168
1183
|
async def test_bitget(self):
|
@@ -1175,7 +1190,8 @@ class testMainClass(baseMainTestClass):
|
|
1175
1190
|
except Exception as e:
|
1176
1191
|
req_headers = exchange.last_request_headers
|
1177
1192
|
assert req_headers['X-CHANNEL-API-CODE'] == id, 'bitget - id: ' + id + ' not in headers.'
|
1178
|
-
|
1193
|
+
if not self.is_synchronous:
|
1194
|
+
await close(exchange)
|
1179
1195
|
return True
|
1180
1196
|
|
1181
1197
|
async def test_mexc(self):
|
@@ -1189,7 +1205,8 @@ class testMainClass(baseMainTestClass):
|
|
1189
1205
|
except Exception as e:
|
1190
1206
|
req_headers = exchange.last_request_headers
|
1191
1207
|
assert req_headers['source'] == id, 'mexc - id: ' + id + ' not in headers.'
|
1192
|
-
|
1208
|
+
if not self.is_synchronous:
|
1209
|
+
await close(exchange)
|
1193
1210
|
return True
|
1194
1211
|
|
1195
1212
|
async def test_htx(self):
|
@@ -1219,7 +1236,8 @@ class testMainClass(baseMainTestClass):
|
|
1219
1236
|
assert client_order_id_swap.startswith(id_string), 'htx - swap channel_code ' + client_order_id_swap + ' does not start with id: ' + id_string
|
1220
1237
|
client_order_id_inverse = swap_inverse_order_request['channel_code']
|
1221
1238
|
assert client_order_id_inverse.startswith(id_string), 'htx - swap inverse channel_code ' + client_order_id_inverse + ' does not start with id: ' + id_string
|
1222
|
-
|
1239
|
+
if not self.is_synchronous:
|
1240
|
+
await close(exchange)
|
1223
1241
|
return True
|
1224
1242
|
|
1225
1243
|
async def test_woo(self):
|
@@ -1244,7 +1262,8 @@ class testMainClass(baseMainTestClass):
|
|
1244
1262
|
stop_order_request = json_parse(exchange.last_request_body)
|
1245
1263
|
client_order_id_stop = stop_order_request['brokerId']
|
1246
1264
|
assert client_order_id_stop.startswith(id_string), 'woo - brokerId: ' + client_order_id_stop + ' does not start with id: ' + id_string
|
1247
|
-
|
1265
|
+
if not self.is_synchronous:
|
1266
|
+
await close(exchange)
|
1248
1267
|
return True
|
1249
1268
|
|
1250
1269
|
async def test_bitmart(self):
|
@@ -1258,7 +1277,8 @@ class testMainClass(baseMainTestClass):
|
|
1258
1277
|
except Exception as e:
|
1259
1278
|
req_headers = exchange.last_request_headers
|
1260
1279
|
assert req_headers['X-BM-BROKER-ID'] == id, 'bitmart - id: ' + id + ' not in headers'
|
1261
|
-
|
1280
|
+
if not self.is_synchronous:
|
1281
|
+
await close(exchange)
|
1262
1282
|
return True
|
1263
1283
|
|
1264
1284
|
async def test_coinex(self):
|
@@ -1273,7 +1293,8 @@ class testMainClass(baseMainTestClass):
|
|
1273
1293
|
client_order_id = spot_order_request['client_id']
|
1274
1294
|
id_string = str(id)
|
1275
1295
|
assert client_order_id.startswith(id_string), 'coinex - clientOrderId: ' + client_order_id + ' does not start with id: ' + id_string
|
1276
|
-
|
1296
|
+
if not self.is_synchronous:
|
1297
|
+
await close(exchange)
|
1277
1298
|
return True
|
1278
1299
|
|
1279
1300
|
async def test_bingx(self):
|
@@ -1287,7 +1308,8 @@ class testMainClass(baseMainTestClass):
|
|
1287
1308
|
# we expect an error here, we're only interested in the headers
|
1288
1309
|
req_headers = exchange.last_request_headers
|
1289
1310
|
assert req_headers['X-SOURCE-KEY'] == id, 'bingx - id: ' + id + ' not in headers.'
|
1290
|
-
|
1311
|
+
if not self.is_synchronous:
|
1312
|
+
await close(exchange)
|
1291
1313
|
|
1292
1314
|
async def test_phemex(self):
|
1293
1315
|
exchange = self.init_offline_exchange('phemex')
|
@@ -1300,7 +1322,8 @@ class testMainClass(baseMainTestClass):
|
|
1300
1322
|
client_order_id = request['clOrdID']
|
1301
1323
|
id_string = str(id)
|
1302
1324
|
assert client_order_id.startswith(id_string), 'phemex - clOrdID: ' + client_order_id + ' does not start with id: ' + id_string
|
1303
|
-
|
1325
|
+
if not self.is_synchronous:
|
1326
|
+
await close(exchange)
|
1304
1327
|
|
1305
1328
|
async def test_blofin(self):
|
1306
1329
|
exchange = self.init_offline_exchange('blofin')
|
@@ -1313,7 +1336,8 @@ class testMainClass(baseMainTestClass):
|
|
1313
1336
|
broker_id = request['brokerId']
|
1314
1337
|
id_string = str(id)
|
1315
1338
|
assert broker_id.startswith(id_string), 'blofin - brokerId: ' + broker_id + ' does not start with id: ' + id_string
|
1316
|
-
|
1339
|
+
if not self.is_synchronous:
|
1340
|
+
await close(exchange)
|
1317
1341
|
|
1318
1342
|
async def test_hyperliquid(self):
|
1319
1343
|
exchange = self.init_offline_exchange('hyperliquid')
|
@@ -1325,7 +1349,8 @@ class testMainClass(baseMainTestClass):
|
|
1325
1349
|
request = json_parse(exchange.last_request_body)
|
1326
1350
|
broker_id = str((request['action']['brokerCode']))
|
1327
1351
|
assert broker_id == id, 'hyperliquid - brokerId: ' + broker_id + ' does not start with id: ' + id
|
1328
|
-
|
1352
|
+
if not self.is_synchronous:
|
1353
|
+
await close(exchange)
|
1329
1354
|
|
1330
1355
|
async def test_coinbaseinternational(self):
|
1331
1356
|
exchange = self.init_offline_exchange('coinbaseinternational')
|
@@ -1339,7 +1364,8 @@ class testMainClass(baseMainTestClass):
|
|
1339
1364
|
request = json_parse(exchange.last_request_body)
|
1340
1365
|
client_order_id = request['client_order_id']
|
1341
1366
|
assert client_order_id.startswith(str(id)), 'clientOrderId does not start with id'
|
1342
|
-
|
1367
|
+
if not self.is_synchronous:
|
1368
|
+
await close(exchange)
|
1343
1369
|
return True
|
1344
1370
|
|
1345
1371
|
async def test_coinbase_advanced(self):
|
@@ -1353,7 +1379,8 @@ class testMainClass(baseMainTestClass):
|
|
1353
1379
|
request = json_parse(exchange.last_request_body)
|
1354
1380
|
client_order_id = request['client_order_id']
|
1355
1381
|
assert client_order_id.startswith(str(id)), 'clientOrderId does not start with id'
|
1356
|
-
|
1382
|
+
if not self.is_synchronous:
|
1383
|
+
await close(exchange)
|
1357
1384
|
return True
|
1358
1385
|
|
1359
1386
|
async def test_woofi_pro(self):
|
@@ -1368,7 +1395,8 @@ class testMainClass(baseMainTestClass):
|
|
1368
1395
|
request = json_parse(exchange.last_request_body)
|
1369
1396
|
broker_id = request['order_tag']
|
1370
1397
|
assert broker_id == id, 'woofipro - id: ' + id + ' different from broker_id: ' + broker_id
|
1371
|
-
|
1398
|
+
if not self.is_synchronous:
|
1399
|
+
await close(exchange)
|
1372
1400
|
return True
|
1373
1401
|
|
1374
1402
|
async def test_oxfun(self):
|
@@ -1404,7 +1432,8 @@ class testMainClass(baseMainTestClass):
|
|
1404
1432
|
swap_order_request = json_parse(exchange.last_request_body)
|
1405
1433
|
swap_media = swap_order_request['clientMedia']
|
1406
1434
|
assert swap_media == id, 'xt - id: ' + id + ' different from swap tag: ' + swap_media
|
1407
|
-
|
1435
|
+
if not self.is_synchronous:
|
1436
|
+
await close(exchange)
|
1408
1437
|
return True
|
1409
1438
|
|
1410
1439
|
async def test_vertex(self):
|
@@ -1426,5 +1455,6 @@ class testMainClass(baseMainTestClass):
|
|
1426
1455
|
order = request['place_order']
|
1427
1456
|
broker_id = order['id']
|
1428
1457
|
assert broker_id == id, 'vertex - id: ' + str(id) + ' different from broker_id: ' + str(broker_id)
|
1429
|
-
|
1458
|
+
if not self.is_synchronous:
|
1459
|
+
await close(exchange)
|
1430
1460
|
return True
|
ccxt/test/tests_helpers.py
CHANGED
@@ -191,6 +191,10 @@ def io_dir_read(path):
|
|
191
191
|
return os.listdir(path)
|
192
192
|
|
193
193
|
|
194
|
+
def call_method_sync(test_files, methodName, exchange, skippedProperties, args):
|
195
|
+
methodNameToCall = 'test_' + convert_to_snake_case(methodName)
|
196
|
+
return getattr(test_files[methodName], methodNameToCall)(exchange, skippedProperties, *args)
|
197
|
+
|
194
198
|
async def call_method(test_files, methodName, exchange, skippedProperties, args):
|
195
199
|
methodNameToCall = 'test_' + convert_to_snake_case(methodName)
|
196
200
|
return await getattr(test_files[methodName], methodNameToCall)(exchange, skippedProperties, *args)
|
@@ -240,7 +244,7 @@ def init_exchange(exchangeId, args, is_ws=False):
|
|
240
244
|
return getattr(ccxt, exchangeId)(args)
|
241
245
|
|
242
246
|
|
243
|
-
|
247
|
+
def get_test_files_sync(properties, ws=False):
|
244
248
|
tests = {}
|
245
249
|
finalPropList = properties + [proxyTestFileName]
|
246
250
|
for i in range(0, len(finalPropList)):
|
@@ -259,6 +263,9 @@ async def get_test_files(properties, ws=False):
|
|
259
263
|
tests[methodName] = imp # getattr(imp, finalName)
|
260
264
|
return tests
|
261
265
|
|
266
|
+
async def get_test_files(properties, ws=False):
|
267
|
+
return get_test_files_sync(properties, ws)
|
268
|
+
|
262
269
|
async def close(exchange):
|
263
270
|
if (not is_synchronous and hasattr(exchange, 'close')):
|
264
271
|
await exchange.close()
|