ccxt 4.3.85__py2.py3-none-any.whl → 4.3.87__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. ccxt/__init__.py +4 -1
  2. ccxt/abstract/hashkey.py +67 -0
  3. ccxt/async_support/__init__.py +4 -1
  4. ccxt/async_support/base/exchange.py +2 -2
  5. ccxt/async_support/binance.py +4 -2
  6. ccxt/async_support/bingx.py +5 -1
  7. ccxt/async_support/bitfinex.py +2 -2
  8. ccxt/async_support/hashkey.py +4061 -0
  9. ccxt/async_support/hyperliquid.py +80 -62
  10. ccxt/async_support/indodax.py +29 -8
  11. ccxt/async_support/kraken.py +32 -5
  12. ccxt/async_support/krakenfutures.py +10 -9
  13. ccxt/async_support/upbit.py +1 -1
  14. ccxt/base/errors.py +7 -1
  15. ccxt/base/exchange.py +2 -2
  16. ccxt/binance.py +4 -2
  17. ccxt/bingx.py +5 -1
  18. ccxt/bitfinex.py +2 -2
  19. ccxt/hashkey.py +4061 -0
  20. ccxt/hyperliquid.py +80 -62
  21. ccxt/indodax.py +29 -8
  22. ccxt/kraken.py +32 -5
  23. ccxt/krakenfutures.py +10 -9
  24. ccxt/pro/__init__.py +3 -1
  25. ccxt/pro/ascendex.py +41 -5
  26. ccxt/pro/bingx.py +13 -12
  27. ccxt/pro/bitget.py +143 -16
  28. ccxt/pro/hashkey.py +783 -0
  29. ccxt/pro/hyperliquid.py +118 -1
  30. ccxt/pro/mexc.py +13 -7
  31. ccxt/pro/p2b.py +30 -7
  32. ccxt/pro/poloniex.py +32 -3
  33. ccxt/pro/poloniexfutures.py +1 -0
  34. ccxt/pro/probit.py +2 -0
  35. ccxt/pro/upbit.py +44 -3
  36. ccxt/pro/vertex.py +1 -0
  37. ccxt/pro/wazirx.py +3 -0
  38. ccxt/pro/whitebit.py +9 -0
  39. ccxt/pro/woo.py +1 -0
  40. ccxt/pro/woofipro.py +1 -0
  41. ccxt/pro/xt.py +1 -0
  42. ccxt/test/tests_async.py +31 -31
  43. ccxt/test/tests_sync.py +31 -31
  44. ccxt/upbit.py +1 -1
  45. {ccxt-4.3.85.dist-info → ccxt-4.3.87.dist-info}/METADATA +9 -6
  46. {ccxt-4.3.85.dist-info → ccxt-4.3.87.dist-info}/RECORD +49 -45
  47. {ccxt-4.3.85.dist-info → ccxt-4.3.87.dist-info}/LICENSE.txt +0 -0
  48. {ccxt-4.3.85.dist-info → ccxt-4.3.87.dist-info}/WHEEL +0 -0
  49. {ccxt-4.3.85.dist-info → ccxt-4.3.87.dist-info}/top_level.txt +0 -0
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
 
@@ -937,6 +920,9 @@ class testMainClass(baseMainTestClass):
937
920
  is_disabled = exchange.safe_bool(result, 'disabled', False)
938
921
  if is_disabled:
939
922
  continue
923
+ is_disabled_c_sharp = exchange.safe_bool(result, 'disabledCS', False)
924
+ if is_disabled_c_sharp and (self.lang == 'C#'):
925
+ continue
940
926
  type = exchange.safe_string(exchange_data, 'outputType')
941
927
  skip_keys = exchange.safe_value(exchange_data, 'skipKeys', [])
942
928
  await self.test_request_statically(exchange, method, result, type, skip_keys)
@@ -1053,7 +1039,7 @@ class testMainClass(baseMainTestClass):
1053
1039
  # -----------------------------------------------------------------------------
1054
1040
  # --- Init of brokerId tests functions-----------------------------------------
1055
1041
  # -----------------------------------------------------------------------------
1056
- promises = [self.test_binance(), self.test_okx(), self.test_cryptocom(), self.test_bybit(), self.test_kucoin(), self.test_kucoinfutures(), self.test_bitget(), self.test_mexc(), self.test_htx(), self.test_woo(), self.test_bitmart(), self.test_coinex(), self.test_bingx(), self.test_phemex(), self.test_blofin(), self.test_hyperliquid(), self.test_coinbaseinternational(), self.test_coinbase_advanced(), self.test_woofi_pro(), self.test_oxfun(), self.test_xt(), self.test_vertex(), self.test_paradex()]
1042
+ promises = [self.test_binance(), self.test_okx(), self.test_cryptocom(), self.test_bybit(), self.test_kucoin(), self.test_kucoinfutures(), self.test_bitget(), self.test_mexc(), self.test_htx(), self.test_woo(), self.test_bitmart(), self.test_coinex(), self.test_bingx(), self.test_phemex(), self.test_blofin(), self.test_hyperliquid(), self.test_coinbaseinternational(), self.test_coinbase_advanced(), self.test_woofi_pro(), self.test_oxfun(), self.test_xt(), self.test_vertex(), self.test_paradex(), self.test_hashkey()]
1057
1043
  await asyncio.gather(*promises)
1058
1044
  success_message = '[' + self.lang + '][TEST_SUCCESS] brokerId tests passed.'
1059
1045
  dump('[INFO]' + success_message)
@@ -1501,3 +1487,17 @@ class testMainClass(baseMainTestClass):
1501
1487
  if not self.is_synchronous:
1502
1488
  await close(exchange)
1503
1489
  return True
1490
+
1491
+ async def test_hashkey(self):
1492
+ exchange = self.init_offline_exchange('hashkey')
1493
+ req_headers = None
1494
+ id = '10000700011'
1495
+ try:
1496
+ await exchange.create_order('BTC/USDT', 'limit', 'buy', 1, 20000)
1497
+ except Exception as e:
1498
+ # we expect an error here, we're only interested in the headers
1499
+ req_headers = exchange.last_request_headers
1500
+ assert req_headers['INPUT-SOURCE'] == id, 'hashkey - id: ' + id + ' not in headers.'
1501
+ if not self.is_synchronous:
1502
+ await close(exchange)
1503
+ return True
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
 
@@ -934,6 +917,9 @@ class testMainClass(baseMainTestClass):
934
917
  is_disabled = exchange.safe_bool(result, 'disabled', False)
935
918
  if is_disabled:
936
919
  continue
920
+ is_disabled_c_sharp = exchange.safe_bool(result, 'disabledCS', False)
921
+ if is_disabled_c_sharp and (self.lang == 'C#'):
922
+ continue
937
923
  type = exchange.safe_string(exchange_data, 'outputType')
938
924
  skip_keys = exchange.safe_value(exchange_data, 'skipKeys', [])
939
925
  self.test_request_statically(exchange, method, result, type, skip_keys)
@@ -1050,7 +1036,7 @@ class testMainClass(baseMainTestClass):
1050
1036
  # -----------------------------------------------------------------------------
1051
1037
  # --- Init of brokerId tests functions-----------------------------------------
1052
1038
  # -----------------------------------------------------------------------------
1053
- promises = [self.test_binance(), self.test_okx(), self.test_cryptocom(), self.test_bybit(), self.test_kucoin(), self.test_kucoinfutures(), self.test_bitget(), self.test_mexc(), self.test_htx(), self.test_woo(), self.test_bitmart(), self.test_coinex(), self.test_bingx(), self.test_phemex(), self.test_blofin(), self.test_hyperliquid(), self.test_coinbaseinternational(), self.test_coinbase_advanced(), self.test_woofi_pro(), self.test_oxfun(), self.test_xt(), self.test_vertex(), self.test_paradex()]
1039
+ promises = [self.test_binance(), self.test_okx(), self.test_cryptocom(), self.test_bybit(), self.test_kucoin(), self.test_kucoinfutures(), self.test_bitget(), self.test_mexc(), self.test_htx(), self.test_woo(), self.test_bitmart(), self.test_coinex(), self.test_bingx(), self.test_phemex(), self.test_blofin(), self.test_hyperliquid(), self.test_coinbaseinternational(), self.test_coinbase_advanced(), self.test_woofi_pro(), self.test_oxfun(), self.test_xt(), self.test_vertex(), self.test_paradex(), self.test_hashkey()]
1054
1040
  (promises)
1055
1041
  success_message = '[' + self.lang + '][TEST_SUCCESS] brokerId tests passed.'
1056
1042
  dump('[INFO]' + success_message)
@@ -1498,3 +1484,17 @@ class testMainClass(baseMainTestClass):
1498
1484
  if not self.is_synchronous:
1499
1485
  close(exchange)
1500
1486
  return True
1487
+
1488
+ def test_hashkey(self):
1489
+ exchange = self.init_offline_exchange('hashkey')
1490
+ req_headers = None
1491
+ id = '10000700011'
1492
+ try:
1493
+ exchange.create_order('BTC/USDT', 'limit', 'buy', 1, 20000)
1494
+ except Exception as e:
1495
+ # we expect an error here, we're only interested in the headers
1496
+ req_headers = exchange.last_request_headers
1497
+ assert req_headers['INPUT-SOURCE'] == id, 'hashkey - id: ' + id + ' not in headers.'
1498
+ if not self.is_synchronous:
1499
+ close(exchange)
1500
+ return True
ccxt/upbit.py CHANGED
@@ -1891,7 +1891,7 @@ class upbit(Exchange, ImplicitAPI):
1891
1891
  body = self.json(params)
1892
1892
  headers['Content-Type'] = 'application/json'
1893
1893
  if hasQuery:
1894
- auth = self.urlencode(query)
1894
+ auth = self.rawencode(query)
1895
1895
  if auth is not None:
1896
1896
  hash = self.hash(self.encode(auth), 'sha512')
1897
1897
  request['query_hash'] = hash
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ccxt
3
- Version: 4.3.85
3
+ Version: 4.3.87
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
 
@@ -70,6 +70,7 @@ Current feature list:
70
70
 
71
71
 
72
72
  ## Sponsored Promotion
73
+ [![hashkey-campaign](https://github.com/user-attachments/assets/1622ba7d-637d-41e3-9ad4-d61a6ea69881)](https://support.global.hashkey.com/hc/en-us/articles/15485543021468-Trade-Through-CCXT-to-Grab-up-to-1-000-USDT-30-Day-VIP5-Trial)
73
74
 
74
75
  ## See Also
75
76
 
@@ -96,6 +97,7 @@ Current feature list:
96
97
  | [![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
98
  | [![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
99
  | [![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) |
100
+ | [![hashkey](https://github.com/user-attachments/assets/6dd6127b-cc19-4a13-9b29-a98d81f80e98)](https://global.hashkey.com/en-US/register/invite?invite_code=82FQUN) | hashkey | [HashKey Global](https://global.hashkey.com/en-US/register/invite?invite_code=82FQUN) | [![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
101
  | [![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
102
  | [![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
103
  | [![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 +108,7 @@ Current feature list:
106
108
 
107
109
  ## Supported Cryptocurrency Exchanges
108
110
 
109
- The CCXT library currently supports the following 102 cryptocurrency exchange markets and trading APIs:
111
+ The CCXT library currently supports the following 103 cryptocurrency exchange markets and trading APIs:
110
112
 
111
113
  | logo | id | name | ver | type | certified | pro |
112
114
  |---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------|-------------------------------------------------------------------------------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------:|------|-----------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------|
@@ -165,6 +167,7 @@ The CCXT library currently supports the following 102 cryptocurrency exchange ma
165
167
  | [![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
168
  | [![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
169
  | [![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) |
170
+ | [![hashkey](https://github.com/user-attachments/assets/6dd6127b-cc19-4a13-9b29-a98d81f80e98)](https://global.hashkey.com/en-US/register/invite?invite_code=82FQUN) | hashkey | [HashKey Global](https://global.hashkey.com/en-US/register/invite?invite_code=82FQUN) | [![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
171
  | [![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
172
  | [![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
173
  | [![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 +272,13 @@ console.log(version, Object.keys(exchanges));
269
272
 
270
273
  All-in-one browser bundle (dependencies included), served from a CDN of your choice:
271
274
 
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
275
+ * jsDelivr: https://cdn.jsdelivr.net/npm/ccxt@4.3.87/dist/ccxt.browser.min.js
276
+ * unpkg: https://unpkg.com/ccxt@4.3.87/dist/ccxt.browser.min.js
274
277
 
275
278
  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
279
 
277
280
  ```HTML
278
- <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ccxt@4.3.85/dist/ccxt.browser.min.js"></script>
281
+ <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ccxt@4.3.87/dist/ccxt.browser.min.js"></script>
279
282
  ```
280
283
 
281
284
  Creates a global `ccxt` object: