ccxt 4.3.85__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/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://mxcdevelop.github.io/apidocs/spot_v3_en/#kline-streams
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://mxcdevelop.github.io/apidocs/spot_v3_en/#diff-depth-stream
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://mxcdevelop.github.io/apidocs/spot_v3_en/#trade-streams
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://mxcdevelop.github.io/apidocs/spot_v3_en/#spot-account-deals
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://mxcdevelop.github.io/apidocs/spot_v3_en/#spot-account-orders
717
- :see: https://mxcdevelop.github.io/apidocs/spot_v3_en/#margin-account-orders
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://mxcdevelop.github.io/apidocs/spot_v3_en/#spot-account-upadte
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/woo.py CHANGED
@@ -28,6 +28,7 @@ class woo(ccxt.async_support.woo):
28
28
  'watchTicker': True,
29
29
  'watchTickers': True,
30
30
  'watchTrades': True,
31
+ 'watchTradesForSymbols': False,
31
32
  'watchPositions': True,
32
33
  },
33
34
  'urls': {
ccxt/pro/woofipro.py CHANGED
@@ -27,6 +27,7 @@ class woofipro(ccxt.async_support.woofipro):
27
27
  'watchTicker': True,
28
28
  'watchTickers': True,
29
29
  'watchTrades': True,
30
+ 'watchTradesForSymbols': False,
30
31
  'watchPositions': True,
31
32
  },
32
33
  'urls': {
ccxt/pro/xt.py CHANGED
@@ -21,6 +21,7 @@ class xt(ccxt.async_support.xt):
21
21
  'watchTicker': True,
22
22
  'watchTickers': True,
23
23
  'watchTrades': True,
24
+ 'watchTradesForSymbols': False,
24
25
  'watchBalance': True,
25
26
  'watchOrders': True,
26
27
  'watchMyTrades': True,
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), self.exchange_hint(exchange), method_name)
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), self.exchange_hint(exchange), method_name, args_stringified)
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), self.exchange_hint(exchange), method_name)
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', ' | ', self.exchange_hint(exchange), method_name, args_stringified, exception_message(e))
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), self.exchange_hint(exchange), method_name, args_stringified)
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), self.exchange_hint(exchange), method_name, args_stringified)
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), self.exchange_hint(exchange), method_name, args_stringified)
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), self.exchange_hint(exchange), method_name, args_stringified)
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]', self.exchange_hint(exchange), test_prefix_string, 'Failed methods : ' + errors_string)
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 + ' ' + self.exchange_hint(exchange), 25))
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]' + '[' + self.exchange_hint(exchange) + ']' + '[' + method + ']' + '[' + data['description'] + ']' + str(e)
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]' + '[' + self.exchange_hint(exchange) + ']' + '[' + method + ']' + '[' + data['description'] + ']' + str(e)
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), self.exchange_hint(exchange), method_name)
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), self.exchange_hint(exchange), method_name, args_stringified)
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), self.exchange_hint(exchange), method_name)
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', ' | ', self.exchange_hint(exchange), method_name, args_stringified, exception_message(e))
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), self.exchange_hint(exchange), method_name, args_stringified)
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), self.exchange_hint(exchange), method_name, args_stringified)
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), self.exchange_hint(exchange), method_name, args_stringified)
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), self.exchange_hint(exchange), method_name, args_stringified)
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]', self.exchange_hint(exchange), test_prefix_string, 'Failed methods : ' + errors_string)
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 + ' ' + self.exchange_hint(exchange), 25))
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]' + '[' + self.exchange_hint(exchange) + ']' + '[' + method + ']' + '[' + data['description'] + ']' + str(e)
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]' + '[' + self.exchange_hint(exchange) + ']' + '[' + method + ']' + '[' + data['description'] + ']' + str(e)
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.85
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
- [![Build Status](https://img.shields.io/travis/com/ccxt/ccxt)](https://travis-ci.com/ccxt/ccxt) [![npm](https://img.shields.io/npm/v/ccxt.svg)](https://npmjs.com/package/ccxt) [![PyPI](https://img.shields.io/pypi/v/ccxt.svg)](https://pypi.python.org/pypi/ccxt) [![NPM Downloads](https://img.shields.io/npm/dy/ccxt.svg)](https://www.npmjs.com/package/ccxt) [![Discord](https://img.shields.io/discord/690203284119617602?logo=discord&logoColor=white)](https://discord.gg/ccxt) [![Supported Exchanges](https://img.shields.io/badge/exchanges-109-blue.svg)](https://github.com/ccxt/ccxt/wiki/Exchange-Markets) [![Twitter Follow](https://img.shields.io/twitter/follow/ccxt_official.svg?style=social&label=CCXT)](https://twitter.com/ccxt_official)
53
+ [![Build Status](https://img.shields.io/travis/com/ccxt/ccxt)](https://travis-ci.com/ccxt/ccxt) [![npm](https://img.shields.io/npm/v/ccxt.svg)](https://npmjs.com/package/ccxt) [![PyPI](https://img.shields.io/pypi/v/ccxt.svg)](https://pypi.python.org/pypi/ccxt) [![NPM Downloads](https://img.shields.io/npm/dy/ccxt.svg)](https://www.npmjs.com/package/ccxt) [![Discord](https://img.shields.io/discord/690203284119617602?logo=discord&logoColor=white)](https://discord.gg/ccxt) [![Supported Exchanges](https://img.shields.io/badge/exchanges-110-blue.svg)](https://github.com/ccxt/ccxt/wiki/Exchange-Markets) [![Twitter Follow](https://img.shields.io/twitter/follow/ccxt_official.svg?style=social&label=CCXT)](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
  | [![coinex](https://user-images.githubusercontent.com/51840849/87182089-1e05fa00-c2ec-11ea-8da9-cc73b45abbbc.jpg)](https://www.coinex.com/register?refer_code=yw5fz) | coinex | [CoinEx](https://www.coinex.com/register?refer_code=yw5fz) | [![API Version 2](https://img.shields.io/badge/2-lightgray)](https://docs.coinex.com/api/v2) | cex | [![CCXT Certified](https://img.shields.io/badge/CCXT-Certified-green.svg)](https://github.com/ccxt/ccxt/wiki/Certification) | [![CCXT Pro](https://img.shields.io/badge/CCXT-Pro-black)](https://ccxt.pro) | |
97
97
  | [![cryptocom](https://user-images.githubusercontent.com/1294454/147792121-38ed5e36-c229-48d6-b49a-48d05fc19ed4.jpeg)](https://crypto.com/exch/kdacthrnxt) | cryptocom | [Crypto.com](https://crypto.com/exch/kdacthrnxt) | [![API Version 2](https://img.shields.io/badge/2-lightgray)](https://exchange-docs.crypto.com/exchange/v1/rest-ws/index.html) | cex | [![CCXT Certified](https://img.shields.io/badge/CCXT-Certified-green.svg)](https://github.com/ccxt/ccxt/wiki/Certification) | [![CCXT Pro](https://img.shields.io/badge/CCXT-Pro-black)](https://ccxt.pro) | [![Sign up with Crypto.com using CCXT's referral link for a 15% discount!](https://img.shields.io/static/v1?label=Fee&message=%2d15%25&color=orange)](https://crypto.com/exch/kdacthrnxt) |
98
98
  | [![gate](https://user-images.githubusercontent.com/1294454/31784029-0313c702-b509-11e7-9ccc-bc0da6a0e435.jpg)](https://www.gate.io/signup/2436035) | gate | [Gate.io](https://www.gate.io/signup/2436035) | [![API Version 4](https://img.shields.io/badge/4-lightgray)](https://www.gate.io/docs/developers/apiv4/en/) | cex | [![CCXT Certified](https://img.shields.io/badge/CCXT-Certified-green.svg)](https://github.com/ccxt/ccxt/wiki/Certification) | [![CCXT Pro](https://img.shields.io/badge/CCXT-Pro-black)](https://ccxt.pro) | [![Sign up with Gate.io using CCXT's referral link for a 20% discount!](https://img.shields.io/static/v1?label=Fee&message=%2d20%25&color=orange)](https://www.gate.io/signup/2436035) |
99
+ | [![hashkey](https://github.com/user-attachments/assets/6dd6127b-cc19-4a13-9b29-a98d81f80e98)](https://global.hashkey.com/) | hashkey | [HashKey Global](https://global.hashkey.com/) | [![API Version 1](https://img.shields.io/badge/1-lightgray)](https://hashkeyglobal-apidoc.readme.io/) | cex | [![CCXT Certified](https://img.shields.io/badge/CCXT-Certified-green.svg)](https://github.com/ccxt/ccxt/wiki/Certification) | [![CCXT Pro](https://img.shields.io/badge/CCXT-Pro-black)](https://ccxt.pro) | |
99
100
  | [![htx](https://user-images.githubusercontent.com/1294454/76137448-22748a80-604e-11ea-8069-6e389271911d.jpg)](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) | [![API Version 1](https://img.shields.io/badge/1-lightgray)](https://huobiapi.github.io/docs/spot/v1/en/) | cex | [![CCXT Certified](https://img.shields.io/badge/CCXT-Certified-green.svg)](https://github.com/ccxt/ccxt/wiki/Certification) | [![CCXT Pro](https://img.shields.io/badge/CCXT-Pro-black)](https://ccxt.pro) | [![Sign up with HTX using CCXT's referral link for a 15% discount!](https://img.shields.io/static/v1?label=Fee&message=%2d15%25&color=orange)](https://www.huobi.com/en-us/v/register/double-invite/?inviter_id=11343840&invite_code=6rmm2223) |
100
101
  | [![kucoin](https://user-images.githubusercontent.com/51840849/87295558-132aaf80-c50e-11ea-9801-a2fb0c57c799.jpg)](https://www.kucoin.com/ucenter/signup?rcode=E5wkqe) | kucoin | [KuCoin](https://www.kucoin.com/ucenter/signup?rcode=E5wkqe) | [![API Version 2](https://img.shields.io/badge/2-lightgray)](https://docs.kucoin.com) | cex | [![CCXT Certified](https://img.shields.io/badge/CCXT-Certified-green.svg)](https://github.com/ccxt/ccxt/wiki/Certification) | [![CCXT Pro](https://img.shields.io/badge/CCXT-Pro-black)](https://ccxt.pro) | |
101
102
  | [![kucoinfutures](https://user-images.githubusercontent.com/1294454/147508995-9e35030a-d046-43a1-a006-6fabd981b554.jpg)](https://futures.kucoin.com/?rcode=E5wkqe) | kucoinfutures | [KuCoin Futures](https://futures.kucoin.com/?rcode=E5wkqe) | [![API Version 1](https://img.shields.io/badge/1-lightgray)](https://docs.kucoin.com/futures) | cex | [![CCXT Certified](https://img.shields.io/badge/CCXT-Certified-green.svg)](https://github.com/ccxt/ccxt/wiki/Certification) | [![CCXT Pro](https://img.shields.io/badge/CCXT-Pro-black)](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 102 cryptocurrency exchange markets and trading APIs:
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
  | [![fmfwio](https://user-images.githubusercontent.com/1294454/159177712-b685b40c-5269-4cea-ac83-f7894c49525d.jpg)](https://fmfw.io/referral/da948b21d6c92d69) | fmfwio | [FMFW.io](https://fmfw.io/referral/da948b21d6c92d69) | [![API Version 3](https://img.shields.io/badge/3-lightgray)](https://api.fmfw.io/) | cex | | |
166
167
  | [![gate](https://user-images.githubusercontent.com/1294454/31784029-0313c702-b509-11e7-9ccc-bc0da6a0e435.jpg)](https://www.gate.io/signup/2436035) | gate | [Gate.io](https://www.gate.io/signup/2436035) | [![API Version 4](https://img.shields.io/badge/4-lightgray)](https://www.gate.io/docs/developers/apiv4/en/) | cex | [![CCXT Certified](https://img.shields.io/badge/CCXT-Certified-green.svg)](https://github.com/ccxt/ccxt/wiki/Certification) | [![CCXT Pro](https://img.shields.io/badge/CCXT-Pro-black)](https://ccxt.pro) |
167
168
  | [![gemini](https://user-images.githubusercontent.com/1294454/27816857-ce7be644-6096-11e7-82d6-3c257263229c.jpg)](https://gemini.com/) | gemini | [Gemini](https://gemini.com/) | [![API Version 1](https://img.shields.io/badge/1-lightgray)](https://docs.gemini.com/rest-api) | cex | | [![CCXT Pro](https://img.shields.io/badge/CCXT-Pro-black)](https://ccxt.pro) |
169
+ | [![hashkey](https://github.com/user-attachments/assets/6dd6127b-cc19-4a13-9b29-a98d81f80e98)](https://global.hashkey.com/) | hashkey | [HashKey Global](https://global.hashkey.com/) | [![API Version 1](https://img.shields.io/badge/1-lightgray)](https://hashkeyglobal-apidoc.readme.io/) | cex | [![CCXT Certified](https://img.shields.io/badge/CCXT-Certified-green.svg)](https://github.com/ccxt/ccxt/wiki/Certification) | [![CCXT Pro](https://img.shields.io/badge/CCXT-Pro-black)](https://ccxt.pro) |
168
170
  | [![hitbtc](https://user-images.githubusercontent.com/1294454/27766555-8eaec20e-5edc-11e7-9c5b-6dc69fc42f5e.jpg)](https://hitbtc.com/?ref_id=5a5d39a65d466) | hitbtc | [HitBTC](https://hitbtc.com/?ref_id=5a5d39a65d466) | [![API Version 3](https://img.shields.io/badge/3-lightgray)](https://api.hitbtc.com) | cex | | |
169
171
  | [![hollaex](https://user-images.githubusercontent.com/1294454/75841031-ca375180-5ddd-11ea-8417-b975674c23cb.jpg)](https://pro.hollaex.com/signup?affiliation_code=QSWA6G) | hollaex | [HollaEx](https://pro.hollaex.com/signup?affiliation_code=QSWA6G) | [![API Version 2](https://img.shields.io/badge/2-lightgray)](https://apidocs.hollaex.com) | cex | | [![CCXT Pro](https://img.shields.io/badge/CCXT-Pro-black)](https://ccxt.pro) |
170
172
  | [![htx](https://user-images.githubusercontent.com/1294454/76137448-22748a80-604e-11ea-8069-6e389271911d.jpg)](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) | [![API Version 1](https://img.shields.io/badge/1-lightgray)](https://huobiapi.github.io/docs/spot/v1/en/) | cex | [![CCXT Certified](https://img.shields.io/badge/CCXT-Certified-green.svg)](https://github.com/ccxt/ccxt/wiki/Certification) | [![CCXT Pro](https://img.shields.io/badge/CCXT-Pro-black)](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.85/dist/ccxt.browser.min.js
273
- * unpkg: https://unpkg.com/ccxt@4.3.85/dist/ccxt.browser.min.js
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.85/dist/ccxt.browser.min.js"></script>
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: