ccxt 4.2.78__py2.py3-none-any.whl → 4.2.80__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 (58) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/abstract/bingx.py +1 -0
  3. ccxt/abstract/gate.py +1 -0
  4. ccxt/abstract/gateio.py +1 -0
  5. ccxt/abstract/upbit.py +1 -0
  6. ccxt/async_support/__init__.py +1 -1
  7. ccxt/async_support/base/exchange.py +10 -1
  8. ccxt/async_support/base/ws/functions.py +1 -1
  9. ccxt/async_support/binance.py +3 -3
  10. ccxt/async_support/bingx.py +37 -5
  11. ccxt/async_support/bitstamp.py +20 -26
  12. ccxt/async_support/bybit.py +92 -0
  13. ccxt/async_support/coinbaseinternational.py +2 -2
  14. ccxt/async_support/deribit.py +152 -1
  15. ccxt/async_support/gate.py +11 -4
  16. ccxt/async_support/hyperliquid.py +42 -9
  17. ccxt/async_support/mexc.py +2 -2
  18. ccxt/async_support/upbit.py +2 -0
  19. ccxt/base/exchange.py +38 -9
  20. ccxt/base/types.py +23 -0
  21. ccxt/binance.py +3 -3
  22. ccxt/bingx.py +37 -5
  23. ccxt/bitstamp.py +20 -26
  24. ccxt/bybit.py +92 -0
  25. ccxt/coinbaseinternational.py +2 -2
  26. ccxt/deribit.py +152 -1
  27. ccxt/gate.py +11 -4
  28. ccxt/hyperliquid.py +42 -9
  29. ccxt/mexc.py +2 -2
  30. ccxt/pro/__init__.py +1 -1
  31. ccxt/pro/alpaca.py +1 -1
  32. ccxt/pro/binance.py +5 -5
  33. ccxt/pro/bitfinex2.py +1 -1
  34. ccxt/pro/bitget.py +1 -1
  35. ccxt/pro/bitmart.py +1 -1
  36. ccxt/pro/bitmex.py +1 -1
  37. ccxt/pro/bitopro.py +2 -1
  38. ccxt/pro/blockchaincom.py +1 -1
  39. ccxt/pro/bybit.py +14 -1
  40. ccxt/pro/cex.py +9 -5
  41. ccxt/pro/cryptocom.py +1 -1
  42. ccxt/pro/gemini.py +4 -3
  43. ccxt/pro/hitbtc.py +1 -1
  44. ccxt/pro/htx.py +1 -1
  45. ccxt/pro/okcoin.py +1 -1
  46. ccxt/pro/onetrading.py +1 -1
  47. ccxt/pro/phemex.py +6 -1
  48. ccxt/pro/woo.py +30 -0
  49. ccxt/test/base/test_ohlcv.py +3 -2
  50. ccxt/test/base/test_shared_methods.py +8 -0
  51. ccxt/test/base/test_ticker.py +7 -1
  52. ccxt/test/test_async.py +26 -25
  53. ccxt/test/test_sync.py +26 -25
  54. ccxt/upbit.py +2 -0
  55. {ccxt-4.2.78.dist-info → ccxt-4.2.80.dist-info}/METADATA +6 -6
  56. {ccxt-4.2.78.dist-info → ccxt-4.2.80.dist-info}/RECORD +58 -58
  57. {ccxt-4.2.78.dist-info → ccxt-4.2.80.dist-info}/WHEEL +0 -0
  58. {ccxt-4.2.78.dist-info → ccxt-4.2.80.dist-info}/top_level.txt +0 -0
ccxt/pro/phemex.py CHANGED
@@ -27,6 +27,10 @@ class phemex(ccxt.async_support.phemex):
27
27
  'watchOrderBook': True,
28
28
  'watchOHLCV': True,
29
29
  'watchPositions': None, # TODO
30
+ # mutli-endpoints are not supported: https://github.com/ccxt/ccxt/pull/21490
31
+ 'watchOrderBookForSymbols': False,
32
+ 'watchTradesForSymbols': False,
33
+ 'watchOHLCVForSymbols': False,
30
34
  },
31
35
  'urls': {
32
36
  'test': {
@@ -536,9 +540,10 @@ class phemex(ccxt.async_support.phemex):
536
540
 
537
541
  async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
538
542
  """
543
+ :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Spot-API-en.md#subscribe-orderbook
539
544
  :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#subscribe-orderbook-for-new-model
540
545
  :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Contract-API-en.md#subscribe-30-levels-orderbook
541
- :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Spot-API-en.md#subscribe-orderbook
546
+ :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Contract-API-en.md#subscribe-full-orderbook
542
547
  watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
543
548
  :param str symbol: unified symbol of the market to fetch the order book for
544
549
  :param int [limit]: the maximum amount of order book entries to return
ccxt/pro/woo.py CHANGED
@@ -89,6 +89,13 @@ class woo(ccxt.async_support.woo):
89
89
  return await self.watch(url, messageHash, request, messageHash, subscribe)
90
90
 
91
91
  async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
92
+ """
93
+ watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
94
+ :param str symbol: unified symbol of the market to fetch the order book for
95
+ :param int [limit]: the maximum amount of order book entries to return.
96
+ :param dict [params]: extra parameters specific to the exchange API endpoint
97
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
98
+ """
92
99
  await self.load_markets()
93
100
  name = 'orderbook'
94
101
  market = self.market(symbol)
@@ -137,9 +144,16 @@ class woo(ccxt.async_support.woo):
137
144
  client.resolve(orderbook, topic)
138
145
 
139
146
  async def watch_ticker(self, symbol: str, params={}) -> Ticker:
147
+ """
148
+ watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
149
+ :param str symbol: unified symbol of the market to fetch the ticker for
150
+ :param dict [params]: extra parameters specific to the exchange API endpoint
151
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
152
+ """
140
153
  await self.load_markets()
141
154
  name = 'ticker'
142
155
  market = self.market(symbol)
156
+ symbol = market['symbol']
143
157
  topic = market['id'] + '@' + name
144
158
  request = {
145
159
  'event': 'subscribe',
@@ -214,7 +228,14 @@ class woo(ccxt.async_support.woo):
214
228
  return message
215
229
 
216
230
  async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
231
+ """
232
+ n watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
233
+ :param str[] symbols: unified symbol of the market to fetch the ticker for
234
+ :param dict [params]: extra parameters specific to the exchange API endpoint
235
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
236
+ """
217
237
  await self.load_markets()
238
+ symbols = self.market_symbols(symbols)
218
239
  name = 'tickers'
219
240
  topic = name
220
241
  request = {
@@ -329,8 +350,17 @@ class woo(ccxt.async_support.woo):
329
350
  client.resolve(stored, topic)
330
351
 
331
352
  async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
353
+ """
354
+ watches information on multiple trades made in a market
355
+ :param str symbol: unified market symbol of the market trades were made in
356
+ :param int [since]: the earliest time in ms to fetch trades for
357
+ :param int [limit]: the maximum number of trade structures to retrieve
358
+ :param dict [params]: extra parameters specific to the exchange API endpoint
359
+ :returns dict[]: a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure
360
+ """
332
361
  await self.load_markets()
333
362
  market = self.market(symbol)
363
+ symbol = market['symbol']
334
364
  topic = market['id'] + '@trade'
335
365
  request = {
336
366
  'event': 'subscribe',
@@ -21,8 +21,9 @@ def test_ohlcv(exchange, skipped_properties, method, entry, symbol, now):
21
21
  test_shared_methods.assert_timestamp_and_datetime(exchange, skipped_properties, method, entry, now, 0)
22
22
  log_text = test_shared_methods.log_template(exchange, method, entry)
23
23
  #
24
- length = len(entry)
25
- assert length >= 6, 'ohlcv array length should be >= 6;' + log_text
24
+ assert len(entry) >= 6, 'ohlcv array length should be >= 6;' + log_text
25
+ if not ('roundTimestamp' in skipped_properties):
26
+ test_shared_methods.assert_round_minute_timestamp(exchange, skipped_properties, method, entry, 0)
26
27
  high = exchange.safe_string(entry, 2)
27
28
  low = exchange.safe_string(entry, 3)
28
29
  test_shared_methods.assert_less_or_equal(exchange, skipped_properties, method, entry, '1', high)
@@ -343,3 +343,11 @@ def assert_non_emtpy_array(exchange, skipped_properties, method, entry, hint=Non
343
343
  if not ('emptyResponse' in skipped_properties):
344
344
  return
345
345
  assert len(entry) > 0, 'response is expected to be a non-empty array' + log_text + ' (add \"emptyResponse\" in skip-tests.json to skip this check)'
346
+
347
+
348
+ def assert_round_minute_timestamp(exchange, skipped_properties, method, entry, key):
349
+ if key in skipped_properties:
350
+ return
351
+ log_text = log_template(exchange, method, entry)
352
+ ts = exchange.safe_string(entry, key)
353
+ assert Precise.string_mod(ts, '60000') == '0', 'timestamp should be a multiple of 60 seconds (1 minute)' + log_text
@@ -39,7 +39,13 @@ def test_ticker(exchange, skipped_properties, method, entry, symbol):
39
39
  'quoteVolume': exchange.parse_number('1.234'),
40
40
  }
41
41
  # todo: atm, many exchanges fail, so temporarily decrease stict mode
42
- empty_allowed_for = ['timestamp', 'datetime', 'open', 'high', 'low', 'close', 'last', 'ask', 'bid', 'bidVolume', 'askVolume', 'baseVolume', 'quoteVolume', 'previousClose', 'vwap', 'change', 'percentage', 'average']
42
+ empty_allowed_for = ['timestamp', 'datetime', 'open', 'high', 'low', 'close', 'last', 'baseVolume', 'quoteVolume', 'previousClose', 'vwap', 'change', 'percentage', 'average']
43
+ # trick csharp-transpiler for string
44
+ if not 'BidsAsks' in str(method):
45
+ empty_allowed_for.append('bid')
46
+ empty_allowed_for.append('ask')
47
+ empty_allowed_for.append('bidVolume')
48
+ empty_allowed_for.append('askVolume')
43
49
  test_shared_methods.assert_structure(exchange, skipped_properties, method, entry, format, empty_allowed_for)
44
50
  test_shared_methods.assert_timestamp_and_datetime(exchange, skipped_properties, method, entry)
45
51
  log_text = test_shared_methods.log_template(exchange, method, entry)
ccxt/test/test_async.py CHANGED
@@ -129,6 +129,7 @@ class baseMainTestClass():
129
129
  response_tests = False
130
130
  ws_tests = False
131
131
  load_keys = False
132
+ skipped_settings_for_exchange = {}
132
133
  skipped_methods = {}
133
134
  check_public_tests = {}
134
135
  test_files = {}
@@ -378,7 +379,8 @@ class testMainClass(baseMainTestClass):
378
379
  # skipped tests
379
380
  skipped_file = self.root_dir_for_skips + 'skip-tests.json'
380
381
  skipped_settings = io_file_read(skipped_file)
381
- skipped_settings_for_exchange = exchange.safe_value(skipped_settings, exchange_id, {})
382
+ self.skipped_settings_for_exchange = exchange.safe_value(skipped_settings, exchange_id, {})
383
+ skipped_settings_for_exchange = self.skipped_settings_for_exchange
382
384
  # others
383
385
  timeout = exchange.safe_value(skipped_settings_for_exchange, 'timeout')
384
386
  if timeout is not None:
@@ -569,6 +571,7 @@ class testMainClass(baseMainTestClass):
569
571
  'watchOHLCV': [symbol],
570
572
  'watchTicker': [symbol],
571
573
  'watchTickers': [symbol],
574
+ 'watchBidsAsks': [symbol],
572
575
  'watchOrderBook': [symbol],
573
576
  'watchTrades': [symbol],
574
577
  }
@@ -615,26 +618,18 @@ class testMainClass(baseMainTestClass):
615
618
  result = await self.test_safe('loadMarkets', exchange, [], True)
616
619
  if not result:
617
620
  return False
618
- symbols = ['BTC/USDT', 'BTC/USDC', 'BTC/CNY', 'BTC/USD', 'BTC/EUR', 'BTC/ETH', 'ETH/BTC', 'BTC/JPY', 'ETH/EUR', 'ETH/JPY', 'ETH/CNY', 'ETH/USD', 'LTC/CNY', 'DASH/BTC', 'DOGE/BTC', 'BTC/AUD', 'BTC/PLN', 'USD/SLL', 'BTC/RUB', 'BTC/UAH', 'LTC/BTC', 'EUR/USD']
619
- result_symbols = []
620
- exchange_specific_symbols = exchange.symbols
621
- for i in range(0, len(exchange_specific_symbols)):
622
- symbol = exchange_specific_symbols[i]
623
- if exchange.in_array(symbol, symbols):
624
- result_symbols.append(symbol)
625
- result_msg = ''
626
- result_length = len(result_symbols)
627
621
  exchange_symbols_length = len(exchange.symbols)
628
- if result_length > 0:
629
- if exchange_symbols_length > result_length:
630
- result_msg = ', '.join(result_symbols) + ' + more...'
631
- else:
632
- result_msg = ', '.join(result_symbols)
633
- dump('[INFO:MAIN] Exchange loaded', exchange_symbols_length, 'symbols', result_msg)
622
+ dump('[INFO:MAIN] Exchange loaded', exchange_symbols_length, 'symbols')
634
623
  return True
635
624
 
636
625
  def get_test_symbol(self, exchange, is_spot, symbols):
637
626
  symbol = None
627
+ preferred_spot_symbol = exchange.safe_string(self.skipped_settings_for_exchange, 'preferredSpotSymbol')
628
+ preferred_swap_symbol = exchange.safe_string(self.skipped_settings_for_exchange, 'preferredSwapSymbol')
629
+ if is_spot and preferred_spot_symbol:
630
+ return preferred_spot_symbol
631
+ elif not is_spot and preferred_swap_symbol:
632
+ return preferred_swap_symbol
638
633
  for i in range(0, len(symbols)):
639
634
  s = symbols[i]
640
635
  market = exchange.safe_value(exchange.markets, s)
@@ -669,9 +664,9 @@ class testMainClass(baseMainTestClass):
669
664
 
670
665
  def get_valid_symbol(self, exchange, spot=True):
671
666
  current_type_markets = self.get_markets_from_exchange(exchange, spot)
672
- codes = ['BTC', 'ETH', 'XRP', 'LTC', 'BCH', 'EOS', 'BNB', 'BSV', 'USDT', 'ATOM', 'BAT', 'BTG', 'DASH', 'DOGE', 'ETC', 'IOTA', 'LSK', 'MKR', 'NEO', 'PAX', 'QTUM', 'TRX', 'TUSD', 'USD', 'USDC', 'WAVES', 'XEM', 'XMR', 'ZEC', 'ZRX']
673
- spot_symbols = ['BTC/USDT', 'BTC/USDC', 'BTC/USD', 'BTC/CNY', 'BTC/EUR', 'BTC/ETH', 'ETH/BTC', 'ETH/USD', 'ETH/USDT', 'BTC/JPY', 'LTC/BTC', 'ZRX/WETH', 'EUR/USD']
674
- swap_symbols = ['BTC/USDT:USDT', 'BTC/USDC:USDC', 'BTC/USD:USD', 'ETH/USDT:USDT', 'ETH/USD:USD', 'LTC/USDT:USDT', 'DOGE/USDT:USDT', 'ADA/USDT:USDT', 'BTC/USD:BTC', 'ETH/USD:ETH']
667
+ codes = ['BTC', 'ETH', 'XRP', 'LTC', 'BNB', 'DASH', 'DOGE', 'ETC', 'TRX', 'USDT', 'USDC', 'USD', 'EUR', 'TUSD', 'CNY', 'JPY', 'BRL']
668
+ spot_symbols = ['BTC/USDT', 'BTC/USDC', 'BTC/USD', 'BTC/CNY', 'BTC/EUR', 'BTC/AUD', 'BTC/BRL', 'BTC/JPY', 'ETH/USDT', 'ETH/USDC', 'ETH/USD', 'ETH/CNY', 'ETH/EUR', 'ETH/AUD', 'ETH/BRL', 'ETH/JPY', 'EUR/USDT', 'EUR/USD', 'EUR/USDC', 'USDT/EUR', 'USD/EUR', 'USDC/EUR', 'BTC/ETH', 'ETH/BTC']
669
+ swap_symbols = ['BTC/USDT:USDT', 'BTC/USDC:USDC', 'BTC/USD:USD', 'ETH/USDT:USDT', 'ETH/USDC:USDC', 'ETH/USD:USD', 'BTC/USD:BTC', 'ETH/USD:ETH']
675
670
  target_symbols = spot_symbols if spot else swap_symbols
676
671
  symbol = self.get_test_symbol(exchange, spot, target_symbols)
677
672
  # if symbols wasn't found from above hardcoded list, then try to locate any symbol which has our target hardcoded 'base' code
@@ -1121,7 +1116,8 @@ class testMainClass(baseMainTestClass):
1121
1116
  # instantiate the exchange and make sure that we sink the requests to avoid an actual request
1122
1117
  exchange = self.init_offline_exchange(exchange_name)
1123
1118
  global_options = exchange.safe_dict(exchange_data, 'options', {})
1124
- exchange.options = exchange.deep_extend(exchange.options, global_options) # custom options to be used in the tests
1119
+ # exchange.options = exchange.deepExtend (exchange.options, globalOptions); # custom options to be used in the tests
1120
+ exchange.extend_exchange_options(global_options)
1125
1121
  methods = exchange.safe_value(exchange_data, 'methods', {})
1126
1122
  methods_names = list(methods.keys())
1127
1123
  for i in range(0, len(methods_names)):
@@ -1131,7 +1127,8 @@ class testMainClass(baseMainTestClass):
1131
1127
  result = results[j]
1132
1128
  old_exchange_options = exchange.options # snapshot options;
1133
1129
  test_exchange_options = exchange.safe_value(result, 'options', {})
1134
- exchange.options = exchange.deep_extend(old_exchange_options, test_exchange_options) # custom options to be used in the tests
1130
+ # exchange.options = exchange.deepExtend (oldExchangeOptions, testExchangeOptions); # custom options to be used in the tests
1131
+ exchange.extend_exchange_options(exchange.deep_extend(old_exchange_options, test_exchange_options))
1135
1132
  description = exchange.safe_value(result, 'description')
1136
1133
  if (test_name is not None) and (test_name != description):
1137
1134
  continue
@@ -1142,7 +1139,8 @@ class testMainClass(baseMainTestClass):
1142
1139
  skip_keys = exchange.safe_value(exchange_data, 'skipKeys', [])
1143
1140
  await self.test_method_statically(exchange, method, result, type, skip_keys)
1144
1141
  # reset options
1145
- exchange.options = exchange.deep_extend(old_exchange_options, {})
1142
+ # exchange.options = exchange.deepExtend (oldExchangeOptions, {});
1143
+ exchange.extend_exchange_options(exchange.deep_extend(old_exchange_options, {}))
1146
1144
  await close(exchange)
1147
1145
  return True # in c# methods that will be used with promiseAll need to return something
1148
1146
 
@@ -1150,7 +1148,8 @@ class testMainClass(baseMainTestClass):
1150
1148
  exchange = self.init_offline_exchange(exchange_name)
1151
1149
  methods = exchange.safe_value(exchange_data, 'methods', {})
1152
1150
  options = exchange.safe_value(exchange_data, 'options', {})
1153
- exchange.options = exchange.deep_extend(exchange.options, options) # custom options to be used in the tests
1151
+ # exchange.options = exchange.deepExtend (exchange.options, options); # custom options to be used in the tests
1152
+ exchange.extend_exchange_options(options)
1154
1153
  methods_names = list(methods.keys())
1155
1154
  for i in range(0, len(methods_names)):
1156
1155
  method = methods_names[i]
@@ -1160,7 +1159,8 @@ class testMainClass(baseMainTestClass):
1160
1159
  description = exchange.safe_value(result, 'description')
1161
1160
  old_exchange_options = exchange.options # snapshot options;
1162
1161
  test_exchange_options = exchange.safe_value(result, 'options', {})
1163
- exchange.options = exchange.deep_extend(old_exchange_options, test_exchange_options) # custom options to be used in the tests
1162
+ # exchange.options = exchange.deepExtend (oldExchangeOptions, testExchangeOptions); # custom options to be used in the tests
1163
+ exchange.extend_exchange_options(exchange.deep_extend(old_exchange_options, test_exchange_options))
1164
1164
  is_disabled = exchange.safe_bool(result, 'disabled', False)
1165
1165
  if is_disabled:
1166
1166
  continue
@@ -1175,7 +1175,8 @@ class testMainClass(baseMainTestClass):
1175
1175
  skip_keys = exchange.safe_value(exchange_data, 'skipKeys', [])
1176
1176
  await self.test_response_statically(exchange, method, skip_keys, result)
1177
1177
  # reset options
1178
- exchange.options = exchange.deep_extend(old_exchange_options, {})
1178
+ # exchange.options = exchange.deepExtend (oldExchangeOptions, {});
1179
+ exchange.extend_exchange_options(exchange.deep_extend(old_exchange_options, {}))
1179
1180
  await close(exchange)
1180
1181
  return True # in c# methods that will be used with promiseAll need to return something
1181
1182
 
ccxt/test/test_sync.py CHANGED
@@ -128,6 +128,7 @@ class baseMainTestClass():
128
128
  response_tests = False
129
129
  ws_tests = False
130
130
  load_keys = False
131
+ skipped_settings_for_exchange = {}
131
132
  skipped_methods = {}
132
133
  check_public_tests = {}
133
134
  test_files = {}
@@ -377,7 +378,8 @@ class testMainClass(baseMainTestClass):
377
378
  # skipped tests
378
379
  skipped_file = self.root_dir_for_skips + 'skip-tests.json'
379
380
  skipped_settings = io_file_read(skipped_file)
380
- skipped_settings_for_exchange = exchange.safe_value(skipped_settings, exchange_id, {})
381
+ self.skipped_settings_for_exchange = exchange.safe_value(skipped_settings, exchange_id, {})
382
+ skipped_settings_for_exchange = self.skipped_settings_for_exchange
381
383
  # others
382
384
  timeout = exchange.safe_value(skipped_settings_for_exchange, 'timeout')
383
385
  if timeout is not None:
@@ -568,6 +570,7 @@ class testMainClass(baseMainTestClass):
568
570
  'watchOHLCV': [symbol],
569
571
  'watchTicker': [symbol],
570
572
  'watchTickers': [symbol],
573
+ 'watchBidsAsks': [symbol],
571
574
  'watchOrderBook': [symbol],
572
575
  'watchTrades': [symbol],
573
576
  }
@@ -614,26 +617,18 @@ class testMainClass(baseMainTestClass):
614
617
  result = self.test_safe('loadMarkets', exchange, [], True)
615
618
  if not result:
616
619
  return False
617
- symbols = ['BTC/USDT', 'BTC/USDC', 'BTC/CNY', 'BTC/USD', 'BTC/EUR', 'BTC/ETH', 'ETH/BTC', 'BTC/JPY', 'ETH/EUR', 'ETH/JPY', 'ETH/CNY', 'ETH/USD', 'LTC/CNY', 'DASH/BTC', 'DOGE/BTC', 'BTC/AUD', 'BTC/PLN', 'USD/SLL', 'BTC/RUB', 'BTC/UAH', 'LTC/BTC', 'EUR/USD']
618
- result_symbols = []
619
- exchange_specific_symbols = exchange.symbols
620
- for i in range(0, len(exchange_specific_symbols)):
621
- symbol = exchange_specific_symbols[i]
622
- if exchange.in_array(symbol, symbols):
623
- result_symbols.append(symbol)
624
- result_msg = ''
625
- result_length = len(result_symbols)
626
620
  exchange_symbols_length = len(exchange.symbols)
627
- if result_length > 0:
628
- if exchange_symbols_length > result_length:
629
- result_msg = ', '.join(result_symbols) + ' + more...'
630
- else:
631
- result_msg = ', '.join(result_symbols)
632
- dump('[INFO:MAIN] Exchange loaded', exchange_symbols_length, 'symbols', result_msg)
621
+ dump('[INFO:MAIN] Exchange loaded', exchange_symbols_length, 'symbols')
633
622
  return True
634
623
 
635
624
  def get_test_symbol(self, exchange, is_spot, symbols):
636
625
  symbol = None
626
+ preferred_spot_symbol = exchange.safe_string(self.skipped_settings_for_exchange, 'preferredSpotSymbol')
627
+ preferred_swap_symbol = exchange.safe_string(self.skipped_settings_for_exchange, 'preferredSwapSymbol')
628
+ if is_spot and preferred_spot_symbol:
629
+ return preferred_spot_symbol
630
+ elif not is_spot and preferred_swap_symbol:
631
+ return preferred_swap_symbol
637
632
  for i in range(0, len(symbols)):
638
633
  s = symbols[i]
639
634
  market = exchange.safe_value(exchange.markets, s)
@@ -668,9 +663,9 @@ class testMainClass(baseMainTestClass):
668
663
 
669
664
  def get_valid_symbol(self, exchange, spot=True):
670
665
  current_type_markets = self.get_markets_from_exchange(exchange, spot)
671
- codes = ['BTC', 'ETH', 'XRP', 'LTC', 'BCH', 'EOS', 'BNB', 'BSV', 'USDT', 'ATOM', 'BAT', 'BTG', 'DASH', 'DOGE', 'ETC', 'IOTA', 'LSK', 'MKR', 'NEO', 'PAX', 'QTUM', 'TRX', 'TUSD', 'USD', 'USDC', 'WAVES', 'XEM', 'XMR', 'ZEC', 'ZRX']
672
- spot_symbols = ['BTC/USDT', 'BTC/USDC', 'BTC/USD', 'BTC/CNY', 'BTC/EUR', 'BTC/ETH', 'ETH/BTC', 'ETH/USD', 'ETH/USDT', 'BTC/JPY', 'LTC/BTC', 'ZRX/WETH', 'EUR/USD']
673
- swap_symbols = ['BTC/USDT:USDT', 'BTC/USDC:USDC', 'BTC/USD:USD', 'ETH/USDT:USDT', 'ETH/USD:USD', 'LTC/USDT:USDT', 'DOGE/USDT:USDT', 'ADA/USDT:USDT', 'BTC/USD:BTC', 'ETH/USD:ETH']
666
+ codes = ['BTC', 'ETH', 'XRP', 'LTC', 'BNB', 'DASH', 'DOGE', 'ETC', 'TRX', 'USDT', 'USDC', 'USD', 'EUR', 'TUSD', 'CNY', 'JPY', 'BRL']
667
+ spot_symbols = ['BTC/USDT', 'BTC/USDC', 'BTC/USD', 'BTC/CNY', 'BTC/EUR', 'BTC/AUD', 'BTC/BRL', 'BTC/JPY', 'ETH/USDT', 'ETH/USDC', 'ETH/USD', 'ETH/CNY', 'ETH/EUR', 'ETH/AUD', 'ETH/BRL', 'ETH/JPY', 'EUR/USDT', 'EUR/USD', 'EUR/USDC', 'USDT/EUR', 'USD/EUR', 'USDC/EUR', 'BTC/ETH', 'ETH/BTC']
668
+ swap_symbols = ['BTC/USDT:USDT', 'BTC/USDC:USDC', 'BTC/USD:USD', 'ETH/USDT:USDT', 'ETH/USDC:USDC', 'ETH/USD:USD', 'BTC/USD:BTC', 'ETH/USD:ETH']
674
669
  target_symbols = spot_symbols if spot else swap_symbols
675
670
  symbol = self.get_test_symbol(exchange, spot, target_symbols)
676
671
  # if symbols wasn't found from above hardcoded list, then try to locate any symbol which has our target hardcoded 'base' code
@@ -1120,7 +1115,8 @@ class testMainClass(baseMainTestClass):
1120
1115
  # instantiate the exchange and make sure that we sink the requests to avoid an actual request
1121
1116
  exchange = self.init_offline_exchange(exchange_name)
1122
1117
  global_options = exchange.safe_dict(exchange_data, 'options', {})
1123
- exchange.options = exchange.deep_extend(exchange.options, global_options) # custom options to be used in the tests
1118
+ # exchange.options = exchange.deepExtend (exchange.options, globalOptions); # custom options to be used in the tests
1119
+ exchange.extend_exchange_options(global_options)
1124
1120
  methods = exchange.safe_value(exchange_data, 'methods', {})
1125
1121
  methods_names = list(methods.keys())
1126
1122
  for i in range(0, len(methods_names)):
@@ -1130,7 +1126,8 @@ class testMainClass(baseMainTestClass):
1130
1126
  result = results[j]
1131
1127
  old_exchange_options = exchange.options # snapshot options;
1132
1128
  test_exchange_options = exchange.safe_value(result, 'options', {})
1133
- exchange.options = exchange.deep_extend(old_exchange_options, test_exchange_options) # custom options to be used in the tests
1129
+ # exchange.options = exchange.deepExtend (oldExchangeOptions, testExchangeOptions); # custom options to be used in the tests
1130
+ exchange.extend_exchange_options(exchange.deep_extend(old_exchange_options, test_exchange_options))
1134
1131
  description = exchange.safe_value(result, 'description')
1135
1132
  if (test_name is not None) and (test_name != description):
1136
1133
  continue
@@ -1141,7 +1138,8 @@ class testMainClass(baseMainTestClass):
1141
1138
  skip_keys = exchange.safe_value(exchange_data, 'skipKeys', [])
1142
1139
  self.test_method_statically(exchange, method, result, type, skip_keys)
1143
1140
  # reset options
1144
- exchange.options = exchange.deep_extend(old_exchange_options, {})
1141
+ # exchange.options = exchange.deepExtend (oldExchangeOptions, {});
1142
+ exchange.extend_exchange_options(exchange.deep_extend(old_exchange_options, {}))
1145
1143
  close(exchange)
1146
1144
  return True # in c# methods that will be used with promiseAll need to return something
1147
1145
 
@@ -1149,7 +1147,8 @@ class testMainClass(baseMainTestClass):
1149
1147
  exchange = self.init_offline_exchange(exchange_name)
1150
1148
  methods = exchange.safe_value(exchange_data, 'methods', {})
1151
1149
  options = exchange.safe_value(exchange_data, 'options', {})
1152
- exchange.options = exchange.deep_extend(exchange.options, options) # custom options to be used in the tests
1150
+ # exchange.options = exchange.deepExtend (exchange.options, options); # custom options to be used in the tests
1151
+ exchange.extend_exchange_options(options)
1153
1152
  methods_names = list(methods.keys())
1154
1153
  for i in range(0, len(methods_names)):
1155
1154
  method = methods_names[i]
@@ -1159,7 +1158,8 @@ class testMainClass(baseMainTestClass):
1159
1158
  description = exchange.safe_value(result, 'description')
1160
1159
  old_exchange_options = exchange.options # snapshot options;
1161
1160
  test_exchange_options = exchange.safe_value(result, 'options', {})
1162
- exchange.options = exchange.deep_extend(old_exchange_options, test_exchange_options) # custom options to be used in the tests
1161
+ # exchange.options = exchange.deepExtend (oldExchangeOptions, testExchangeOptions); # custom options to be used in the tests
1162
+ exchange.extend_exchange_options(exchange.deep_extend(old_exchange_options, test_exchange_options))
1163
1163
  is_disabled = exchange.safe_bool(result, 'disabled', False)
1164
1164
  if is_disabled:
1165
1165
  continue
@@ -1174,7 +1174,8 @@ class testMainClass(baseMainTestClass):
1174
1174
  skip_keys = exchange.safe_value(exchange_data, 'skipKeys', [])
1175
1175
  self.test_response_statically(exchange, method, skip_keys, result)
1176
1176
  # reset options
1177
- exchange.options = exchange.deep_extend(old_exchange_options, {})
1177
+ # exchange.options = exchange.deepExtend (oldExchangeOptions, {});
1178
+ exchange.extend_exchange_options(exchange.deep_extend(old_exchange_options, {}))
1178
1179
  close(exchange)
1179
1180
  return True # in c# methods that will be used with promiseAll need to return something
1180
1181
 
ccxt/upbit.py CHANGED
@@ -85,6 +85,7 @@ class upbit(Exchange, ImplicitAPI):
85
85
  '1m': 'minutes',
86
86
  '3m': 'minutes',
87
87
  '5m': 'minutes',
88
+ '10m': 'minutes',
88
89
  '15m': 'minutes',
89
90
  '30m': 'minutes',
90
91
  '1h': 'minutes',
@@ -114,6 +115,7 @@ class upbit(Exchange, ImplicitAPI):
114
115
  'candles/minutes/1',
115
116
  'candles/minutes/3',
116
117
  'candles/minutes/5',
118
+ 'candles/minutes/10',
117
119
  'candles/minutes/15',
118
120
  'candles/minutes/30',
119
121
  'candles/minutes/60',
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ccxt
3
- Version: 4.2.78
3
+ Version: 4.2.80
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
@@ -91,7 +91,7 @@ Current feature list:
91
91
  | [![bitmart](https://user-images.githubusercontent.com/1294454/129991357-8f47464b-d0f4-41d6-8a82-34122f0d1398.jpg)](http://www.bitmart.com/?r=rQCFLh) | bitmart | [BitMart](http://www.bitmart.com/?r=rQCFLh) | [![API Version 2](https://img.shields.io/badge/2-lightgray)](https://developer-pro.bitmart.com/) | [![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 BitMart using CCXT's referral link for a 30% discount!](https://img.shields.io/static/v1?label=Fee&message=%2d30%25&color=orange)](http://www.bitmart.com/?r=rQCFLh) |
92
92
  | [![bitmex](https://github.com/ccxt/ccxt/assets/43336371/cea9cfe5-c57e-4b84-b2ac-77b960b04445)](https://www.bitmex.com/app/register/NZTR1q) | bitmex | [BitMEX](https://www.bitmex.com/app/register/NZTR1q) | [![API Version 1](https://img.shields.io/badge/1-lightgray)](https://www.bitmex.com/app/apiOverview) | [![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 BitMEX using CCXT's referral link for a 10% discount!](https://img.shields.io/static/v1?label=Fee&message=%2d10%25&color=orange)](https://www.bitmex.com/app/register/NZTR1q) |
93
93
  | [![bybit](https://user-images.githubusercontent.com/51840849/76547799-daff5b80-649e-11ea-87fb-3be9bac08954.jpg)](https://www.bybit.com/register?affiliate_id=35953) | bybit | [Bybit](https://www.bybit.com/register?affiliate_id=35953) | [![API Version 5](https://img.shields.io/badge/5-lightgray)](https://bybit-exchange.github.io/docs/inverse/) | [![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) | |
94
- | [![coinbaseinternational](https://github.com/ccxt/ccxt/assets/43336371/866ae638-6ab5-4ebf-ab2c-cdcce9545625)](https://international.coinbase.com) | coinbaseinternational | [Coinbase International](https://international.coinbase.com) | [![API Version 1](https://img.shields.io/badge/1-lightgray)](https://docs.cloud.coinbaseinternational.com/intx/docs) | [![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) | |
94
+ | [![coinbaseinternational](https://github.com/ccxt/ccxt/assets/43336371/866ae638-6ab5-4ebf-ab2c-cdcce9545625)](https://international.coinbase.com) | coinbaseinternational | [Coinbase International](https://international.coinbase.com) | [![API Version 1](https://img.shields.io/badge/1-lightgray)](https://docs.cloud.coinbase.com/intx/docs) | [![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) | |
95
95
  | [![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 1](https://img.shields.io/badge/1-lightgray)](https://viabtc.github.io/coinex_api_en_doc) | [![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) | |
96
96
  | [![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) | [![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) |
97
97
  | [![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/) | [![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) |
@@ -144,7 +144,7 @@ The CCXT library currently supports the following 97 cryptocurrency exchange mar
144
144
  | [![bybit](https://user-images.githubusercontent.com/51840849/76547799-daff5b80-649e-11ea-87fb-3be9bac08954.jpg)](https://www.bybit.com/register?affiliate_id=35953) | bybit | [Bybit](https://www.bybit.com/register?affiliate_id=35953) | [![API Version 5](https://img.shields.io/badge/5-lightgray)](https://bybit-exchange.github.io/docs/inverse/) | [![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) |
145
145
  | [![cex](https://user-images.githubusercontent.com/1294454/27766442-8ddc33b0-5ed8-11e7-8b98-f786aef0f3c9.jpg)](https://cex.io/r/0/up105393824/0/) | cex | [CEX.IO](https://cex.io/r/0/up105393824/0/) | [![API Version *](https://img.shields.io/badge/*-lightgray)](https://cex.io/cex-api) | | [![CCXT Pro](https://img.shields.io/badge/CCXT-Pro-black)](https://ccxt.pro) |
146
146
  | [![coinbase](https://user-images.githubusercontent.com/1294454/40811661-b6eceae2-653a-11e8-829e-10bfadb078cf.jpg)](https://www.coinbase.com/join/58cbe25a355148797479dbd2) | coinbase | [Coinbase](https://www.coinbase.com/join/58cbe25a355148797479dbd2) | [![API Version 2](https://img.shields.io/badge/2-lightgray)](https://developers.coinbase.com/api/v2) | | [![CCXT Pro](https://img.shields.io/badge/CCXT-Pro-black)](https://ccxt.pro) |
147
- | [![coinbaseinternational](https://github.com/ccxt/ccxt/assets/43336371/866ae638-6ab5-4ebf-ab2c-cdcce9545625)](https://international.coinbase.com) | coinbaseinternational | [Coinbase International](https://international.coinbase.com) | [![API Version 1](https://img.shields.io/badge/1-lightgray)](https://docs.cloud.coinbaseinternational.com/intx/docs) | [![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) |
147
+ | [![coinbaseinternational](https://github.com/ccxt/ccxt/assets/43336371/866ae638-6ab5-4ebf-ab2c-cdcce9545625)](https://international.coinbase.com) | coinbaseinternational | [Coinbase International](https://international.coinbase.com) | [![API Version 1](https://img.shields.io/badge/1-lightgray)](https://docs.cloud.coinbase.com/intx/docs) | [![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) |
148
148
  | [![coinbasepro](https://user-images.githubusercontent.com/1294454/41764625-63b7ffde-760a-11e8-996d-a6328fa9347a.jpg)](https://pro.coinbase.com/) | coinbasepro | [Coinbase Pro](https://pro.coinbase.com/) | [![API Version *](https://img.shields.io/badge/*-lightgray)](https://docs.pro.coinbase.com) | | [![CCXT Pro](https://img.shields.io/badge/CCXT-Pro-black)](https://ccxt.pro) |
149
149
  | [![coincheck](https://user-images.githubusercontent.com/51840849/87182088-1d6d6380-c2ec-11ea-9c64-8ab9f9b289f5.jpg)](https://coincheck.com) | coincheck | [coincheck](https://coincheck.com) | [![API Version *](https://img.shields.io/badge/*-lightgray)](https://coincheck.com/documents/exchange/api) | | |
150
150
  | [![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 1](https://img.shields.io/badge/1-lightgray)](https://viabtc.github.io/coinex_api_en_doc) | [![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) |
@@ -262,13 +262,13 @@ console.log(version, Object.keys(exchanges));
262
262
 
263
263
  All-in-one browser bundle (dependencies included), served from a CDN of your choice:
264
264
 
265
- * jsDelivr: https://cdn.jsdelivr.net/npm/ccxt@4.2.78/dist/ccxt.browser.js
266
- * unpkg: https://unpkg.com/ccxt@4.2.78/dist/ccxt.browser.js
265
+ * jsDelivr: https://cdn.jsdelivr.net/npm/ccxt@4.2.80/dist/ccxt.browser.js
266
+ * unpkg: https://unpkg.com/ccxt@4.2.80/dist/ccxt.browser.js
267
267
 
268
268
  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.
269
269
 
270
270
  ```HTML
271
- <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ccxt@4.2.78/dist/ccxt.browser.js"></script>
271
+ <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ccxt@4.2.80/dist/ccxt.browser.js"></script>
272
272
  ```
273
273
 
274
274
  Creates a global `ccxt` object: