ccxt 4.4.78__py2.py3-none-any.whl → 4.4.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 (83) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/abstract/bitmart.py +1 -0
  3. ccxt/apex.py +2 -2
  4. ccxt/ascendex.py +22 -5
  5. ccxt/async_support/__init__.py +1 -1
  6. ccxt/async_support/apex.py +2 -2
  7. ccxt/async_support/ascendex.py +22 -5
  8. ccxt/async_support/base/exchange.py +5 -1
  9. ccxt/async_support/binance.py +6 -0
  10. ccxt/async_support/bingx.py +3 -3
  11. ccxt/async_support/bitfinex.py +59 -34
  12. ccxt/async_support/bitget.py +52 -64
  13. ccxt/async_support/bitmart.py +7 -2
  14. ccxt/async_support/bitmex.py +8 -1
  15. ccxt/async_support/bitopro.py +5 -1
  16. ccxt/async_support/bitrue.py +2 -1
  17. ccxt/async_support/bitso.py +1 -1
  18. ccxt/async_support/bitteam.py +2 -0
  19. ccxt/async_support/bitvavo.py +25 -10
  20. ccxt/async_support/btcalpha.py +1 -1
  21. ccxt/async_support/btcmarkets.py +1 -1
  22. ccxt/async_support/btcturk.py +1 -1
  23. ccxt/async_support/bybit.py +27 -15
  24. ccxt/async_support/coinbase.py +3 -15
  25. ccxt/async_support/coinex.py +1 -0
  26. ccxt/async_support/coinlist.py +1 -0
  27. ccxt/async_support/coinone.py +1 -0
  28. ccxt/async_support/delta.py +3 -0
  29. ccxt/async_support/deribit.py +1 -0
  30. ccxt/async_support/hollaex.py +1 -0
  31. ccxt/async_support/htx.py +7 -3
  32. ccxt/async_support/huobijp.py +1 -0
  33. ccxt/async_support/hyperliquid.py +1 -0
  34. ccxt/async_support/kraken.py +2 -0
  35. ccxt/async_support/okx.py +1 -1
  36. ccxt/async_support/poloniex.py +1 -0
  37. ccxt/async_support/timex.py +2 -2
  38. ccxt/async_support/upbit.py +43 -21
  39. ccxt/async_support/whitebit.py +65 -12
  40. ccxt/base/errors.py +0 -6
  41. ccxt/base/exchange.py +1 -1
  42. ccxt/binance.py +6 -0
  43. ccxt/bingx.py +3 -3
  44. ccxt/bitfinex.py +59 -34
  45. ccxt/bitget.py +52 -64
  46. ccxt/bitmart.py +7 -2
  47. ccxt/bitmex.py +8 -1
  48. ccxt/bitopro.py +5 -1
  49. ccxt/bitrue.py +2 -1
  50. ccxt/bitso.py +1 -1
  51. ccxt/bitteam.py +2 -0
  52. ccxt/bitvavo.py +25 -10
  53. ccxt/btcalpha.py +1 -1
  54. ccxt/btcmarkets.py +1 -1
  55. ccxt/btcturk.py +1 -1
  56. ccxt/bybit.py +27 -15
  57. ccxt/coinbase.py +3 -15
  58. ccxt/coinex.py +1 -0
  59. ccxt/coinlist.py +1 -0
  60. ccxt/coinone.py +1 -0
  61. ccxt/delta.py +3 -0
  62. ccxt/deribit.py +1 -0
  63. ccxt/hollaex.py +1 -0
  64. ccxt/htx.py +7 -3
  65. ccxt/huobijp.py +1 -0
  66. ccxt/hyperliquid.py +1 -0
  67. ccxt/kraken.py +2 -0
  68. ccxt/okx.py +1 -1
  69. ccxt/poloniex.py +1 -0
  70. ccxt/pro/__init__.py +1 -1
  71. ccxt/pro/binance.py +3 -3
  72. ccxt/pro/coinbase.py +40 -52
  73. ccxt/pro/upbit.py +42 -0
  74. ccxt/test/tests_async.py +0 -1
  75. ccxt/test/tests_sync.py +0 -1
  76. ccxt/timex.py +2 -2
  77. ccxt/upbit.py +43 -21
  78. ccxt/whitebit.py +65 -12
  79. {ccxt-4.4.78.dist-info → ccxt-4.4.80.dist-info}/METADATA +9 -11
  80. {ccxt-4.4.78.dist-info → ccxt-4.4.80.dist-info}/RECORD +83 -83
  81. {ccxt-4.4.78.dist-info → ccxt-4.4.80.dist-info}/LICENSE.txt +0 -0
  82. {ccxt-4.4.78.dist-info → ccxt-4.4.80.dist-info}/WHEEL +0 -0
  83. {ccxt-4.4.78.dist-info → ccxt-4.4.80.dist-info}/top_level.txt +0 -0
ccxt/coinone.py CHANGED
@@ -330,6 +330,7 @@ class coinone(Exchange, ImplicitAPI):
330
330
  },
331
331
  },
332
332
  'networks': {},
333
+ 'type': 'crypto',
333
334
  }
334
335
  return result
335
336
 
ccxt/delta.py CHANGED
@@ -357,6 +357,8 @@ class delta(Exchange, ImplicitAPI):
357
357
  base = self.safe_string(optionParts, 1)
358
358
  expiry = self.safe_string(optionParts, 3)
359
359
  optionType = self.safe_string(optionParts, 0)
360
+ if expiry is not None:
361
+ expiry = expiry[4:] + expiry[2:4] + expiry[0:2]
360
362
  settle = quote
361
363
  strike = self.safe_string(optionParts, 2)
362
364
  datetime = self.convert_expire_date(expiry)
@@ -567,6 +569,7 @@ class delta(Exchange, ImplicitAPI):
567
569
  },
568
570
  },
569
571
  'networks': {},
572
+ 'type': 'crypto',
570
573
  }
571
574
  return result
572
575
 
ccxt/deribit.py CHANGED
@@ -655,6 +655,7 @@ class deribit(Exchange, ImplicitAPI):
655
655
  'active': None,
656
656
  'deposit': None,
657
657
  'withdraw': None,
658
+ 'type': 'crypto',
658
659
  'fee': self.safe_number(currency, 'withdrawal_fee'),
659
660
  'precision': self.parse_number(self.parse_precision(self.safe_string(currency, 'fee_precision'))),
660
661
  'limits': {
ccxt/hollaex.py CHANGED
@@ -493,6 +493,7 @@ class hollaex(Exchange, ImplicitAPI):
493
493
  },
494
494
  },
495
495
  'networks': {},
496
+ 'type': 'crypto',
496
497
  }
497
498
  return result
498
499
 
ccxt/htx.py CHANGED
@@ -962,6 +962,7 @@ class htx(Exchange, ImplicitAPI):
962
962
  },
963
963
  'precisionMode': TICK_SIZE,
964
964
  'options': {
965
+ 'include_OS_certificates': False, # temporarily leave self, remove in future
965
966
  'fetchMarkets': {
966
967
  'types': {
967
968
  'spot': True,
@@ -2172,14 +2173,14 @@ class htx(Exchange, ImplicitAPI):
2172
2173
  ask = None
2173
2174
  askVolume = None
2174
2175
  if 'bid' in ticker:
2175
- if isinstance(ticker['bid'], list):
2176
+ if ticker['bid'] is not None and isinstance(ticker['bid'], list):
2176
2177
  bid = self.safe_string(ticker['bid'], 0)
2177
2178
  bidVolume = self.safe_string(ticker['bid'], 1)
2178
2179
  else:
2179
2180
  bid = self.safe_string(ticker, 'bid')
2180
2181
  bidVolume = self.safe_string(ticker, 'bidSize')
2181
2182
  if 'ask' in ticker:
2182
- if isinstance(ticker['ask'], list):
2183
+ if ticker['ask'] is not None and isinstance(ticker['ask'], list):
2183
2184
  ask = self.safe_string(ticker['ask'], 0)
2184
2185
  askVolume = self.safe_string(ticker['ask'], 1)
2185
2186
  else:
@@ -3270,7 +3271,7 @@ class htx(Exchange, ImplicitAPI):
3270
3271
  # "withdrawQuotaPerYear": null,
3271
3272
  # "withdrawQuotaTotal": null,
3272
3273
  # "withdrawFeeType": "fixed",
3273
- # "transactFeeWithdraw": "11.1653",
3274
+ # "transactFeeWithdraw": "11.1654",
3274
3275
  # "addrWithTag": False,
3275
3276
  # "addrDepositTag": False
3276
3277
  # }
@@ -3293,6 +3294,8 @@ class htx(Exchange, ImplicitAPI):
3293
3294
  chains = self.safe_value(entry, 'chains', [])
3294
3295
  networks: dict = {}
3295
3296
  instStatus = self.safe_string(entry, 'instStatus')
3297
+ assetType = self.safe_string(entry, 'assetType')
3298
+ type = assetType == 'crypto' if '1' else 'fiat'
3296
3299
  currencyActive = instStatus == 'normal'
3297
3300
  minPrecision = None
3298
3301
  minDeposit = None
@@ -3350,6 +3353,7 @@ class htx(Exchange, ImplicitAPI):
3350
3353
  'withdraw': withdraw,
3351
3354
  'fee': None,
3352
3355
  'name': None,
3356
+ 'type': type,
3353
3357
  'limits': {
3354
3358
  'amount': {
3355
3359
  'min': None,
ccxt/huobijp.py CHANGED
@@ -1110,6 +1110,7 @@ class huobijp(Exchange, ImplicitAPI):
1110
1110
  'withdraw': withdrawEnabled,
1111
1111
  'fee': None, # todo need to fetch from fee endpoint
1112
1112
  'precision': precision,
1113
+ 'networks': None,
1113
1114
  'limits': {
1114
1115
  'amount': {
1115
1116
  'min': precision,
ccxt/hyperliquid.py CHANGED
@@ -379,6 +379,7 @@ class hyperliquid(Exchange, ImplicitAPI):
379
379
  'withdraw': None,
380
380
  'networks': None,
381
381
  'fee': None,
382
+ 'type': 'crypto',
382
383
  'limits': {
383
384
  'amount': {
384
385
  'min': None,
ccxt/kraken.py CHANGED
@@ -864,12 +864,14 @@ class kraken(Exchange, ImplicitAPI):
864
864
  precision = self.parse_number(self.parse_precision(self.safe_string(currency, 'decimals')))
865
865
  # assumes all currencies are active except those listed above
866
866
  active = self.safe_string(currency, 'status') == 'enabled'
867
+ isFiat = code.find('.HOLD') >= 0
867
868
  result[code] = {
868
869
  'id': id,
869
870
  'code': code,
870
871
  'info': currency,
871
872
  'name': self.safe_string(currency, 'altname'),
872
873
  'active': active,
874
+ 'type': 'fiat' if isFiat else 'crypto',
873
875
  'deposit': None,
874
876
  'withdraw': None,
875
877
  'fee': None,
ccxt/okx.py CHANGED
@@ -4831,7 +4831,7 @@ class okx(Exchange, ImplicitAPI):
4831
4831
  :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
4832
4832
  """
4833
4833
  self.load_markets()
4834
- rawNetwork = self.safe_string_upper(params, 'network')
4834
+ rawNetwork = self.safe_string(params, 'network') # some networks are like "Dora Vota Mainnet"
4835
4835
  params = self.omit(params, 'network')
4836
4836
  code = self.safe_currency_code(code)
4837
4837
  network = self.network_id_to_code(rawNetwork, code)
ccxt/poloniex.py CHANGED
@@ -1203,6 +1203,7 @@ class poloniex(Exchange, ImplicitAPI):
1203
1203
  'withdraw': withdrawEnabled,
1204
1204
  'fee': self.parse_number(feeString),
1205
1205
  'precision': None,
1206
+ 'type': 'crypto',
1206
1207
  'limits': {
1207
1208
  'amount': {
1208
1209
  'min': None,
ccxt/pro/__init__.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # ----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.4.78'
7
+ __version__ = '4.4.80'
8
8
 
9
9
  # ----------------------------------------------------------------------------
10
10
 
ccxt/pro/binance.py CHANGED
@@ -71,12 +71,12 @@ class binance(ccxt.async_support.binance):
71
71
  'urls': {
72
72
  'test': {
73
73
  'ws': {
74
- 'spot': 'wss://testnet.binance.vision/ws',
75
- 'margin': 'wss://testnet.binance.vision/ws',
74
+ 'spot': 'wss://stream.testnet.binance.vision/ws',
75
+ 'margin': 'wss://stream.testnet.binance.vision/ws',
76
76
  'future': 'wss://fstream.binancefuture.com/ws',
77
77
  'delivery': 'wss://dstream.binancefuture.com/ws',
78
78
  'ws-api': {
79
- 'spot': 'wss://testnet.binance.vision/ws-api/v3',
79
+ 'spot': 'wss://ws-api.testnet.binance.vision/ws-api/v3',
80
80
  'future': 'wss://testnet.binancefuture.com/ws-fapi/v1',
81
81
  'delivery': 'wss://testnet.binancefuture.com/ws-dapi/v1',
82
82
  },
ccxt/pro/coinbase.py CHANGED
@@ -78,7 +78,7 @@ class coinbase(ccxt.async_support.coinbase):
78
78
  messageHash = messageHash + '::' + ','.join(symbol)
79
79
  elif symbol is not None:
80
80
  market = self.market(symbol)
81
- messageHash = name + '::' + market['id']
81
+ messageHash = name + '::' + symbol
82
82
  productIds = [market['id']]
83
83
  url = self.urls['api']['ws']
84
84
  subscribe = {
@@ -115,7 +115,7 @@ class coinbase(ccxt.async_support.coinbase):
115
115
  market = self.market(symbol)
116
116
  marketId = market['id']
117
117
  productIds.append(marketId)
118
- messageHashes.append(name + '::' + marketId)
118
+ messageHashes.append(name + '::' + symbol)
119
119
  url = self.urls['api']['ws']
120
120
  subscribe = {
121
121
  'type': 'subscribe',
@@ -176,8 +176,11 @@ class coinbase(ccxt.async_support.coinbase):
176
176
  if symbols is None:
177
177
  symbols = self.symbols
178
178
  name = 'ticker_batch'
179
- tickers = await self.subscribe(name, False, symbols, params)
179
+ ticker = await self.subscribe_multiple(name, False, symbols, params)
180
180
  if self.newUpdates:
181
+ tickers = {}
182
+ symbol = ticker['symbol']
183
+ tickers[symbol] = ticker
181
184
  return tickers
182
185
  return self.tickers
183
186
 
@@ -272,7 +275,7 @@ class coinbase(ccxt.async_support.coinbase):
272
275
  #
273
276
  #
274
277
  channel = self.safe_string(message, 'channel')
275
- events = self.safe_value(message, 'events', [])
278
+ events = self.safe_list(message, 'events', [])
276
279
  datetime = self.safe_string(message, 'timestamp')
277
280
  timestamp = self.parse8601(datetime)
278
281
  newTickers = []
@@ -281,31 +284,18 @@ class coinbase(ccxt.async_support.coinbase):
281
284
  tickers = self.safe_list(tickersObj, 'tickers', [])
282
285
  for j in range(0, len(tickers)):
283
286
  ticker = tickers[j]
287
+ wsMarketId = self.safe_string(ticker, 'product_id')
288
+ if wsMarketId is None:
289
+ continue
284
290
  result = self.parse_ws_ticker(ticker)
285
291
  result['timestamp'] = timestamp
286
292
  result['datetime'] = datetime
287
293
  symbol = result['symbol']
288
294
  self.tickers[symbol] = result
289
- wsMarketId = self.safe_string(ticker, 'product_id')
290
- if wsMarketId is None:
291
- continue
292
- messageHash = channel + '::' + wsMarketId
293
295
  newTickers.append(result)
296
+ messageHash = channel + '::' + symbol
294
297
  client.resolve(result, messageHash)
295
- if messageHash.endswith('USD'):
296
- client.resolve(result, messageHash + 'C') # sometimes we subscribe to BTC/USDC and coinbase returns BTC/USD
297
- messageHashes = self.find_message_hashes(client, 'ticker_batch::')
298
- for i in range(0, len(messageHashes)):
299
- messageHash = messageHashes[i]
300
- parts = messageHash.split('::')
301
- symbolsString = parts[1]
302
- symbols = symbolsString.split(',')
303
- tickers = self.filter_by_array(newTickers, 'symbol', symbols)
304
- if not self.is_empty(tickers):
305
- client.resolve(tickers, messageHash)
306
- if messageHash.endswith('USD'):
307
- client.resolve(tickers, messageHash + 'C') # sometimes we subscribe to BTC/USDC and coinbase returns BTC/USD
308
- return message
298
+ self.try_resolve_usdc(client, messageHash, result)
309
299
 
310
300
  def parse_ws_ticker(self, ticker, market=None):
311
301
  #
@@ -470,13 +460,13 @@ class coinbase(ccxt.async_support.coinbase):
470
460
  # ]
471
461
  # }
472
462
  #
473
- events = self.safe_value(message, 'events')
463
+ events = self.safe_list(message, 'events')
474
464
  event = self.safe_value(events, 0)
475
- trades = self.safe_value(event, 'trades')
476
- trade = self.safe_value(trades, 0)
465
+ trades = self.safe_list(event, 'trades')
466
+ trade = self.safe_dict(trades, 0)
477
467
  marketId = self.safe_string(trade, 'product_id')
478
- messageHash = 'market_trades::' + marketId
479
468
  symbol = self.safe_symbol(marketId)
469
+ messageHash = 'market_trades::' + symbol
480
470
  tradesArray = self.safe_value(self.trades, symbol)
481
471
  if tradesArray is None:
482
472
  tradesLimit = self.safe_integer(self.options, 'tradesLimit', 1000)
@@ -484,14 +474,12 @@ class coinbase(ccxt.async_support.coinbase):
484
474
  self.trades[symbol] = tradesArray
485
475
  for i in range(0, len(events)):
486
476
  currentEvent = events[i]
487
- currentTrades = self.safe_value(currentEvent, 'trades')
477
+ currentTrades = self.safe_list(currentEvent, 'trades')
488
478
  for j in range(0, len(currentTrades)):
489
479
  item = currentTrades[i]
490
480
  tradesArray.append(self.parse_trade(item))
491
481
  client.resolve(tradesArray, messageHash)
492
- if marketId.endswith('USD'):
493
- client.resolve(tradesArray, messageHash + 'C') # sometimes we subscribe to BTC/USDC and coinbase returns BTC/USD
494
- return message
482
+ self.try_resolve_usdc(client, messageHash, tradesArray)
495
483
 
496
484
  def handle_order(self, client, message):
497
485
  #
@@ -522,14 +510,14 @@ class coinbase(ccxt.async_support.coinbase):
522
510
  # ]
523
511
  # }
524
512
  #
525
- events = self.safe_value(message, 'events')
513
+ events = self.safe_list(message, 'events')
526
514
  marketIds = []
527
515
  if self.orders is None:
528
516
  limit = self.safe_integer(self.options, 'ordersLimit', 1000)
529
517
  self.orders = ArrayCacheBySymbolById(limit)
530
518
  for i in range(0, len(events)):
531
519
  event = events[i]
532
- responseOrders = self.safe_value(event, 'orders')
520
+ responseOrders = self.safe_list(event, 'orders')
533
521
  for j in range(0, len(responseOrders)):
534
522
  responseOrder = responseOrders[j]
535
523
  parsed = self.parse_ws_order(responseOrder)
@@ -540,12 +528,11 @@ class coinbase(ccxt.async_support.coinbase):
540
528
  cachedOrders.append(parsed)
541
529
  for i in range(0, len(marketIds)):
542
530
  marketId = marketIds[i]
543
- messageHash = 'user::' + marketId
531
+ symbol = self.safe_symbol(marketId)
532
+ messageHash = 'user::' + symbol
544
533
  client.resolve(self.orders, messageHash)
545
- if messageHash.endswith('USD'):
546
- client.resolve(self.orders, messageHash + 'C') # sometimes we subscribe to BTC/USDC and coinbase returns BTC/USD
534
+ self.try_resolve_usdc(client, messageHash, self.orders)
547
535
  client.resolve(self.orders, 'user')
548
- return message
549
536
 
550
537
  def parse_ws_order(self, order, market=None):
551
538
  #
@@ -635,34 +622,35 @@ class coinbase(ccxt.async_support.coinbase):
635
622
  # ]
636
623
  # }
637
624
  #
638
- events = self.safe_value(message, 'events')
625
+ events = self.safe_list(message, 'events')
639
626
  datetime = self.safe_string(message, 'timestamp')
640
627
  for i in range(0, len(events)):
641
628
  event = events[i]
642
- updates = self.safe_value(event, 'updates', [])
629
+ updates = self.safe_list(event, 'updates', [])
643
630
  marketId = self.safe_string(event, 'product_id')
644
631
  # sometimes we subscribe to BTC/USDC and coinbase returns BTC/USD, are aliases
645
632
  market = self.safe_market(marketId)
646
- messageHash = 'level2::' + market['id']
647
633
  symbol = market['symbol']
634
+ messageHash = 'level2::' + symbol
648
635
  subscription = self.safe_value(client.subscriptions, messageHash, {})
649
636
  limit = self.safe_integer(subscription, 'limit')
650
637
  type = self.safe_string(event, 'type')
651
638
  if type == 'snapshot':
652
639
  self.orderbooks[symbol] = self.order_book({}, limit)
653
- orderbook = self.orderbooks[symbol]
654
- self.handle_order_book_helper(orderbook, updates)
655
- orderbook['timestamp'] = self.parse8601(datetime)
656
- orderbook['datetime'] = datetime
657
- orderbook['symbol'] = symbol
658
- client.resolve(orderbook, messageHash)
659
- elif type == 'update':
660
- orderbook = self.orderbooks[symbol]
661
- self.handle_order_book_helper(orderbook, updates)
662
- orderbook['datetime'] = datetime
663
- orderbook['timestamp'] = self.parse8601(datetime)
664
- orderbook['symbol'] = symbol
665
- client.resolve(orderbook, messageHash)
640
+ # unknown bug, can't reproduce, but sometimes orderbook is None
641
+ if not (symbol in self.orderbooks) and self.orderbooks[symbol] is None:
642
+ continue
643
+ orderbook = self.orderbooks[symbol]
644
+ self.handle_order_book_helper(orderbook, updates)
645
+ orderbook['timestamp'] = self.parse8601(datetime)
646
+ orderbook['datetime'] = datetime
647
+ orderbook['symbol'] = symbol
648
+ client.resolve(orderbook, messageHash)
649
+ self.try_resolve_usdc(client, messageHash, orderbook)
650
+
651
+ def try_resolve_usdc(self, client, messageHash, result):
652
+ if messageHash.endswith('/USD') or messageHash.endswith('-USD'):
653
+ client.resolve(result, messageHash + 'C') # when subscribing to BTC/USDC and coinbase returns BTC/USD, so resolve USDC too
666
654
 
667
655
  def handle_subscription_status(self, client, message):
668
656
  #
ccxt/pro/upbit.py CHANGED
@@ -8,6 +8,7 @@ from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById
8
8
  from ccxt.base.types import Any, Balances, Int, Order, OrderBook, Str, Strings, Ticker, Tickers, Trade
9
9
  from ccxt.async_support.base.ws.client import Client
10
10
  from typing import List
11
+ from ccxt.base.errors import NotSupported
11
12
 
12
13
 
13
14
  class upbit(ccxt.async_support.upbit):
@@ -21,6 +22,7 @@ class upbit(ccxt.async_support.upbit):
21
22
  'watchTickers': True,
22
23
  'watchTrades': True,
23
24
  'watchTradesForSymbols': True,
25
+ 'watchOHLCV': True,
24
26
  'watchOrders': True,
25
27
  'watchMyTrades': True,
26
28
  'watchBalance': True,
@@ -190,6 +192,25 @@ class upbit(ccxt.async_support.upbit):
190
192
  orderbook = await self.watch_public(symbol, 'orderbook')
191
193
  return orderbook.limit()
192
194
 
195
+ async def watch_ohlcv(self, symbol: str, timeframe='1s', since: Int = None, limit: Int = None, params={}) -> List[list]:
196
+ """
197
+ watches information an OHLCV with timestamp, openingPrice, highPrice, lowPrice, tradePrice, baseVolume in 1s.
198
+
199
+ https://docs.upbit.com/kr/reference/websocket-candle for Upbit KR
200
+ https://global-docs.upbit.com/reference/websocket-candle for Upbit Global
201
+
202
+ :param str symbol: unified market symbol of the market orders were made in
203
+ :param str timeframe: specifies the OHLCV candle interval to watch. As of now, Upbit only supports 1s candles.
204
+ :param int [since]: the earliest time in ms to fetch orders for
205
+ :param int [limit]: the maximum number of order structures to retrieve
206
+ :param dict [params]: extra parameters specific to the exchange API endpoint
207
+ :returns OHLCV[]: a list of `OHLCV structures <https://docs.ccxt.com/#/?id=ohlcv-structure>`
208
+ """
209
+ if timeframe != '1s':
210
+ raise NotSupported(self.id + ' watchOHLCV does not support' + timeframe + ' candle.')
211
+ timeFrameOHLCV = 'candle.' + timeframe
212
+ return await self.watch_public(symbol, timeFrameOHLCV)
213
+
193
214
  def handle_ticker(self, client: Client, message):
194
215
  # 2020-03-17T23:07:36.511Z "onMessage" <Buffer 7b 22 74 79 70 65 22 3a 22 74 69 63 6b 65 72 22 2c 22 63 6f 64 65 22 3a 22 42 54 43 2d 45 54 48 22 2c 22 6f 70 65 6e 69 6e 67 5f 70 72 69 63 65 22 3a ... >
195
216
  # {type: "ticker",
@@ -313,6 +334,26 @@ class upbit(ccxt.async_support.upbit):
313
334
  messageHash = 'trade:' + marketId
314
335
  client.resolve(stored, messageHash)
315
336
 
337
+ def handle_ohlcv(self, client: Client, message):
338
+ # {
339
+ # type: 'candle.1s',
340
+ # code: 'KRW-USDT',
341
+ # candle_date_time_utc: '2025-04-22T09:50:34',
342
+ # candle_date_time_kst: '2025-04-22T18:50:34',
343
+ # opening_price: 1438,
344
+ # high_price: 1438,
345
+ # low_price: 1438,
346
+ # trade_price: 1438,
347
+ # candle_acc_trade_volume: 1145.8935,
348
+ # candle_acc_trade_price: 1647794.853,
349
+ # timestamp: 1745315434125,
350
+ # stream_type: 'REALTIME'
351
+ # }
352
+ marketId = self.safe_string(message, 'code')
353
+ messageHash = 'candle.1s:' + marketId
354
+ ohlcv = self.parse_ohlcv(message)
355
+ client.resolve(ohlcv, messageHash)
356
+
316
357
  async def authenticate(self, params={}):
317
358
  self.check_required_credentials()
318
359
  wsOptions: dict = self.safe_dict(self.options, 'ws', {})
@@ -611,6 +652,7 @@ class upbit(ccxt.async_support.upbit):
611
652
  'trade': self.handle_trades,
612
653
  'myOrder': self.handle_my_order,
613
654
  'myAsset': self.handle_balance,
655
+ 'candle.1s': self.handle_ohlcv,
614
656
  }
615
657
  methodName = self.safe_string(message, 'type')
616
658
  method = self.safe_value(methods, methodName)
ccxt/test/tests_async.py CHANGED
@@ -348,7 +348,6 @@ class testMainClass:
348
348
  'fetchOHLCV': [symbol],
349
349
  'fetchTrades': [symbol],
350
350
  'fetchOrderBook': [symbol],
351
- 'fetchL2OrderBook': [symbol],
352
351
  'fetchOrderBooks': [],
353
352
  'fetchBidsAsks': [],
354
353
  'fetchStatus': [],
ccxt/test/tests_sync.py CHANGED
@@ -345,7 +345,6 @@ class testMainClass:
345
345
  'fetchOHLCV': [symbol],
346
346
  'fetchTrades': [symbol],
347
347
  'fetchOrderBook': [symbol],
348
- 'fetchL2OrderBook': [symbol],
349
348
  'fetchOrderBooks': [],
350
349
  'fetchBidsAsks': [],
351
350
  'fetchStatus': [],
ccxt/timex.py CHANGED
@@ -1526,7 +1526,7 @@ class timex(Exchange, ImplicitAPI):
1526
1526
  'cost': feeCost,
1527
1527
  'currency': feeCurrency,
1528
1528
  }
1529
- return {
1529
+ return self.safe_trade({
1530
1530
  'info': trade,
1531
1531
  'id': id,
1532
1532
  'timestamp': timestamp,
@@ -1540,7 +1540,7 @@ class timex(Exchange, ImplicitAPI):
1540
1540
  'cost': cost,
1541
1541
  'takerOrMaker': takerOrMaker,
1542
1542
  'fee': fee,
1543
- }
1543
+ })
1544
1544
 
1545
1545
  def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
1546
1546
  #