ccxt 4.4.12__py2.py3-none-any.whl → 4.4.14__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/binance.py +1 -0
- ccxt/abstract/binancecoinm.py +1 -0
- ccxt/abstract/binanceus.py +1 -0
- ccxt/abstract/binanceusdm.py +1 -0
- ccxt/abstract/cryptocom.py +1 -0
- ccxt/async_support/__init__.py +1 -1
- ccxt/async_support/base/exchange.py +37 -1
- ccxt/async_support/bigone.py +2 -0
- ccxt/async_support/binance.py +113 -12
- ccxt/async_support/bingx.py +69 -3
- ccxt/async_support/bitget.py +102 -3
- ccxt/async_support/bitmex.py +1 -0
- ccxt/async_support/bitrue.py +1 -7
- ccxt/async_support/bitvavo.py +1 -3
- ccxt/async_support/bybit.py +2 -0
- ccxt/async_support/coinbaseinternational.py +2 -0
- ccxt/async_support/coinex.py +15 -1
- ccxt/async_support/cryptocom.py +1 -0
- ccxt/async_support/delta.py +2 -0
- ccxt/async_support/deribit.py +2 -0
- ccxt/async_support/digifinex.py +15 -1
- ccxt/async_support/gate.py +2 -0
- ccxt/async_support/htx.py +2 -2
- ccxt/async_support/huobijp.py +1 -3
- ccxt/async_support/krakenfutures.py +2 -0
- ccxt/async_support/kucoin.py +36 -1
- ccxt/async_support/kucoinfutures.py +56 -3
- ccxt/async_support/mexc.py +52 -8
- ccxt/async_support/okx.py +48 -0
- ccxt/async_support/oxfun.py +1 -0
- ccxt/async_support/paradex.py +1 -0
- ccxt/async_support/poloniex.py +1 -0
- ccxt/async_support/poloniexfutures.py +35 -11
- ccxt/async_support/woo.py +12 -0
- ccxt/async_support/woofipro.py +12 -0
- ccxt/async_support/xt.py +12 -0
- ccxt/base/exchange.py +44 -2
- ccxt/base/types.py +2 -0
- ccxt/bigone.py +2 -0
- ccxt/binance.py +113 -12
- ccxt/bingx.py +69 -3
- ccxt/bitget.py +102 -3
- ccxt/bitmex.py +1 -0
- ccxt/bitrue.py +1 -7
- ccxt/bitvavo.py +1 -3
- ccxt/bybit.py +2 -0
- ccxt/coinbaseinternational.py +2 -0
- ccxt/coinex.py +15 -1
- ccxt/cryptocom.py +1 -0
- ccxt/delta.py +2 -0
- ccxt/deribit.py +2 -0
- ccxt/digifinex.py +15 -1
- ccxt/gate.py +2 -0
- ccxt/htx.py +2 -2
- ccxt/huobijp.py +1 -3
- ccxt/krakenfutures.py +2 -0
- ccxt/kucoin.py +36 -1
- ccxt/kucoinfutures.py +56 -3
- ccxt/mexc.py +52 -8
- ccxt/okx.py +48 -0
- ccxt/oxfun.py +1 -0
- ccxt/paradex.py +1 -0
- ccxt/poloniex.py +1 -0
- ccxt/poloniexfutures.py +35 -11
- ccxt/pro/__init__.py +1 -1
- ccxt/pro/binance.py +72 -5
- ccxt/pro/bitfinex.py +8 -8
- ccxt/pro/krakenfutures.py +2 -0
- ccxt/pro/okx.py +38 -0
- ccxt/pro/phemex.py +2 -0
- ccxt/pro/woo.py +69 -0
- ccxt/test/tests_async.py +76 -48
- ccxt/test/tests_helpers.py +27 -36
- ccxt/test/tests_init.py +6 -2
- ccxt/test/tests_sync.py +76 -48
- ccxt/woo.py +12 -0
- ccxt/woofipro.py +12 -0
- ccxt/xt.py +12 -0
- {ccxt-4.4.12.dist-info → ccxt-4.4.14.dist-info}/METADATA +4 -5
- {ccxt-4.4.12.dist-info → ccxt-4.4.14.dist-info}/RECORD +84 -84
- {ccxt-4.4.12.dist-info → ccxt-4.4.14.dist-info}/LICENSE.txt +0 -0
- {ccxt-4.4.12.dist-info → ccxt-4.4.14.dist-info}/WHEEL +0 -0
- {ccxt-4.4.12.dist-info → ccxt-4.4.14.dist-info}/top_level.txt +0 -0
ccxt/pro/woo.py
CHANGED
@@ -27,6 +27,7 @@ class woo(ccxt.async_support.woo):
|
|
27
27
|
'watchOrders': True,
|
28
28
|
'watchTicker': True,
|
29
29
|
'watchTickers': True,
|
30
|
+
'watchBidsAsks': True,
|
30
31
|
'watchTrades': True,
|
31
32
|
'watchTradesForSymbols': False,
|
32
33
|
'watchPositions': True,
|
@@ -383,6 +384,73 @@ class woo(ccxt.async_support.woo):
|
|
383
384
|
result.append(ticker)
|
384
385
|
client.resolve(result, topic)
|
385
386
|
|
387
|
+
async def watch_bids_asks(self, symbols: Strings = None, params={}) -> Tickers:
|
388
|
+
"""
|
389
|
+
:see: https://docs.woox.io/#bbos
|
390
|
+
watches best bid & ask for symbols
|
391
|
+
:param str[] symbols: unified symbol of the market to fetch the ticker for
|
392
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
393
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
394
|
+
"""
|
395
|
+
await self.load_markets()
|
396
|
+
symbols = self.market_symbols(symbols, None, False)
|
397
|
+
name = 'bbos'
|
398
|
+
topic = name
|
399
|
+
request: dict = {
|
400
|
+
'event': 'subscribe',
|
401
|
+
'topic': topic,
|
402
|
+
}
|
403
|
+
message = self.extend(request, params)
|
404
|
+
tickers = await self.watch_public(topic, message)
|
405
|
+
if self.newUpdates:
|
406
|
+
return tickers
|
407
|
+
return self.filter_by_array(self.bidsasks, 'symbol', symbols)
|
408
|
+
|
409
|
+
def handle_bid_ask(self, client: Client, message):
|
410
|
+
#
|
411
|
+
# {
|
412
|
+
# "topic": "bbos",
|
413
|
+
# "ts": 1618822376000,
|
414
|
+
# "data": [
|
415
|
+
# {
|
416
|
+
# "symbol": "SPOT_FIL_USDT",
|
417
|
+
# "ask": 159.0318,
|
418
|
+
# "askSize": 370.43,
|
419
|
+
# "bid": 158.9158,
|
420
|
+
# "bidSize": 16
|
421
|
+
# }
|
422
|
+
# ]
|
423
|
+
# }
|
424
|
+
#
|
425
|
+
topic = self.safe_string(message, 'topic')
|
426
|
+
data = self.safe_list(message, 'data', [])
|
427
|
+
timestamp = self.safe_integer(message, 'ts')
|
428
|
+
result: dict = {}
|
429
|
+
for i in range(0, len(data)):
|
430
|
+
ticker = self.safe_dict(data, i)
|
431
|
+
ticker['ts'] = timestamp
|
432
|
+
parsedTicker = self.parse_ws_bid_ask(ticker)
|
433
|
+
symbol = parsedTicker['symbol']
|
434
|
+
self.bidsasks[symbol] = parsedTicker
|
435
|
+
result[symbol] = parsedTicker
|
436
|
+
client.resolve(result, topic)
|
437
|
+
|
438
|
+
def parse_ws_bid_ask(self, ticker, market=None):
|
439
|
+
marketId = self.safe_string(ticker, 'symbol')
|
440
|
+
market = self.safe_market(marketId, market)
|
441
|
+
symbol = self.safe_string(market, 'symbol')
|
442
|
+
timestamp = self.safe_integer(ticker, 'ts')
|
443
|
+
return self.safe_ticker({
|
444
|
+
'symbol': symbol,
|
445
|
+
'timestamp': timestamp,
|
446
|
+
'datetime': self.iso8601(timestamp),
|
447
|
+
'ask': self.safe_string(ticker, 'ask'),
|
448
|
+
'askVolume': self.safe_string(ticker, 'askSize'),
|
449
|
+
'bid': self.safe_string(ticker, 'bid'),
|
450
|
+
'bidVolume': self.safe_string(ticker, 'bidSize'),
|
451
|
+
'info': ticker,
|
452
|
+
}, market)
|
453
|
+
|
386
454
|
async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
|
387
455
|
"""
|
388
456
|
watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
@@ -1101,6 +1169,7 @@ class woo(ccxt.async_support.woo):
|
|
1101
1169
|
'trade': self.handle_trade,
|
1102
1170
|
'balance': self.handle_balance,
|
1103
1171
|
'position': self.handle_positions,
|
1172
|
+
'bbos': self.handle_bid_ask,
|
1104
1173
|
}
|
1105
1174
|
event = self.safe_string(message, 'event')
|
1106
1175
|
method = self.safe_value(methods, event)
|
ccxt/test/tests_async.py
CHANGED
@@ -3,10 +3,34 @@
|
|
3
3
|
import asyncio
|
4
4
|
|
5
5
|
|
6
|
-
from tests_helpers import AuthenticationError, NotSupported, InvalidProxySettings, ExchangeNotAvailable, OperationFailed, OnMaintenance, get_cli_arg_value,
|
7
|
-
|
8
|
-
class testMainClass
|
9
|
-
|
6
|
+
from tests_helpers import AuthenticationError, NotSupported, InvalidProxySettings, ExchangeNotAvailable, OperationFailed, OnMaintenance, get_cli_arg_value, get_root_dir, is_sync, 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, get_root_exception, 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, get_env_vars, get_lang, get_ext # noqa: F401
|
7
|
+
|
8
|
+
class testMainClass:
|
9
|
+
id_tests = False
|
10
|
+
request_tests_failed = False
|
11
|
+
response_tests_failed = False
|
12
|
+
request_tests = False
|
13
|
+
ws_tests = False
|
14
|
+
response_tests = False
|
15
|
+
static_tests = False
|
16
|
+
info = False
|
17
|
+
verbose = False
|
18
|
+
debug = False
|
19
|
+
private_test = False
|
20
|
+
private_test_only = False
|
21
|
+
load_keys = False
|
22
|
+
sandbox = False
|
23
|
+
only_specific_tests = []
|
24
|
+
skipped_settings_for_exchange = {}
|
25
|
+
skipped_methods = {}
|
26
|
+
checked_public_tests = {}
|
27
|
+
test_files = {}
|
28
|
+
public_tests = {}
|
29
|
+
ext = ''
|
30
|
+
lang = ''
|
31
|
+
proxy_test_file_name = 'proxies'
|
32
|
+
|
33
|
+
def parse_cli_args_and_props(self):
|
10
34
|
self.response_tests = get_cli_arg_value('--responseTests')
|
11
35
|
self.id_tests = get_cli_arg_value('--idTests')
|
12
36
|
self.request_tests = get_cli_arg_value('--requestTests')
|
@@ -18,9 +42,11 @@ class testMainClass(baseMainTestClass):
|
|
18
42
|
self.sandbox = get_cli_arg_value('--sandbox')
|
19
43
|
self.load_keys = get_cli_arg_value('--loadKeys')
|
20
44
|
self.ws_tests = get_cli_arg_value('--ws')
|
45
|
+
self.lang = get_lang()
|
46
|
+
self.ext = get_ext()
|
21
47
|
|
22
48
|
async def init(self, exchange_id, symbol_argv, method_argv):
|
23
|
-
self.
|
49
|
+
self.parse_cli_args_and_props()
|
24
50
|
if self.request_tests and self.response_tests:
|
25
51
|
await self.run_static_request_tests(exchange_id, symbol_argv)
|
26
52
|
await self.run_static_response_tests(exchange_id, symbol_argv)
|
@@ -34,12 +60,13 @@ class testMainClass(baseMainTestClass):
|
|
34
60
|
if self.id_tests:
|
35
61
|
await self.run_broker_id_tests()
|
36
62
|
return
|
37
|
-
|
63
|
+
new_line = '\n'
|
64
|
+
dump(new_line + '' + new_line + '' + '[INFO] TESTING ', self.ext, {
|
38
65
|
'exchange': exchange_id,
|
39
66
|
'symbol': symbol_argv,
|
40
67
|
'method': method_argv,
|
41
68
|
'isWs': self.ws_tests,
|
42
|
-
},
|
69
|
+
}, new_line)
|
43
70
|
exchange_args = {
|
44
71
|
'verbose': self.verbose,
|
45
72
|
'debug': self.debug,
|
@@ -72,7 +99,7 @@ class testMainClass(baseMainTestClass):
|
|
72
99
|
async def import_files(self, exchange):
|
73
100
|
properties = list(exchange.has.keys())
|
74
101
|
properties.append('loadMarkets')
|
75
|
-
if
|
102
|
+
if is_sync():
|
76
103
|
self.test_files = get_test_files_sync(properties, self.ws_tests)
|
77
104
|
else:
|
78
105
|
self.test_files = await get_test_files(properties, self.ws_tests)
|
@@ -87,14 +114,15 @@ class testMainClass(baseMainTestClass):
|
|
87
114
|
if is_required and get_exchange_prop(exchange, credential) is None:
|
88
115
|
full_key = exchange_id + '_' + credential
|
89
116
|
credential_env_name = full_key.upper() # example: KRAKEN_APIKEY
|
90
|
-
|
117
|
+
env_vars = get_env_vars()
|
118
|
+
credential_value = env_vars[credential_env_name] if (credential_env_name in env_vars) else None
|
91
119
|
if credential_value:
|
92
120
|
set_exchange_prop(exchange, credential, credential_value)
|
93
121
|
|
94
122
|
def expand_settings(self, exchange):
|
95
123
|
exchange_id = exchange.id
|
96
|
-
keys_global =
|
97
|
-
keys_local =
|
124
|
+
keys_global = get_root_dir() + 'keys.json'
|
125
|
+
keys_local = get_root_dir() + 'keys.local.json'
|
98
126
|
keys_global_exists = io_file_exists(keys_global)
|
99
127
|
keys_local_exists = io_file_exists(keys_local)
|
100
128
|
global_settings = io_file_read(keys_global) if keys_global_exists else {}
|
@@ -117,7 +145,7 @@ class testMainClass(baseMainTestClass):
|
|
117
145
|
if self.load_keys:
|
118
146
|
self.load_credentials_from_env(exchange)
|
119
147
|
# skipped tests
|
120
|
-
skipped_file =
|
148
|
+
skipped_file = get_root_dir() + 'skip-tests.json'
|
121
149
|
skipped_settings = io_file_read(skipped_file)
|
122
150
|
self.skipped_settings_for_exchange = exchange.safe_value(skipped_settings, exchange_id, {})
|
123
151
|
skipped_settings_for_exchange = self.skipped_settings_for_exchange
|
@@ -178,7 +206,7 @@ class testMainClass(baseMainTestClass):
|
|
178
206
|
if self.info:
|
179
207
|
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"
|
180
208
|
dump(self.add_padding('[INFO] TESTING', 25), name, method_name, args_stringified)
|
181
|
-
if
|
209
|
+
if is_sync():
|
182
210
|
call_method_sync(self.test_files, method_name, exchange, skipped_properties_for_method, args)
|
183
211
|
else:
|
184
212
|
await call_method(self.test_files, method_name, exchange, skipped_properties_for_method, args)
|
@@ -561,7 +589,7 @@ class testMainClass(baseMainTestClass):
|
|
561
589
|
# these tests should be synchronously executed, because of conflicting nature of proxy settings
|
562
590
|
proxy_test_name = self.proxy_test_file_name
|
563
591
|
# todo: temporary skip for sync py
|
564
|
-
if self.ext == 'py' and
|
592
|
+
if self.ext == 'py' and is_sync():
|
565
593
|
return
|
566
594
|
# try proxy several times
|
567
595
|
max_retries = 3
|
@@ -589,7 +617,7 @@ class testMainClass(baseMainTestClass):
|
|
589
617
|
try:
|
590
618
|
result = await self.load_exchange(exchange)
|
591
619
|
if not result:
|
592
|
-
if not
|
620
|
+
if not is_sync():
|
593
621
|
await close(exchange)
|
594
622
|
return
|
595
623
|
# if (exchange.id === 'binance') {
|
@@ -597,10 +625,10 @@ class testMainClass(baseMainTestClass):
|
|
597
625
|
# # await this.testProxies (exchange);
|
598
626
|
# }
|
599
627
|
await self.test_exchange(exchange, symbol)
|
600
|
-
if not
|
628
|
+
if not is_sync():
|
601
629
|
await close(exchange)
|
602
630
|
except Exception as e:
|
603
|
-
if not
|
631
|
+
if not is_sync():
|
604
632
|
await close(exchange)
|
605
633
|
raise e
|
606
634
|
|
@@ -620,12 +648,12 @@ class testMainClass(baseMainTestClass):
|
|
620
648
|
# to make this test as fast as possible
|
621
649
|
# and basically independent from the exchange
|
622
650
|
# so we can run it offline
|
623
|
-
filename =
|
651
|
+
filename = get_root_dir() + './ts/src/test/static/markets/' + id + '.json'
|
624
652
|
content = io_file_read(filename)
|
625
653
|
return content
|
626
654
|
|
627
655
|
def load_currencies_from_file(self, id):
|
628
|
-
filename =
|
656
|
+
filename = get_root_dir() + './ts/src/test/static/currencies/' + id + '.json'
|
629
657
|
content = io_file_read(filename)
|
630
658
|
return content
|
631
659
|
|
@@ -815,7 +843,7 @@ class testMainClass(baseMainTestClass):
|
|
815
843
|
output = None
|
816
844
|
request_url = None
|
817
845
|
try:
|
818
|
-
if not
|
846
|
+
if not is_sync():
|
819
847
|
await call_exchange_method_dynamically(exchange, method, self.sanitize_data_input(data['input']))
|
820
848
|
else:
|
821
849
|
call_exchange_method_dynamically_sync(exchange, method, self.sanitize_data_input(data['input']))
|
@@ -836,7 +864,7 @@ class testMainClass(baseMainTestClass):
|
|
836
864
|
expected_result = exchange.safe_value(data, 'parsedResponse')
|
837
865
|
mocked_exchange = set_fetch_response(exchange, data['httpResponse'])
|
838
866
|
try:
|
839
|
-
if not
|
867
|
+
if not is_sync():
|
840
868
|
unified_result = await call_exchange_method_dynamically(exchange, method, self.sanitize_data_input(data['input']))
|
841
869
|
self.assert_static_response_output(mocked_exchange, skip_keys, unified_result, expected_result)
|
842
870
|
else:
|
@@ -932,7 +960,7 @@ class testMainClass(baseMainTestClass):
|
|
932
960
|
# reset options
|
933
961
|
# exchange.options = exchange.deepExtend (oldExchangeOptions, {});
|
934
962
|
exchange.extend_exchange_options(exchange.deep_extend(old_exchange_options, {}))
|
935
|
-
if not
|
963
|
+
if not is_sync():
|
936
964
|
await close(exchange)
|
937
965
|
return True # in c# methods that will be used with promiseAll need to return something
|
938
966
|
|
@@ -982,7 +1010,7 @@ class testMainClass(baseMainTestClass):
|
|
982
1010
|
# reset options
|
983
1011
|
# exchange.options = exchange.deepExtend (oldExchangeOptions, {});
|
984
1012
|
exchange.extend_exchange_options(exchange.deep_extend(old_exchange_options, {}))
|
985
|
-
if not
|
1013
|
+
if not is_sync():
|
986
1014
|
await close(exchange)
|
987
1015
|
return True # in c# methods that will be used with promiseAll need to return something
|
988
1016
|
|
@@ -1003,7 +1031,7 @@ class testMainClass(baseMainTestClass):
|
|
1003
1031
|
await self.run_static_tests('request', target_exchange, test_name)
|
1004
1032
|
|
1005
1033
|
async def run_static_tests(self, type, target_exchange=None, test_name=None):
|
1006
|
-
folder =
|
1034
|
+
folder = get_root_dir() + './ts/src/test/static/' + type + '/'
|
1007
1035
|
static_data = self.load_static_data(folder, target_exchange)
|
1008
1036
|
if static_data is None:
|
1009
1037
|
return
|
@@ -1028,7 +1056,7 @@ class testMainClass(baseMainTestClass):
|
|
1028
1056
|
if self.request_tests_failed or self.response_tests_failed:
|
1029
1057
|
exit_script(1)
|
1030
1058
|
else:
|
1031
|
-
prefix = '[SYNC]' if (
|
1059
|
+
prefix = '[SYNC]' if (is_sync()) else ''
|
1032
1060
|
success_message = '[' + self.lang + ']' + prefix + '[TEST_SUCCESS] ' + str(sum) + ' static ' + type + ' tests passed.'
|
1033
1061
|
dump('[INFO]' + success_message)
|
1034
1062
|
|
@@ -1075,7 +1103,7 @@ class testMainClass(baseMainTestClass):
|
|
1075
1103
|
assert client_order_id_swap.startswith(swap_id_string), 'binance - swap clientOrderId: ' + client_order_id_swap + ' does not start with swapId' + swap_id_string
|
1076
1104
|
client_order_id_inverse = swap_inverse_order_request['newClientOrderId']
|
1077
1105
|
assert client_order_id_inverse.startswith(swap_id_string), 'binance - swap clientOrderIdInverse: ' + client_order_id_inverse + ' does not start with swapId' + swap_id_string
|
1078
|
-
if not
|
1106
|
+
if not is_sync():
|
1079
1107
|
await close(exchange)
|
1080
1108
|
return True
|
1081
1109
|
|
@@ -1101,7 +1129,7 @@ class testMainClass(baseMainTestClass):
|
|
1101
1129
|
assert client_order_id_swap.startswith(id_string), 'okx - swap clientOrderId: ' + client_order_id_swap + ' does not start with id: ' + id_string
|
1102
1130
|
swap_tag = swap_order_request[0]['tag']
|
1103
1131
|
assert swap_tag == id, 'okx - id: ' + id + ' different from swap tag: ' + swap_tag
|
1104
|
-
if not
|
1132
|
+
if not is_sync():
|
1105
1133
|
await close(exchange)
|
1106
1134
|
return True
|
1107
1135
|
|
@@ -1116,7 +1144,7 @@ class testMainClass(baseMainTestClass):
|
|
1116
1144
|
request = json_parse(exchange.last_request_body)
|
1117
1145
|
broker_id = request['params']['broker_id']
|
1118
1146
|
assert broker_id == id, 'cryptocom - id: ' + id + ' different from broker_id: ' + broker_id
|
1119
|
-
if not
|
1147
|
+
if not is_sync():
|
1120
1148
|
await close(exchange)
|
1121
1149
|
return True
|
1122
1150
|
|
@@ -1131,7 +1159,7 @@ class testMainClass(baseMainTestClass):
|
|
1131
1159
|
# we expect an error here, we're only interested in the headers
|
1132
1160
|
req_headers = exchange.last_request_headers
|
1133
1161
|
assert req_headers['Referer'] == id, 'bybit - id: ' + id + ' not in headers.'
|
1134
|
-
if not
|
1162
|
+
if not is_sync():
|
1135
1163
|
await close(exchange)
|
1136
1164
|
return True
|
1137
1165
|
|
@@ -1149,7 +1177,7 @@ class testMainClass(baseMainTestClass):
|
|
1149
1177
|
req_headers = exchange.last_request_headers
|
1150
1178
|
id = 'ccxt'
|
1151
1179
|
assert req_headers['KC-API-PARTNER'] == id, 'kucoin - id: ' + id + ' not in headers.'
|
1152
|
-
if not
|
1180
|
+
if not is_sync():
|
1153
1181
|
await close(exchange)
|
1154
1182
|
return True
|
1155
1183
|
|
@@ -1166,7 +1194,7 @@ class testMainClass(baseMainTestClass):
|
|
1166
1194
|
except Exception as e:
|
1167
1195
|
req_headers = exchange.last_request_headers
|
1168
1196
|
assert req_headers['KC-API-PARTNER'] == id, 'kucoinfutures - id: ' + id + ' not in headers.'
|
1169
|
-
if not
|
1197
|
+
if not is_sync():
|
1170
1198
|
await close(exchange)
|
1171
1199
|
return True
|
1172
1200
|
|
@@ -1180,7 +1208,7 @@ class testMainClass(baseMainTestClass):
|
|
1180
1208
|
except Exception as e:
|
1181
1209
|
req_headers = exchange.last_request_headers
|
1182
1210
|
assert req_headers['X-CHANNEL-API-CODE'] == id, 'bitget - id: ' + id + ' not in headers.'
|
1183
|
-
if not
|
1211
|
+
if not is_sync():
|
1184
1212
|
await close(exchange)
|
1185
1213
|
return True
|
1186
1214
|
|
@@ -1195,7 +1223,7 @@ class testMainClass(baseMainTestClass):
|
|
1195
1223
|
except Exception as e:
|
1196
1224
|
req_headers = exchange.last_request_headers
|
1197
1225
|
assert req_headers['source'] == id, 'mexc - id: ' + id + ' not in headers.'
|
1198
|
-
if not
|
1226
|
+
if not is_sync():
|
1199
1227
|
await close(exchange)
|
1200
1228
|
return True
|
1201
1229
|
|
@@ -1226,7 +1254,7 @@ class testMainClass(baseMainTestClass):
|
|
1226
1254
|
assert client_order_id_swap.startswith(id_string), 'htx - swap channel_code ' + client_order_id_swap + ' does not start with id: ' + id_string
|
1227
1255
|
client_order_id_inverse = swap_inverse_order_request['channel_code']
|
1228
1256
|
assert client_order_id_inverse.startswith(id_string), 'htx - swap inverse channel_code ' + client_order_id_inverse + ' does not start with id: ' + id_string
|
1229
|
-
if not
|
1257
|
+
if not is_sync():
|
1230
1258
|
await close(exchange)
|
1231
1259
|
return True
|
1232
1260
|
|
@@ -1252,7 +1280,7 @@ class testMainClass(baseMainTestClass):
|
|
1252
1280
|
stop_order_request = json_parse(exchange.last_request_body)
|
1253
1281
|
client_order_id_stop = stop_order_request['brokerId']
|
1254
1282
|
assert client_order_id_stop.startswith(id_string), 'woo - brokerId: ' + client_order_id_stop + ' does not start with id: ' + id_string
|
1255
|
-
if not
|
1283
|
+
if not is_sync():
|
1256
1284
|
await close(exchange)
|
1257
1285
|
return True
|
1258
1286
|
|
@@ -1267,7 +1295,7 @@ class testMainClass(baseMainTestClass):
|
|
1267
1295
|
except Exception as e:
|
1268
1296
|
req_headers = exchange.last_request_headers
|
1269
1297
|
assert req_headers['X-BM-BROKER-ID'] == id, 'bitmart - id: ' + id + ' not in headers'
|
1270
|
-
if not
|
1298
|
+
if not is_sync():
|
1271
1299
|
await close(exchange)
|
1272
1300
|
return True
|
1273
1301
|
|
@@ -1283,7 +1311,7 @@ class testMainClass(baseMainTestClass):
|
|
1283
1311
|
client_order_id = spot_order_request['client_id']
|
1284
1312
|
id_string = str(id)
|
1285
1313
|
assert client_order_id.startswith(id_string), 'coinex - clientOrderId: ' + client_order_id + ' does not start with id: ' + id_string
|
1286
|
-
if not
|
1314
|
+
if not is_sync():
|
1287
1315
|
await close(exchange)
|
1288
1316
|
return True
|
1289
1317
|
|
@@ -1298,7 +1326,7 @@ class testMainClass(baseMainTestClass):
|
|
1298
1326
|
# we expect an error here, we're only interested in the headers
|
1299
1327
|
req_headers = exchange.last_request_headers
|
1300
1328
|
assert req_headers['X-SOURCE-KEY'] == id, 'bingx - id: ' + id + ' not in headers.'
|
1301
|
-
if not
|
1329
|
+
if not is_sync():
|
1302
1330
|
await close(exchange)
|
1303
1331
|
|
1304
1332
|
async def test_phemex(self):
|
@@ -1312,7 +1340,7 @@ class testMainClass(baseMainTestClass):
|
|
1312
1340
|
client_order_id = request['clOrdID']
|
1313
1341
|
id_string = str(id)
|
1314
1342
|
assert client_order_id.startswith(id_string), 'phemex - clOrdID: ' + client_order_id + ' does not start with id: ' + id_string
|
1315
|
-
if not
|
1343
|
+
if not is_sync():
|
1316
1344
|
await close(exchange)
|
1317
1345
|
|
1318
1346
|
async def test_blofin(self):
|
@@ -1326,7 +1354,7 @@ class testMainClass(baseMainTestClass):
|
|
1326
1354
|
broker_id = request['brokerId']
|
1327
1355
|
id_string = str(id)
|
1328
1356
|
assert broker_id.startswith(id_string), 'blofin - brokerId: ' + broker_id + ' does not start with id: ' + id_string
|
1329
|
-
if not
|
1357
|
+
if not is_sync():
|
1330
1358
|
await close(exchange)
|
1331
1359
|
|
1332
1360
|
async def test_hyperliquid(self):
|
@@ -1339,7 +1367,7 @@ class testMainClass(baseMainTestClass):
|
|
1339
1367
|
request = json_parse(exchange.last_request_body)
|
1340
1368
|
broker_id = str((request['action']['brokerCode']))
|
1341
1369
|
assert broker_id == id, 'hyperliquid - brokerId: ' + broker_id + ' does not start with id: ' + id
|
1342
|
-
if not
|
1370
|
+
if not is_sync():
|
1343
1371
|
await close(exchange)
|
1344
1372
|
|
1345
1373
|
async def test_coinbaseinternational(self):
|
@@ -1354,7 +1382,7 @@ class testMainClass(baseMainTestClass):
|
|
1354
1382
|
request = json_parse(exchange.last_request_body)
|
1355
1383
|
client_order_id = request['client_order_id']
|
1356
1384
|
assert client_order_id.startswith(str(id)), 'clientOrderId does not start with id'
|
1357
|
-
if not
|
1385
|
+
if not is_sync():
|
1358
1386
|
await close(exchange)
|
1359
1387
|
return True
|
1360
1388
|
|
@@ -1369,7 +1397,7 @@ class testMainClass(baseMainTestClass):
|
|
1369
1397
|
request = json_parse(exchange.last_request_body)
|
1370
1398
|
client_order_id = request['client_order_id']
|
1371
1399
|
assert client_order_id.startswith(str(id)), 'clientOrderId does not start with id'
|
1372
|
-
if not
|
1400
|
+
if not is_sync():
|
1373
1401
|
await close(exchange)
|
1374
1402
|
return True
|
1375
1403
|
|
@@ -1385,7 +1413,7 @@ class testMainClass(baseMainTestClass):
|
|
1385
1413
|
request = json_parse(exchange.last_request_body)
|
1386
1414
|
broker_id = request['order_tag']
|
1387
1415
|
assert broker_id == id, 'woofipro - id: ' + id + ' different from broker_id: ' + broker_id
|
1388
|
-
if not
|
1416
|
+
if not is_sync():
|
1389
1417
|
await close(exchange)
|
1390
1418
|
return True
|
1391
1419
|
|
@@ -1422,7 +1450,7 @@ class testMainClass(baseMainTestClass):
|
|
1422
1450
|
swap_order_request = json_parse(exchange.last_request_body)
|
1423
1451
|
swap_media = swap_order_request['clientMedia']
|
1424
1452
|
assert swap_media == id, 'xt - id: ' + id + ' different from swap tag: ' + swap_media
|
1425
|
-
if not
|
1453
|
+
if not is_sync():
|
1426
1454
|
await close(exchange)
|
1427
1455
|
return True
|
1428
1456
|
|
@@ -1445,7 +1473,7 @@ class testMainClass(baseMainTestClass):
|
|
1445
1473
|
order = request['place_order']
|
1446
1474
|
broker_id = order['id']
|
1447
1475
|
assert broker_id == id, 'vertex - id: ' + str(id) + ' different from broker_id: ' + str(broker_id)
|
1448
|
-
if not
|
1476
|
+
if not is_sync():
|
1449
1477
|
await close(exchange)
|
1450
1478
|
return True
|
1451
1479
|
|
@@ -1487,7 +1515,7 @@ class testMainClass(baseMainTestClass):
|
|
1487
1515
|
except Exception as e:
|
1488
1516
|
req_headers = exchange.last_request_headers
|
1489
1517
|
assert req_headers['PARADEX-PARTNER'] == id, 'paradex - id: ' + id + ' not in headers'
|
1490
|
-
if not
|
1518
|
+
if not is_sync():
|
1491
1519
|
await close(exchange)
|
1492
1520
|
return True
|
1493
1521
|
|
@@ -1501,6 +1529,6 @@ class testMainClass(baseMainTestClass):
|
|
1501
1529
|
# we expect an error here, we're only interested in the headers
|
1502
1530
|
req_headers = exchange.last_request_headers
|
1503
1531
|
assert req_headers['INPUT-SOURCE'] == id, 'hashkey - id: ' + id + ' not in headers.'
|
1504
|
-
if not
|
1532
|
+
if not is_sync():
|
1505
1533
|
await close(exchange)
|
1506
1534
|
return True
|
ccxt/test/tests_helpers.py
CHANGED
@@ -105,14 +105,15 @@ sys.excepthook = handle_all_unhandled_exceptions
|
|
105
105
|
|
106
106
|
# non-transpiled part, but shared names among langs
|
107
107
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
108
|
+
EXT = 'py'
|
109
|
+
LANG = 'PY'
|
110
|
+
IS_SYNCHRONOUS = argv.sync # 'async' not in os.path.basename(__file__)
|
111
|
+
PROXY_TEST_FILE_NAME = 'proxies'
|
112
|
+
ROOT_DIR = DIR_NAME + '/../../../'
|
113
|
+
ENV_VARS = os.environ
|
114
|
+
NEW_LINE = '\n'
|
113
115
|
LOG_CHARS_LENGTH = 10000
|
114
|
-
|
115
|
-
proxyTestFileName = 'proxies'
|
116
|
+
|
116
117
|
|
117
118
|
|
118
119
|
def get_cli_arg_value(arg):
|
@@ -125,30 +126,6 @@ def get_cli_arg_value(arg):
|
|
125
126
|
|
126
127
|
isWsTests = get_cli_arg_value('--ws')
|
127
128
|
|
128
|
-
|
129
|
-
class baseMainTestClass():
|
130
|
-
lang = 'PY'
|
131
|
-
is_synchronous = is_synchronous
|
132
|
-
request_tests_failed = False
|
133
|
-
response_tests_failed = False
|
134
|
-
response_tests = False
|
135
|
-
ws_tests = False
|
136
|
-
load_keys = False
|
137
|
-
skipped_settings_for_exchange = {}
|
138
|
-
skipped_methods = {}
|
139
|
-
check_public_tests = {}
|
140
|
-
test_files = {}
|
141
|
-
public_tests = {}
|
142
|
-
new_line = '\n'
|
143
|
-
root_dir = rootDir
|
144
|
-
env_vars = envVars
|
145
|
-
ext = ext
|
146
|
-
root_dir_for_skips = rootDirForSkips
|
147
|
-
only_specific_tests = []
|
148
|
-
proxy_test_file_name = proxyTestFileName
|
149
|
-
pass
|
150
|
-
|
151
|
-
|
152
129
|
def dump(*args):
|
153
130
|
print(' '.join([str(arg) for arg in args]))
|
154
131
|
|
@@ -240,7 +217,7 @@ def set_exchange_prop(exchange, prop, value):
|
|
240
217
|
|
241
218
|
|
242
219
|
def init_exchange(exchangeId, args, is_ws=False):
|
243
|
-
if
|
220
|
+
if IS_SYNCHRONOUS:
|
244
221
|
return getattr(ccxt_sync, exchangeId)(args)
|
245
222
|
if (is_ws):
|
246
223
|
return getattr(ccxtpro, exchangeId)(args)
|
@@ -249,11 +226,11 @@ def init_exchange(exchangeId, args, is_ws=False):
|
|
249
226
|
|
250
227
|
def get_test_files_sync(properties, ws=False):
|
251
228
|
tests = {}
|
252
|
-
finalPropList = properties + [
|
229
|
+
finalPropList = properties + [PROXY_TEST_FILE_NAME]
|
253
230
|
for i in range(0, len(finalPropList)):
|
254
231
|
methodName = finalPropList[i]
|
255
232
|
name_snake_case = convert_to_snake_case(methodName)
|
256
|
-
prefix = 'async' if not
|
233
|
+
prefix = 'async' if not IS_SYNCHRONOUS else 'sync'
|
257
234
|
dir_to_test = DIR_NAME + '/exchange/' + prefix + '/'
|
258
235
|
module_string = 'ccxt.test.exchange.' + prefix + '.test_' + name_snake_case
|
259
236
|
if (ws):
|
@@ -270,14 +247,14 @@ async def get_test_files(properties, ws=False):
|
|
270
247
|
return get_test_files_sync(properties, ws)
|
271
248
|
|
272
249
|
async def close(exchange):
|
273
|
-
if (not
|
250
|
+
if (not IS_SYNCHRONOUS and hasattr(exchange, 'close')):
|
274
251
|
await exchange.close()
|
275
252
|
|
276
253
|
def is_null_value(value):
|
277
254
|
return value is None
|
278
255
|
|
279
256
|
def set_fetch_response(exchange: ccxt.Exchange, data):
|
280
|
-
if (
|
257
|
+
if (IS_SYNCHRONOUS):
|
281
258
|
def fetch(url, method='GET', headers=None, body=None):
|
282
259
|
return data
|
283
260
|
exchange.fetch = fetch
|
@@ -287,6 +264,20 @@ def set_fetch_response(exchange: ccxt.Exchange, data):
|
|
287
264
|
exchange.fetch = fetch
|
288
265
|
return exchange
|
289
266
|
|
267
|
+
def get_lang():
|
268
|
+
return LANG
|
269
|
+
|
270
|
+
def get_ext():
|
271
|
+
return EXT
|
272
|
+
|
273
|
+
def get_root_dir():
|
274
|
+
return ROOT_DIR
|
275
|
+
|
276
|
+
def get_env_vars():
|
277
|
+
return ENV_VARS
|
278
|
+
|
279
|
+
def is_sync():
|
280
|
+
return IS_SYNCHRONOUS
|
290
281
|
|
291
282
|
argvExchange = argv.exchange
|
292
283
|
argvSymbol = 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,
|
3
|
+
from tests_helpers import get_cli_arg_value, IS_SYNCHRONOUS, argvExchange, argvSymbol, argvMethod
|
4
4
|
|
5
5
|
try:
|
6
6
|
import asyncio
|
@@ -10,6 +10,10 @@ except ImportError:
|
|
10
10
|
from base.tests_init import base_tests_init # noqa: F401
|
11
11
|
from ccxt.pro.test.base.tests_init import test_base_init_ws # noqa: F401
|
12
12
|
|
13
|
+
# fix : https://github.com/aio-libs/aiodns/issues/86
|
14
|
+
import sys
|
15
|
+
if sys.platform == 'win32':
|
16
|
+
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
13
17
|
|
14
18
|
# ########### args ###########
|
15
19
|
isWs = get_cli_arg_value('--ws')
|
@@ -27,7 +31,7 @@ if (isBaseTests):
|
|
27
31
|
exit(0)
|
28
32
|
|
29
33
|
# ###### exchange tests #######
|
30
|
-
if (
|
34
|
+
if (IS_SYNCHRONOUS):
|
31
35
|
from tests_sync import testMainClass as testMainClassSync
|
32
36
|
testMainClassSync().init(argvExchange, argvSymbol, argvMethod)
|
33
37
|
else:
|