ccxt 4.3.84__py2.py3-none-any.whl → 4.3.86__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 +4 -1
- ccxt/abstract/cryptocom.py +2 -0
- ccxt/abstract/hashkey.py +67 -0
- ccxt/abstract/kucoinfutures.py +2 -0
- ccxt/async_support/__init__.py +4 -1
- ccxt/async_support/base/exchange.py +2 -2
- ccxt/async_support/binance.py +4 -2
- ccxt/async_support/bitfinex.py +2 -2
- ccxt/async_support/bitmex.py +2 -0
- ccxt/async_support/bybit.py +16 -14
- ccxt/async_support/cryptocom.py +113 -3
- ccxt/async_support/hashkey.py +4062 -0
- ccxt/async_support/hyperliquid.py +80 -62
- ccxt/async_support/indodax.py +29 -8
- ccxt/async_support/kraken.py +28 -1
- ccxt/async_support/krakenfutures.py +10 -9
- ccxt/async_support/kucoinfutures.py +5 -0
- ccxt/async_support/mexc.py +2 -2
- ccxt/base/errors.py +6 -0
- ccxt/base/exchange.py +2 -2
- ccxt/binance.py +4 -2
- ccxt/bitfinex.py +2 -2
- ccxt/bitmex.py +2 -0
- ccxt/bybit.py +16 -14
- ccxt/cryptocom.py +113 -3
- ccxt/hashkey.py +4062 -0
- ccxt/hyperliquid.py +80 -62
- ccxt/indodax.py +29 -8
- ccxt/kraken.py +28 -1
- ccxt/krakenfutures.py +10 -9
- ccxt/kucoinfutures.py +5 -0
- ccxt/mexc.py +2 -2
- ccxt/pro/__init__.py +3 -1
- ccxt/pro/ascendex.py +41 -5
- ccxt/pro/binance.py +1 -1
- ccxt/pro/bingx.py +13 -12
- ccxt/pro/bitget.py +104 -4
- ccxt/pro/hashkey.py +783 -0
- ccxt/pro/hyperliquid.py +118 -1
- ccxt/pro/mexc.py +13 -7
- ccxt/pro/okx.py +21 -3
- ccxt/pro/woo.py +1 -0
- ccxt/pro/woofipro.py +1 -0
- ccxt/pro/xt.py +1 -0
- ccxt/test/tests_async.py +13 -30
- ccxt/test/tests_sync.py +13 -30
- {ccxt-4.3.84.dist-info → ccxt-4.3.86.dist-info}/METADATA +8 -6
- {ccxt-4.3.84.dist-info → ccxt-4.3.86.dist-info}/RECORD +51 -47
- {ccxt-4.3.84.dist-info → ccxt-4.3.86.dist-info}/LICENSE.txt +0 -0
- {ccxt-4.3.84.dist-info → ccxt-4.3.86.dist-info}/WHEEL +0 -0
- {ccxt-4.3.84.dist-info → ccxt-4.3.86.dist-info}/top_level.txt +0 -0
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, Strings, Ticker, Tickers, Trade
|
8
|
+
from ccxt.base.types import Any, Int, Market, Num, Order, OrderBook, OrderRequest, 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
|
@@ -17,6 +17,9 @@ class hyperliquid(ccxt.async_support.hyperliquid):
|
|
17
17
|
return self.deep_extend(super(hyperliquid, self).describe(), {
|
18
18
|
'has': {
|
19
19
|
'ws': True,
|
20
|
+
'createOrderWs': True,
|
21
|
+
'createOrdersWs': True,
|
22
|
+
'editOrderWs': True,
|
20
23
|
'watchBalance': False,
|
21
24
|
'watchMyTrades': True,
|
22
25
|
'watchOHLCV': True,
|
@@ -53,6 +56,84 @@ class hyperliquid(ccxt.async_support.hyperliquid):
|
|
53
56
|
},
|
54
57
|
})
|
55
58
|
|
59
|
+
async def create_orders_ws(self, orders: List[OrderRequest], params={}):
|
60
|
+
"""
|
61
|
+
create a list of trade orders using WebSocket post request
|
62
|
+
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#place-an-order
|
63
|
+
:param Array orders: list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params
|
64
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
65
|
+
"""
|
66
|
+
await self.load_markets()
|
67
|
+
url = self.urls['api']['ws']['public']
|
68
|
+
ordersRequest = self.createOrdersRequest(orders, params)
|
69
|
+
wrapped = self.wrap_as_post_action(ordersRequest)
|
70
|
+
request = self.safe_dict(wrapped, 'request', {})
|
71
|
+
requestId = self.safe_string(wrapped, 'requestId')
|
72
|
+
response = await self.watch(url, requestId, request, requestId)
|
73
|
+
responseOjb = self.safe_dict(response, 'response', {})
|
74
|
+
data = self.safe_dict(responseOjb, 'data', {})
|
75
|
+
statuses = self.safe_list(data, 'statuses', [])
|
76
|
+
return self.parse_orders(statuses, None)
|
77
|
+
|
78
|
+
async def create_order_ws(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
|
79
|
+
"""
|
80
|
+
create a trade order using WebSocket post request
|
81
|
+
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#place-an-order
|
82
|
+
:param str symbol: unified symbol of the market to create an order in
|
83
|
+
:param str type: 'market' or 'limit'
|
84
|
+
:param str side: 'buy' or 'sell'
|
85
|
+
:param float amount: how much of currency you want to trade in units of base currency
|
86
|
+
:param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
|
87
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
88
|
+
:param str [params.timeInForce]: 'Gtc', 'Ioc', 'Alo'
|
89
|
+
:param bool [params.postOnly]: True or False whether the order is post-only
|
90
|
+
:param bool [params.reduceOnly]: True or False whether the order is reduce-only
|
91
|
+
:param float [params.triggerPrice]: The price at which a trigger order is triggered at
|
92
|
+
:param str [params.clientOrderId]: client order id,(optional 128 bit hex string e.g. 0x1234567890abcdef1234567890abcdef)
|
93
|
+
:param str [params.slippage]: the slippage for market order
|
94
|
+
:param str [params.vaultAddress]: the vault address for order
|
95
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
96
|
+
"""
|
97
|
+
await self.load_markets()
|
98
|
+
order, globalParams = self.parseCreateOrderArgs(symbol, type, side, amount, price, params)
|
99
|
+
orders = await self.create_orders_ws([order], globalParams)
|
100
|
+
return orders[0]
|
101
|
+
|
102
|
+
async def edit_order_ws(self, id: str, symbol: str, type: str, side: str, amount: Num = None, price: Num = None, params={}):
|
103
|
+
"""
|
104
|
+
edit a trade order
|
105
|
+
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#modify-an-order
|
106
|
+
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#modify-multiple-orders
|
107
|
+
:param str id: cancel order id
|
108
|
+
:param str symbol: unified symbol of the market to create an order in
|
109
|
+
:param str type: 'market' or 'limit'
|
110
|
+
:param str side: 'buy' or 'sell'
|
111
|
+
:param float amount: how much of currency you want to trade in units of base currency
|
112
|
+
:param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
|
113
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
114
|
+
:param str [params.timeInForce]: 'Gtc', 'Ioc', 'Alo'
|
115
|
+
:param bool [params.postOnly]: True or False whether the order is post-only
|
116
|
+
:param bool [params.reduceOnly]: True or False whether the order is reduce-only
|
117
|
+
:param float [params.triggerPrice]: The price at which a trigger order is triggered at
|
118
|
+
:param str [params.clientOrderId]: client order id,(optional 128 bit hex string e.g. 0x1234567890abcdef1234567890abcdef)
|
119
|
+
:param str [params.vaultAddress]: the vault address for order
|
120
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
121
|
+
"""
|
122
|
+
await self.load_markets()
|
123
|
+
market = self.market(symbol)
|
124
|
+
url = self.urls['api']['ws']['public']
|
125
|
+
postRequest = self.edit_order_request(id, symbol, type, side, amount, price, params)
|
126
|
+
wrapped = self.wrap_as_post_action(postRequest)
|
127
|
+
request = self.safe_dict(wrapped, 'request', {})
|
128
|
+
requestId = self.safe_string(wrapped, 'requestId')
|
129
|
+
response = await self.watch(url, requestId, request, requestId)
|
130
|
+
# response is the same self.edit_order
|
131
|
+
responseObject = self.safe_dict(response, 'response', {})
|
132
|
+
dataObject = self.safe_dict(responseObject, 'data', {})
|
133
|
+
statuses = self.safe_list(dataObject, 'statuses', [])
|
134
|
+
first = self.safe_dict(statuses, 0, {})
|
135
|
+
return self.parse_order(first, market)
|
136
|
+
|
56
137
|
async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
|
57
138
|
"""
|
58
139
|
watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
|
@@ -494,6 +575,22 @@ class hyperliquid(ccxt.async_support.hyperliquid):
|
|
494
575
|
messageHash = 'candles:' + timeframe + ':' + symbol
|
495
576
|
client.resolve(ohlcv, messageHash)
|
496
577
|
|
578
|
+
def handle_ws_post(self, client: Client, message: Any):
|
579
|
+
# {
|
580
|
+
# channel: "post",
|
581
|
+
# data: {
|
582
|
+
# id: <number>,
|
583
|
+
# response: {
|
584
|
+
# type: "info" | "action" | "error",
|
585
|
+
# payload: {...}
|
586
|
+
# }
|
587
|
+
# }
|
588
|
+
data = self.safe_dict(message, 'data')
|
589
|
+
id = self.safe_string(data, 'id')
|
590
|
+
response = self.safe_dict(data, 'response')
|
591
|
+
payload = self.safe_dict(response, 'payload')
|
592
|
+
client.resolve(payload, id)
|
593
|
+
|
497
594
|
async def watch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
498
595
|
"""
|
499
596
|
watches information on multiple orders made by the user
|
@@ -597,6 +694,7 @@ class hyperliquid(ccxt.async_support.hyperliquid):
|
|
597
694
|
'orderUpdates': self.handle_order,
|
598
695
|
'userFills': self.handle_my_trades,
|
599
696
|
'webData2': self.handle_ws_tickers,
|
697
|
+
'post': self.handle_ws_post,
|
600
698
|
}
|
601
699
|
exacMethod = self.safe_value(methods, topic)
|
602
700
|
if exacMethod is not None:
|
@@ -623,3 +721,22 @@ class hyperliquid(ccxt.async_support.hyperliquid):
|
|
623
721
|
#
|
624
722
|
client.lastPong = self.safe_integer(message, 'pong')
|
625
723
|
return message
|
724
|
+
|
725
|
+
def request_id(self) -> float:
|
726
|
+
requestId = self.sum(self.safe_integer(self.options, 'requestId', 0), 1)
|
727
|
+
self.options['requestId'] = requestId
|
728
|
+
return requestId
|
729
|
+
|
730
|
+
def wrap_as_post_action(self, request: dict) -> dict:
|
731
|
+
requestId = self.request_id()
|
732
|
+
return {
|
733
|
+
'requestId': requestId,
|
734
|
+
'request': {
|
735
|
+
'method': 'post',
|
736
|
+
'id': requestId,
|
737
|
+
'request': {
|
738
|
+
'type': 'action',
|
739
|
+
'payload': request,
|
740
|
+
},
|
741
|
+
},
|
742
|
+
}
|
ccxt/pro/mexc.py
CHANGED
@@ -35,6 +35,7 @@ class mexc(ccxt.async_support.mexc):
|
|
35
35
|
'watchTicker': True,
|
36
36
|
'watchTickers': False,
|
37
37
|
'watchTrades': True,
|
38
|
+
'watchTradesForSymbols': False,
|
38
39
|
},
|
39
40
|
'urls': {
|
40
41
|
'api': {
|
@@ -76,6 +77,8 @@ class mexc(ccxt.async_support.mexc):
|
|
76
77
|
async def watch_ticker(self, symbol: str, params={}) -> Ticker:
|
77
78
|
"""
|
78
79
|
watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
|
80
|
+
:see: https://mexcdevelop.github.io/apidocs/spot_v3_en/#individual-symbol-book-ticker-streams
|
81
|
+
:see: https://mexcdevelop.github.io/apidocs/contract_v1_en/#public-channels
|
79
82
|
:param str symbol: unified symbol of the market to fetch the ticker for
|
80
83
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
81
84
|
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
@@ -202,7 +205,7 @@ class mexc(ccxt.async_support.mexc):
|
|
202
205
|
|
203
206
|
async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
|
204
207
|
"""
|
205
|
-
:see: https://
|
208
|
+
:see: https://mexcdevelop.github.io/apidocs/spot_v3_en/#kline-streams
|
206
209
|
watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
207
210
|
:param str symbol: unified symbol of the market to fetch OHLCV data for
|
208
211
|
:param str timeframe: the length of time each candle represents
|
@@ -342,7 +345,8 @@ class mexc(ccxt.async_support.mexc):
|
|
342
345
|
|
343
346
|
async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
|
344
347
|
"""
|
345
|
-
:see: https://
|
348
|
+
:see: https://mexcdevelop.github.io/apidocs/spot_v3_en/#diff-depth-stream
|
349
|
+
:see: https://mexcdevelop.github.io/apidocs/contract_v1_en/#public-channels
|
346
350
|
watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
|
347
351
|
:param str symbol: unified symbol of the market to fetch the order book for
|
348
352
|
:param int [limit]: the maximum amount of order book entries to return
|
@@ -496,7 +500,8 @@ class mexc(ccxt.async_support.mexc):
|
|
496
500
|
|
497
501
|
async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
498
502
|
"""
|
499
|
-
:see: https://
|
503
|
+
:see: https://mexcdevelop.github.io/apidocs/spot_v3_en/#trade-streams
|
504
|
+
:see: https://mexcdevelop.github.io/apidocs/contract_v1_en/#public-channels
|
500
505
|
get the list of most recent trades for a particular symbol
|
501
506
|
:param str symbol: unified symbol of the market to fetch trades for
|
502
507
|
:param int [since]: timestamp in ms of the earliest trade to fetch
|
@@ -576,7 +581,8 @@ class mexc(ccxt.async_support.mexc):
|
|
576
581
|
|
577
582
|
async def watch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
578
583
|
"""
|
579
|
-
:see: https://
|
584
|
+
:see: https://mexcdevelop.github.io/apidocs/spot_v3_en/#spot-account-deals
|
585
|
+
:see: https://mexcdevelop.github.io/apidocs/contract_v1_en/#private-channels
|
580
586
|
watches information on multiple trades made by the user
|
581
587
|
:param str symbol: unified market symbol of the market trades were made in
|
582
588
|
:param int [since]: the earliest time in ms to fetch trades for
|
@@ -713,8 +719,8 @@ class mexc(ccxt.async_support.mexc):
|
|
713
719
|
|
714
720
|
async def watch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
715
721
|
"""
|
716
|
-
:see: https://
|
717
|
-
:see: https://
|
722
|
+
:see: https://mexcdevelop.github.io/apidocs/spot_v3_en/#spot-account-orders
|
723
|
+
:see: https://mexcdevelop.github.io/apidocs/spot_v3_en/#margin-account-orders
|
718
724
|
watches information on multiple orders made by the user
|
719
725
|
:param str symbol: unified market symbol of the market orders were made in
|
720
726
|
:param int [since]: the earliest time in ms to fetch orders for
|
@@ -955,7 +961,7 @@ class mexc(ccxt.async_support.mexc):
|
|
955
961
|
|
956
962
|
async def watch_balance(self, params={}) -> Balances:
|
957
963
|
"""
|
958
|
-
:see: https://
|
964
|
+
:see: https://mexcdevelop.github.io/apidocs/spot_v3_en/#spot-account-upadte
|
959
965
|
watch balance and get the amount of funds available for trading or funds locked in orders
|
960
966
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
961
967
|
:returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
|
ccxt/pro/okx.py
CHANGED
@@ -419,8 +419,13 @@ class okx(ccxt.async_support.okx):
|
|
419
419
|
await self.load_markets()
|
420
420
|
symbols = self.market_symbols(symbols, None, True, True)
|
421
421
|
messageHash = 'liquidations'
|
422
|
+
messageHashes = []
|
422
423
|
if symbols is not None:
|
423
|
-
|
424
|
+
for i in range(0, len(symbols)):
|
425
|
+
symbol = symbols[i]
|
426
|
+
messageHashes.append(messageHash + '::' + symbol)
|
427
|
+
else:
|
428
|
+
messageHashes.append(messageHash)
|
424
429
|
market = self.get_market_from_symbols(symbols)
|
425
430
|
type = None
|
426
431
|
type, params = self.handle_market_type_and_params('watchliquidationsForSymbols', market, params)
|
@@ -431,9 +436,16 @@ class okx(ccxt.async_support.okx):
|
|
431
436
|
type = 'futures'
|
432
437
|
uppercaseType = type.upper()
|
433
438
|
request = {
|
434
|
-
'
|
439
|
+
'op': 'subscribe',
|
440
|
+
'args': [
|
441
|
+
{
|
442
|
+
'channel': channel,
|
443
|
+
'instType': uppercaseType,
|
444
|
+
},
|
445
|
+
],
|
435
446
|
}
|
436
|
-
|
447
|
+
url = self.get_url(channel, 'public')
|
448
|
+
newLiquidations = await self.watch_multiple(url, messageHashes, request, messageHashes)
|
437
449
|
if self.newUpdates:
|
438
450
|
return newLiquidations
|
439
451
|
return self.filter_by_symbols_since_limit(self.liquidations, symbols, since, limit, True)
|
@@ -1305,6 +1317,12 @@ class okx(ccxt.async_support.okx):
|
|
1305
1317
|
for i in range(0, len(data)):
|
1306
1318
|
rawPosition = data[i]
|
1307
1319
|
position = self.parse_position(rawPosition)
|
1320
|
+
if position['contracts'] == 0:
|
1321
|
+
position['side'] = 'long'
|
1322
|
+
shortPosition = self.clone(position)
|
1323
|
+
shortPosition['side'] = 'short'
|
1324
|
+
cache.append(shortPosition)
|
1325
|
+
newPositions.append(shortPosition)
|
1308
1326
|
newPositions.append(position)
|
1309
1327
|
cache.append(position)
|
1310
1328
|
messageHashes = self.find_message_hashes(client, channel + '::')
|
ccxt/pro/woo.py
CHANGED
ccxt/pro/woofipro.py
CHANGED
ccxt/pro/xt.py
CHANGED
ccxt/test/tests_async.py
CHANGED
@@ -143,24 +143,6 @@ class testMainClass(baseMainTestClass):
|
|
143
143
|
res += ' '
|
144
144
|
return message + res
|
145
145
|
|
146
|
-
def exchange_hint(self, exchange, market=None):
|
147
|
-
market_type = exchange.safe_string_2(exchange.options, 'defaultType', 'type', '')
|
148
|
-
market_sub_type = exchange.safe_string_2(exchange.options, 'defaultSubType', 'subType')
|
149
|
-
if market is not None:
|
150
|
-
market_type = market['type']
|
151
|
-
if market['linear']:
|
152
|
-
market_sub_type = 'linear'
|
153
|
-
elif market['inverse']:
|
154
|
-
market_sub_type = 'inverse'
|
155
|
-
elif exchange.safe_value(market, 'quanto'):
|
156
|
-
market_sub_type = 'quanto'
|
157
|
-
is_ws = ('ws' in exchange.has)
|
158
|
-
ws_flag = '(WS)' if is_ws else ''
|
159
|
-
result = exchange.id + ' ' + ws_flag + ' ' + market_type
|
160
|
-
if market_sub_type is not None:
|
161
|
-
result = result + ' [subType: ' + market_sub_type + '] '
|
162
|
-
return result
|
163
|
-
|
164
146
|
async def test_method(self, method_name, exchange, args, is_public):
|
165
147
|
# todo: temporary skip for c#
|
166
148
|
if 'OrderBook' in method_name and self.ext == 'cs':
|
@@ -188,19 +170,20 @@ class testMainClass(baseMainTestClass):
|
|
188
170
|
# exceptionally for `loadMarkets` call, we call it before it's even checked for "skip" as we need it to be called anyway (but can skip "test.loadMarket" for it)
|
189
171
|
if is_load_markets:
|
190
172
|
await exchange.load_markets(True)
|
173
|
+
name = exchange.id
|
191
174
|
if skip_message:
|
192
175
|
if self.info:
|
193
|
-
dump(self.add_padding(skip_message, 25),
|
176
|
+
dump(self.add_padding(skip_message, 25), name, method_name)
|
194
177
|
return
|
195
178
|
if self.info:
|
196
179
|
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"
|
197
|
-
dump(self.add_padding('[INFO] TESTING', 25),
|
180
|
+
dump(self.add_padding('[INFO] TESTING', 25), name, method_name, args_stringified)
|
198
181
|
if self.is_synchronous:
|
199
182
|
call_method_sync(self.test_files, method_name, exchange, skipped_properties_for_method, args)
|
200
183
|
else:
|
201
184
|
await call_method(self.test_files, method_name, exchange, skipped_properties_for_method, args)
|
202
185
|
if self.info:
|
203
|
-
dump(self.add_padding('[INFO] TESTING DONE', 25),
|
186
|
+
dump(self.add_padding('[INFO] TESTING DONE', 25), name, method_name)
|
204
187
|
# add to the list of successed tests
|
205
188
|
if is_public:
|
206
189
|
self.checked_public_tests[method_name] = True
|
@@ -294,7 +277,7 @@ class testMainClass(baseMainTestClass):
|
|
294
277
|
return_success = True
|
295
278
|
# output the message
|
296
279
|
fail_type = '[TEST_FAILURE]' if should_fail else '[TEST_WARNING]'
|
297
|
-
dump(fail_type, 'Method could not be tested due to a repeated Network/Availability issues', ' | ',
|
280
|
+
dump(fail_type, 'Method could not be tested due to a repeated Network/Availability issues', ' | ', exchange.id, method_name, args_stringified, exception_message(e))
|
298
281
|
return return_success
|
299
282
|
else:
|
300
283
|
# wait and retry again
|
@@ -304,21 +287,21 @@ class testMainClass(baseMainTestClass):
|
|
304
287
|
else:
|
305
288
|
# if it's loadMarkets, then fail test, because it's mandatory for tests
|
306
289
|
if is_load_markets:
|
307
|
-
dump('[TEST_FAILURE]', 'Exchange can not load markets', exception_message(e),
|
290
|
+
dump('[TEST_FAILURE]', 'Exchange can not load markets', exception_message(e), exchange.id, method_name, args_stringified)
|
308
291
|
return False
|
309
292
|
# if the specific arguments to the test method throws "NotSupported" exception
|
310
293
|
# then let's don't fail the test
|
311
294
|
if is_not_supported:
|
312
295
|
if self.info:
|
313
|
-
dump('[INFO] NOT_SUPPORTED', exception_message(e),
|
296
|
+
dump('[INFO] NOT_SUPPORTED', exception_message(e), exchange.id, method_name, args_stringified)
|
314
297
|
return True
|
315
298
|
# If public test faces authentication error, we don't break (see comments under `testSafe` method)
|
316
299
|
if is_public and is_auth_error:
|
317
300
|
if self.info:
|
318
|
-
dump('[INFO]', 'Authentication problem for public method', exception_message(e),
|
301
|
+
dump('[INFO]', 'Authentication problem for public method', exception_message(e), exchange.id, method_name, args_stringified)
|
319
302
|
return True
|
320
303
|
else:
|
321
|
-
dump('[TEST_FAILURE]', exception_message(e),
|
304
|
+
dump('[TEST_FAILURE]', exception_message(e), exchange.id, method_name, args_stringified)
|
322
305
|
return False
|
323
306
|
return True
|
324
307
|
|
@@ -384,9 +367,9 @@ class testMainClass(baseMainTestClass):
|
|
384
367
|
test_prefix_string = 'PUBLIC_TESTS' if is_public_test else 'PRIVATE_TESTS'
|
385
368
|
if len(failed_methods):
|
386
369
|
errors_string = ', '.join(failed_methods)
|
387
|
-
dump('[TEST_FAILURE]',
|
370
|
+
dump('[TEST_FAILURE]', exchange.id, test_prefix_string, 'Failed methods : ' + errors_string)
|
388
371
|
if self.info:
|
389
|
-
dump(self.add_padding('[INFO] END ' + test_prefix_string + ' ' +
|
372
|
+
dump(self.add_padding('[INFO] END ' + test_prefix_string + ' ' + exchange.id, 25))
|
390
373
|
|
391
374
|
async def load_exchange(self, exchange):
|
392
375
|
result = await self.test_safe('loadMarkets', exchange, [], True)
|
@@ -846,7 +829,7 @@ class testMainClass(baseMainTestClass):
|
|
846
829
|
self.assert_static_request_output(exchange, type, skip_keys, data['url'], request_url, call_output, output)
|
847
830
|
except Exception as e:
|
848
831
|
self.request_tests_failed = True
|
849
|
-
error_message = '[' + self.lang + '][STATIC_REQUEST_TEST_FAILURE]' + '[' +
|
832
|
+
error_message = '[' + self.lang + '][STATIC_REQUEST_TEST_FAILURE]' + '[' + exchange.id + ']' + '[' + method + ']' + '[' + data['description'] + ']' + str(e)
|
850
833
|
dump('[TEST_FAILURE]' + error_message)
|
851
834
|
|
852
835
|
async def test_response_statically(self, exchange, method, skip_keys, data):
|
@@ -861,7 +844,7 @@ class testMainClass(baseMainTestClass):
|
|
861
844
|
self.assert_static_response_output(mocked_exchange, skip_keys, unified_result_sync, expected_result)
|
862
845
|
except Exception as e:
|
863
846
|
self.response_tests_failed = True
|
864
|
-
error_message = '[' + self.lang + '][STATIC_RESPONSE_TEST_FAILURE]' + '[' +
|
847
|
+
error_message = '[' + self.lang + '][STATIC_RESPONSE_TEST_FAILURE]' + '[' + exchange.id + ']' + '[' + method + ']' + '[' + data['description'] + ']' + str(e)
|
865
848
|
dump('[TEST_FAILURE]' + error_message)
|
866
849
|
set_fetch_response(exchange, None) # reset state
|
867
850
|
|
ccxt/test/tests_sync.py
CHANGED
@@ -140,24 +140,6 @@ class testMainClass(baseMainTestClass):
|
|
140
140
|
res += ' '
|
141
141
|
return message + res
|
142
142
|
|
143
|
-
def exchange_hint(self, exchange, market=None):
|
144
|
-
market_type = exchange.safe_string_2(exchange.options, 'defaultType', 'type', '')
|
145
|
-
market_sub_type = exchange.safe_string_2(exchange.options, 'defaultSubType', 'subType')
|
146
|
-
if market is not None:
|
147
|
-
market_type = market['type']
|
148
|
-
if market['linear']:
|
149
|
-
market_sub_type = 'linear'
|
150
|
-
elif market['inverse']:
|
151
|
-
market_sub_type = 'inverse'
|
152
|
-
elif exchange.safe_value(market, 'quanto'):
|
153
|
-
market_sub_type = 'quanto'
|
154
|
-
is_ws = ('ws' in exchange.has)
|
155
|
-
ws_flag = '(WS)' if is_ws else ''
|
156
|
-
result = exchange.id + ' ' + ws_flag + ' ' + market_type
|
157
|
-
if market_sub_type is not None:
|
158
|
-
result = result + ' [subType: ' + market_sub_type + '] '
|
159
|
-
return result
|
160
|
-
|
161
143
|
def test_method(self, method_name, exchange, args, is_public):
|
162
144
|
# todo: temporary skip for c#
|
163
145
|
if 'OrderBook' in method_name and self.ext == 'cs':
|
@@ -185,19 +167,20 @@ class testMainClass(baseMainTestClass):
|
|
185
167
|
# exceptionally for `loadMarkets` call, we call it before it's even checked for "skip" as we need it to be called anyway (but can skip "test.loadMarket" for it)
|
186
168
|
if is_load_markets:
|
187
169
|
exchange.load_markets(True)
|
170
|
+
name = exchange.id
|
188
171
|
if skip_message:
|
189
172
|
if self.info:
|
190
|
-
dump(self.add_padding(skip_message, 25),
|
173
|
+
dump(self.add_padding(skip_message, 25), name, method_name)
|
191
174
|
return
|
192
175
|
if self.info:
|
193
176
|
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
|
-
dump(self.add_padding('[INFO] TESTING', 25),
|
177
|
+
dump(self.add_padding('[INFO] TESTING', 25), name, method_name, args_stringified)
|
195
178
|
if self.is_synchronous:
|
196
179
|
call_method_sync(self.test_files, method_name, exchange, skipped_properties_for_method, args)
|
197
180
|
else:
|
198
181
|
call_method(self.test_files, method_name, exchange, skipped_properties_for_method, args)
|
199
182
|
if self.info:
|
200
|
-
dump(self.add_padding('[INFO] TESTING DONE', 25),
|
183
|
+
dump(self.add_padding('[INFO] TESTING DONE', 25), name, method_name)
|
201
184
|
# add to the list of successed tests
|
202
185
|
if is_public:
|
203
186
|
self.checked_public_tests[method_name] = True
|
@@ -291,7 +274,7 @@ class testMainClass(baseMainTestClass):
|
|
291
274
|
return_success = True
|
292
275
|
# output the message
|
293
276
|
fail_type = '[TEST_FAILURE]' if should_fail else '[TEST_WARNING]'
|
294
|
-
dump(fail_type, 'Method could not be tested due to a repeated Network/Availability issues', ' | ',
|
277
|
+
dump(fail_type, 'Method could not be tested due to a repeated Network/Availability issues', ' | ', exchange.id, method_name, args_stringified, exception_message(e))
|
295
278
|
return return_success
|
296
279
|
else:
|
297
280
|
# wait and retry again
|
@@ -301,21 +284,21 @@ class testMainClass(baseMainTestClass):
|
|
301
284
|
else:
|
302
285
|
# if it's loadMarkets, then fail test, because it's mandatory for tests
|
303
286
|
if is_load_markets:
|
304
|
-
dump('[TEST_FAILURE]', 'Exchange can not load markets', exception_message(e),
|
287
|
+
dump('[TEST_FAILURE]', 'Exchange can not load markets', exception_message(e), exchange.id, method_name, args_stringified)
|
305
288
|
return False
|
306
289
|
# if the specific arguments to the test method throws "NotSupported" exception
|
307
290
|
# then let's don't fail the test
|
308
291
|
if is_not_supported:
|
309
292
|
if self.info:
|
310
|
-
dump('[INFO] NOT_SUPPORTED', exception_message(e),
|
293
|
+
dump('[INFO] NOT_SUPPORTED', exception_message(e), exchange.id, method_name, args_stringified)
|
311
294
|
return True
|
312
295
|
# If public test faces authentication error, we don't break (see comments under `testSafe` method)
|
313
296
|
if is_public and is_auth_error:
|
314
297
|
if self.info:
|
315
|
-
dump('[INFO]', 'Authentication problem for public method', exception_message(e),
|
298
|
+
dump('[INFO]', 'Authentication problem for public method', exception_message(e), exchange.id, method_name, args_stringified)
|
316
299
|
return True
|
317
300
|
else:
|
318
|
-
dump('[TEST_FAILURE]', exception_message(e),
|
301
|
+
dump('[TEST_FAILURE]', exception_message(e), exchange.id, method_name, args_stringified)
|
319
302
|
return False
|
320
303
|
return True
|
321
304
|
|
@@ -381,9 +364,9 @@ class testMainClass(baseMainTestClass):
|
|
381
364
|
test_prefix_string = 'PUBLIC_TESTS' if is_public_test else 'PRIVATE_TESTS'
|
382
365
|
if len(failed_methods):
|
383
366
|
errors_string = ', '.join(failed_methods)
|
384
|
-
dump('[TEST_FAILURE]',
|
367
|
+
dump('[TEST_FAILURE]', exchange.id, test_prefix_string, 'Failed methods : ' + errors_string)
|
385
368
|
if self.info:
|
386
|
-
dump(self.add_padding('[INFO] END ' + test_prefix_string + ' ' +
|
369
|
+
dump(self.add_padding('[INFO] END ' + test_prefix_string + ' ' + exchange.id, 25))
|
387
370
|
|
388
371
|
def load_exchange(self, exchange):
|
389
372
|
result = self.test_safe('loadMarkets', exchange, [], True)
|
@@ -843,7 +826,7 @@ class testMainClass(baseMainTestClass):
|
|
843
826
|
self.assert_static_request_output(exchange, type, skip_keys, data['url'], request_url, call_output, output)
|
844
827
|
except Exception as e:
|
845
828
|
self.request_tests_failed = True
|
846
|
-
error_message = '[' + self.lang + '][STATIC_REQUEST_TEST_FAILURE]' + '[' +
|
829
|
+
error_message = '[' + self.lang + '][STATIC_REQUEST_TEST_FAILURE]' + '[' + exchange.id + ']' + '[' + method + ']' + '[' + data['description'] + ']' + str(e)
|
847
830
|
dump('[TEST_FAILURE]' + error_message)
|
848
831
|
|
849
832
|
def test_response_statically(self, exchange, method, skip_keys, data):
|
@@ -858,7 +841,7 @@ class testMainClass(baseMainTestClass):
|
|
858
841
|
self.assert_static_response_output(mocked_exchange, skip_keys, unified_result_sync, expected_result)
|
859
842
|
except Exception as e:
|
860
843
|
self.response_tests_failed = True
|
861
|
-
error_message = '[' + self.lang + '][STATIC_RESPONSE_TEST_FAILURE]' + '[' +
|
844
|
+
error_message = '[' + self.lang + '][STATIC_RESPONSE_TEST_FAILURE]' + '[' + exchange.id + ']' + '[' + method + ']' + '[' + data['description'] + ']' + str(e)
|
862
845
|
dump('[TEST_FAILURE]' + error_message)
|
863
846
|
set_fetch_response(exchange, None) # reset state
|
864
847
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: ccxt
|
3
|
-
Version: 4.3.
|
3
|
+
Version: 4.3.86
|
4
4
|
Summary: A JavaScript / TypeScript / Python / C# / PHP cryptocurrency trading library with support for 100+ exchanges
|
5
5
|
Home-page: https://ccxt.com
|
6
6
|
Author: Igor Kroitor
|
@@ -50,7 +50,7 @@ Requires-Dist: mypy (==1.6.1) ; extra == 'type'
|
|
50
50
|
|
51
51
|
# CCXT – CryptoCurrency eXchange Trading Library
|
52
52
|
|
53
|
-
[](https://travis-ci.com/ccxt/ccxt) [](https://npmjs.com/package/ccxt) [](https://pypi.python.org/pypi/ccxt) [](https://www.npmjs.com/package/ccxt) [](https://discord.gg/ccxt) [](https://travis-ci.com/ccxt/ccxt) [](https://npmjs.com/package/ccxt) [](https://pypi.python.org/pypi/ccxt) [](https://www.npmjs.com/package/ccxt) [](https://discord.gg/ccxt) [](https://github.com/ccxt/ccxt/wiki/Exchange-Markets) [](https://twitter.com/ccxt_official)
|
54
54
|
|
55
55
|
A JavaScript / Python / PHP / C# library for cryptocurrency trading and e-commerce with support for many bitcoin/ether/altcoin exchange markets and merchant APIs.
|
56
56
|
|
@@ -96,6 +96,7 @@ Current feature list:
|
|
96
96
|
| [](https://www.coinex.com/register?refer_code=yw5fz) | coinex | [CoinEx](https://www.coinex.com/register?refer_code=yw5fz) | [](https://docs.coinex.com/api/v2) | cex | [](https://github.com/ccxt/ccxt/wiki/Certification) | [](https://ccxt.pro) | |
|
97
97
|
| [](https://crypto.com/exch/kdacthrnxt) | cryptocom | [Crypto.com](https://crypto.com/exch/kdacthrnxt) | [](https://exchange-docs.crypto.com/exchange/v1/rest-ws/index.html) | cex | [](https://github.com/ccxt/ccxt/wiki/Certification) | [](https://ccxt.pro) | [](https://crypto.com/exch/kdacthrnxt) |
|
98
98
|
| [](https://www.gate.io/signup/2436035) | gate | [Gate.io](https://www.gate.io/signup/2436035) | [](https://www.gate.io/docs/developers/apiv4/en/) | cex | [](https://github.com/ccxt/ccxt/wiki/Certification) | [](https://ccxt.pro) | [](https://www.gate.io/signup/2436035) |
|
99
|
+
| [](https://global.hashkey.com/) | hashkey | [HashKey Global](https://global.hashkey.com/) | [](https://hashkeyglobal-apidoc.readme.io/) | cex | [](https://github.com/ccxt/ccxt/wiki/Certification) | [](https://ccxt.pro) | |
|
99
100
|
| [](https://www.huobi.com/en-us/v/register/double-invite/?inviter_id=11343840&invite_code=6rmm2223) | htx | [HTX](https://www.huobi.com/en-us/v/register/double-invite/?inviter_id=11343840&invite_code=6rmm2223) | [](https://huobiapi.github.io/docs/spot/v1/en/) | cex | [](https://github.com/ccxt/ccxt/wiki/Certification) | [](https://ccxt.pro) | [](https://www.huobi.com/en-us/v/register/double-invite/?inviter_id=11343840&invite_code=6rmm2223) |
|
100
101
|
| [](https://www.kucoin.com/ucenter/signup?rcode=E5wkqe) | kucoin | [KuCoin](https://www.kucoin.com/ucenter/signup?rcode=E5wkqe) | [](https://docs.kucoin.com) | cex | [](https://github.com/ccxt/ccxt/wiki/Certification) | [](https://ccxt.pro) | |
|
101
102
|
| [](https://futures.kucoin.com/?rcode=E5wkqe) | kucoinfutures | [KuCoin Futures](https://futures.kucoin.com/?rcode=E5wkqe) | [](https://docs.kucoin.com/futures) | cex | [](https://github.com/ccxt/ccxt/wiki/Certification) | [](https://ccxt.pro) | |
|
@@ -106,7 +107,7 @@ Current feature list:
|
|
106
107
|
|
107
108
|
## Supported Cryptocurrency Exchanges
|
108
109
|
|
109
|
-
The CCXT library currently supports the following
|
110
|
+
The CCXT library currently supports the following 103 cryptocurrency exchange markets and trading APIs:
|
110
111
|
|
111
112
|
| logo | id | name | ver | type | certified | pro |
|
112
113
|
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------|-------------------------------------------------------------------------------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------:|------|-----------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------|
|
@@ -165,6 +166,7 @@ The CCXT library currently supports the following 102 cryptocurrency exchange ma
|
|
165
166
|
| [](https://fmfw.io/referral/da948b21d6c92d69) | fmfwio | [FMFW.io](https://fmfw.io/referral/da948b21d6c92d69) | [](https://api.fmfw.io/) | cex | | |
|
166
167
|
| [](https://www.gate.io/signup/2436035) | gate | [Gate.io](https://www.gate.io/signup/2436035) | [](https://www.gate.io/docs/developers/apiv4/en/) | cex | [](https://github.com/ccxt/ccxt/wiki/Certification) | [](https://ccxt.pro) |
|
167
168
|
| [](https://gemini.com/) | gemini | [Gemini](https://gemini.com/) | [](https://docs.gemini.com/rest-api) | cex | | [](https://ccxt.pro) |
|
169
|
+
| [](https://global.hashkey.com/) | hashkey | [HashKey Global](https://global.hashkey.com/) | [](https://hashkeyglobal-apidoc.readme.io/) | cex | [](https://github.com/ccxt/ccxt/wiki/Certification) | [](https://ccxt.pro) |
|
168
170
|
| [](https://hitbtc.com/?ref_id=5a5d39a65d466) | hitbtc | [HitBTC](https://hitbtc.com/?ref_id=5a5d39a65d466) | [](https://api.hitbtc.com) | cex | | |
|
169
171
|
| [](https://pro.hollaex.com/signup?affiliation_code=QSWA6G) | hollaex | [HollaEx](https://pro.hollaex.com/signup?affiliation_code=QSWA6G) | [](https://apidocs.hollaex.com) | cex | | [](https://ccxt.pro) |
|
170
172
|
| [](https://www.huobi.com/en-us/v/register/double-invite/?inviter_id=11343840&invite_code=6rmm2223) | htx | [HTX](https://www.huobi.com/en-us/v/register/double-invite/?inviter_id=11343840&invite_code=6rmm2223) | [](https://huobiapi.github.io/docs/spot/v1/en/) | cex | [](https://github.com/ccxt/ccxt/wiki/Certification) | [](https://ccxt.pro) |
|
@@ -269,13 +271,13 @@ console.log(version, Object.keys(exchanges));
|
|
269
271
|
|
270
272
|
All-in-one browser bundle (dependencies included), served from a CDN of your choice:
|
271
273
|
|
272
|
-
* jsDelivr: https://cdn.jsdelivr.net/npm/ccxt@4.3.
|
273
|
-
* unpkg: https://unpkg.com/ccxt@4.3.
|
274
|
+
* jsDelivr: https://cdn.jsdelivr.net/npm/ccxt@4.3.86/dist/ccxt.browser.min.js
|
275
|
+
* unpkg: https://unpkg.com/ccxt@4.3.86/dist/ccxt.browser.min.js
|
274
276
|
|
275
277
|
CDNs are not updated in real-time and may have delays. Defaulting to the most recent version without specifying the version number is not recommended. Please, keep in mind that we are not responsible for the correct operation of those CDN servers.
|
276
278
|
|
277
279
|
```HTML
|
278
|
-
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ccxt@4.3.
|
280
|
+
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ccxt@4.3.86/dist/ccxt.browser.min.js"></script>
|
279
281
|
```
|
280
282
|
|
281
283
|
Creates a global `ccxt` object:
|