ccxt 4.3.98__py2.py3-none-any.whl → 4.4.2__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
ccxt/pro/hyperliquid.py CHANGED
@@ -5,9 +5,10 @@
5
5
 
6
6
  import ccxt.async_support
7
7
  from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById, ArrayCacheByTimestamp
8
- from ccxt.base.types import Any, Int, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade
8
+ from ccxt.base.types import Int, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade
9
9
  from ccxt.async_support.base.ws.client import Client
10
10
  from typing import List
11
+ from typing import Any
11
12
  from ccxt.base.errors import ExchangeError
12
13
 
13
14
 
@@ -160,6 +161,32 @@ class hyperliquid(ccxt.async_support.hyperliquid):
160
161
  orderbook = await self.watch(url, messageHash, message, messageHash)
161
162
  return orderbook.limit()
162
163
 
164
+ async def un_watch_order_book(self, symbol: str, params={}) -> Any:
165
+ """
166
+ unWatches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
167
+ :see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions
168
+ :param str symbol: unified symbol of the market to fetch the order book for
169
+ :param dict [params]: extra parameters specific to the exchange API endpoint
170
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
171
+ """
172
+ await self.load_markets()
173
+ market = self.market(symbol)
174
+ symbol = market['symbol']
175
+ subMessageHash = 'orderbook:' + symbol
176
+ messageHash = 'unsubscribe:' + subMessageHash
177
+ url = self.urls['api']['ws']['public']
178
+ id = str(self.nonce())
179
+ request: dict = {
180
+ 'id': id,
181
+ 'method': 'unsubscribe',
182
+ 'subscription': {
183
+ 'type': 'l2Book',
184
+ 'coin': market['base'] if market['swap'] else market['id'],
185
+ },
186
+ }
187
+ message = self.extend(request, params)
188
+ return await self.watch(url, messageHash, message, messageHash)
189
+
163
190
  def handle_order_book(self, client, message):
164
191
  #
165
192
  # {
@@ -230,6 +257,28 @@ class hyperliquid(ccxt.async_support.hyperliquid):
230
257
  return self.filter_by_array_tickers(tickers, 'symbol', symbols)
231
258
  return self.tickers
232
259
 
260
+ async def un_watch_tickers(self, symbols: Strings = None, params={}) -> Any:
261
+ """
262
+ unWatches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
263
+ :see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions
264
+ :param str[] symbols: unified symbol of the market to fetch the ticker for
265
+ :param dict [params]: extra parameters specific to the exchange API endpoint
266
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
267
+ """
268
+ await self.load_markets()
269
+ symbols = self.market_symbols(symbols, None, True)
270
+ subMessageHash = 'tickers'
271
+ messageHash = 'unsubscribe:' + subMessageHash
272
+ url = self.urls['api']['ws']['public']
273
+ request: dict = {
274
+ 'method': 'unsubscribe',
275
+ 'subscription': {
276
+ 'type': 'webData2', # allMids
277
+ 'user': '0x0000000000000000000000000000000000000000',
278
+ },
279
+ }
280
+ return await self.watch(url, messageHash, self.extend(request, params), messageHash)
281
+
233
282
  async def watch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
234
283
  """
235
284
  watches information on multiple trades made by the user
@@ -392,15 +441,17 @@ class hyperliquid(ccxt.async_support.hyperliquid):
392
441
  client.resolve(trades, messageHash)
393
442
 
394
443
  async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
395
- """
396
- watches information on multiple trades made in a market
397
- :see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions
398
- :param str symbol: unified market symbol of the market trades were made in
399
- :param int [since]: the earliest time in ms to fetch trades for
400
- :param int [limit]: the maximum number of trade structures to retrieve
401
- :param dict [params]: extra parameters specific to the exchange API endpoint
402
- :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
403
- """
444
+ # s
445
+ # @method
446
+ # @name hyperliquid#watchTrades
447
+ # @description watches information on multiple trades made in a market
448
+ # @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions
449
+ # @param {string} symbol unified market symbol of the market trades were made in
450
+ # @param {int} [since] the earliest time in ms to fetch trades for
451
+ # @param {int} [limit] the maximum number of trade structures to retrieve
452
+ # @param {object} [params] extra parameters specific to the exchange API endpoint
453
+ # @returns {object[]} a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
454
+ #
404
455
  await self.load_markets()
405
456
  market = self.market(symbol)
406
457
  symbol = market['symbol']
@@ -419,6 +470,30 @@ class hyperliquid(ccxt.async_support.hyperliquid):
419
470
  limit = trades.getLimit(symbol, limit)
420
471
  return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
421
472
 
473
+ async def un_watch_trades(self, symbol: str, params={}) -> Any:
474
+ """
475
+ unWatches information on multiple trades made in a market
476
+ :see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions
477
+ :param str symbol: unified market symbol of the market trades were made in
478
+ :param dict [params]: extra parameters specific to the exchange API endpoint
479
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
480
+ """
481
+ await self.load_markets()
482
+ market = self.market(symbol)
483
+ symbol = market['symbol']
484
+ subMessageHash = 'trade:' + symbol
485
+ messageHash = 'unsubscribe:' + subMessageHash
486
+ url = self.urls['api']['ws']['public']
487
+ request: dict = {
488
+ 'method': 'unsubscribe',
489
+ 'subscription': {
490
+ 'type': 'trades',
491
+ 'coin': market['base'] if market['swap'] else market['id'],
492
+ },
493
+ }
494
+ message = self.extend(request, params)
495
+ return await self.watch(url, messageHash, message, messageHash)
496
+
422
497
  def handle_trades(self, client: Client, message):
423
498
  #
424
499
  # {
@@ -546,6 +621,32 @@ class hyperliquid(ccxt.async_support.hyperliquid):
546
621
  limit = ohlcv.getLimit(symbol, limit)
547
622
  return self.filter_by_since_limit(ohlcv, since, limit, 0, True)
548
623
 
624
+ async def un_watch_ohlcv(self, symbol: str, timeframe='1m', params={}) -> Any:
625
+ """
626
+ watches historical candlestick data containing the open, high, low, close price, and the volume of a market
627
+ :see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions
628
+ :param str symbol: unified symbol of the market to fetch OHLCV data for
629
+ :param str timeframe: the length of time each candle represents
630
+ :param dict [params]: extra parameters specific to the exchange API endpoint
631
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
632
+ """
633
+ await self.load_markets()
634
+ market = self.market(symbol)
635
+ symbol = market['symbol']
636
+ url = self.urls['api']['ws']['public']
637
+ request: dict = {
638
+ 'method': 'unsubscribe',
639
+ 'subscription': {
640
+ 'type': 'candle',
641
+ 'coin': market['base'] if market['swap'] else market['id'],
642
+ 'interval': timeframe,
643
+ },
644
+ }
645
+ subMessageHash = 'candles:' + timeframe + ':' + symbol
646
+ messagehash = 'unsubscribe:' + subMessageHash
647
+ message = self.extend(request, params)
648
+ return await self.watch(url, messagehash, message, messagehash)
649
+
549
650
  def handle_ohlcv(self, client: Client, message):
550
651
  #
551
652
  # {
@@ -581,7 +682,7 @@ class hyperliquid(ccxt.async_support.hyperliquid):
581
682
  messageHash = 'candles:' + timeframe + ':' + symbol
582
683
  client.resolve(ohlcv, messageHash)
583
684
 
584
- def handle_ws_post(self, client: Client, message: Any):
685
+ def handle_ws_post(self, client: Client, message: dict):
585
686
  # {
586
687
  # channel: "post",
587
688
  # data: {
@@ -689,7 +790,111 @@ class hyperliquid(ccxt.async_support.hyperliquid):
689
790
  else:
690
791
  return False
691
792
 
793
+ def handle_order_book_unsubscription(self, client: Client, subscription: dict):
794
+ #
795
+ # "subscription":{
796
+ # "type":"l2Book",
797
+ # "coin":"BTC",
798
+ # "nSigFigs":5,
799
+ # "mantissa":null
800
+ # }
801
+ #
802
+ coin = self.safe_string(subscription, 'coin')
803
+ marketId = self.coinToMarketId(coin)
804
+ symbol = self.safe_symbol(marketId)
805
+ subMessageHash = 'orderbook:' + symbol
806
+ messageHash = 'unsubscribe:' + subMessageHash
807
+ self.clean_unsubscription(client, subMessageHash, messageHash)
808
+ if symbol in self.orderbooks:
809
+ del self.orderbooks[symbol]
810
+
811
+ def handle_trades_unsubscription(self, client: Client, subscription: dict):
812
+ #
813
+ coin = self.safe_string(subscription, 'coin')
814
+ marketId = self.coinToMarketId(coin)
815
+ symbol = self.safe_symbol(marketId)
816
+ subMessageHash = 'trade:' + symbol
817
+ messageHash = 'unsubscribe:' + subMessageHash
818
+ self.clean_unsubscription(client, subMessageHash, messageHash)
819
+ if symbol in self.trades:
820
+ del self.trades[symbol]
821
+
822
+ def handle_tickers_unsubscription(self, client: Client, subscription: dict):
823
+ #
824
+ subMessageHash = 'tickers'
825
+ messageHash = 'unsubscribe:' + subMessageHash
826
+ self.clean_unsubscription(client, subMessageHash, messageHash)
827
+ symbols = list(self.tickers.keys())
828
+ for i in range(0, len(symbols)):
829
+ del self.tickers[symbols[i]]
830
+
831
+ def handle_ohlcv_unsubscription(self, client: Client, subscription: dict):
832
+ coin = self.safe_string(subscription, 'coin')
833
+ marketId = self.coinToMarketId(coin)
834
+ symbol = self.safe_symbol(marketId)
835
+ interval = self.safe_string(subscription, 'interval')
836
+ timeframe = self.find_timeframe(interval)
837
+ subMessageHash = 'candles:' + timeframe + ':' + symbol
838
+ messageHash = 'unsubscribe:' + subMessageHash
839
+ self.clean_unsubscription(client, subMessageHash, messageHash)
840
+ if symbol in self.ohlcvs:
841
+ if timeframe in self.ohlcvs[symbol]:
842
+ del self.ohlcvs[symbol][timeframe]
843
+
844
+ def handle_subscription_response(self, client: Client, message):
845
+ # {
846
+ # "channel":"subscriptionResponse",
847
+ # "data":{
848
+ # "method":"unsubscribe",
849
+ # "subscription":{
850
+ # "type":"l2Book",
851
+ # "coin":"BTC",
852
+ # "nSigFigs":5,
853
+ # "mantissa":null
854
+ # }
855
+ # }
856
+ # }
857
+ #
858
+ # {
859
+ # "channel":"subscriptionResponse",
860
+ # "data":{
861
+ # "method":"unsubscribe",
862
+ # "subscription":{
863
+ # "type":"trades",
864
+ # "coin":"PURR/USDC"
865
+ # }
866
+ # }
867
+ # }
868
+ #
869
+ data = self.safe_dict(message, 'data', {})
870
+ method = self.safe_string(data, 'method')
871
+ if method == 'unsubscribe':
872
+ subscription = self.safe_dict(data, 'subscription', {})
873
+ type = self.safe_string(subscription, 'type')
874
+ if type == 'l2Book':
875
+ self.handle_order_book_unsubscription(client, subscription)
876
+ elif type == 'trades':
877
+ self.handle_trades_unsubscription(client, subscription)
878
+ elif type == 'webData2':
879
+ self.handle_tickers_unsubscription(client, subscription)
880
+ elif type == 'candle':
881
+ self.handle_ohlcv_unsubscription(client, subscription)
882
+
692
883
  def handle_message(self, client: Client, message):
884
+ #
885
+ # {
886
+ # "channel":"subscriptionResponse",
887
+ # "data":{
888
+ # "method":"unsubscribe",
889
+ # "subscription":{
890
+ # "type":"l2Book",
891
+ # "coin":"BTC",
892
+ # "nSigFigs":5,
893
+ # "mantissa":null
894
+ # }
895
+ # }
896
+ # }
897
+ #
693
898
  if self.handle_error_message(client, message):
694
899
  return
695
900
  topic = self.safe_string(message, 'channel', '')
@@ -702,6 +907,7 @@ class hyperliquid(ccxt.async_support.hyperliquid):
702
907
  'userFills': self.handle_my_trades,
703
908
  'webData2': self.handle_ws_tickers,
704
909
  'post': self.handle_ws_post,
910
+ 'subscriptionResponse': self.handle_subscription_response,
705
911
  }
706
912
  exacMethod = self.safe_value(methods, topic)
707
913
  if exacMethod is not None:
ccxt/pro/kucoin.py CHANGED
@@ -11,7 +11,6 @@ from typing import List
11
11
  from typing import Any
12
12
  from ccxt.base.errors import ExchangeError
13
13
  from ccxt.base.errors import ArgumentsRequired
14
- from ccxt.base.errors import UnsubscribeError
15
14
 
16
15
 
17
16
  class kucoin(ccxt.async_support.kucoin):
@@ -502,8 +501,6 @@ class kucoin(ccxt.async_support.kucoin):
502
501
  unWatches trades stream
503
502
  :see: https://www.kucoin.com/docs/websocket/spot-trading/public-channels/match-execution-data
504
503
  :param str symbol: unified symbol of the market to fetch trades for
505
- :param int [since]: timestamp in ms of the earliest trade to fetch
506
- :param int [limit]: the maximum amount of trades to fetch
507
504
  :param dict [params]: extra parameters specific to the exchange API endpoint
508
505
  :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
509
506
  """
@@ -851,46 +848,8 @@ class kucoin(ccxt.async_support.kucoin):
851
848
  for i in range(0, len(messageHashes)):
852
849
  messageHash = messageHashes[i]
853
850
  subHash = subMessageHashes[i]
854
- if messageHash in client.subscriptions:
855
- del client.subscriptions[messageHash]
856
- if subHash in client.subscriptions:
857
- del client.subscriptions[subHash]
858
- error = UnsubscribeError(self.id + ' ' + subHash)
859
- client.reject(error, subHash)
860
- client.resolve(True, messageHash)
861
- self.clean_cache(subscription)
862
-
863
- def clean_cache(self, subscription: dict):
864
- topic = self.safe_string(subscription, 'topic')
865
- symbols = self.safe_list(subscription, 'symbols', [])
866
- symbolsLength = len(symbols)
867
- if symbolsLength > 0:
868
- for i in range(0, len(symbols)):
869
- symbol = symbols[i]
870
- if topic == 'trades':
871
- if symbol in self.trades:
872
- del self.trades[symbol]
873
- elif topic == 'orderbook':
874
- if symbol in self.orderbooks:
875
- del self.orderbooks[symbol]
876
- elif topic == 'ticker':
877
- if symbol in self.tickers:
878
- del self.tickers[symbol]
879
- else:
880
- if topic == 'myTrades':
881
- # don't reset self.myTrades directly here
882
- # because in c# we need to use a different object
883
- keys = list(self.myTrades.keys())
884
- for i in range(0, len(keys)):
885
- del self.myTrades[keys[i]]
886
- elif topic == 'orders':
887
- orderSymbols = list(self.orders.keys())
888
- for i in range(0, len(orderSymbols)):
889
- del self.orders[orderSymbols[i]]
890
- elif topic == 'ticker':
891
- tickerSymbols = list(self.tickers.keys())
892
- for i in range(0, len(tickerSymbols)):
893
- del self.tickers[tickerSymbols[i]]
851
+ self.clean_unsubscription(client, subHash, messageHash)
852
+ self.clean_cache(subscription)
894
853
 
895
854
  def handle_system_status(self, client: Client, message):
896
855
  #
ccxt/pro/kucoinfutures.py CHANGED
@@ -8,6 +8,7 @@ from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById,
8
8
  from ccxt.base.types import Balances, Int, Order, OrderBook, Position, Str, Strings, Ticker, Tickers, Trade
9
9
  from ccxt.async_support.base.ws.client import Client
10
10
  from typing import List
11
+ from typing import Any
11
12
  from ccxt.base.errors import ExchangeError
12
13
  from ccxt.base.errors import ArgumentsRequired
13
14
 
@@ -175,6 +176,24 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
175
176
  }
176
177
  return await self.watch_multiple(url, messageHashes, self.extend(request, params), subscriptionHashes, subscriptionArgs)
177
178
 
179
+ async def un_subscribe_multiple(self, url, messageHashes, topic, subscriptionHashes, params={}, subscription: dict = None):
180
+ requestId = str(self.request_id())
181
+ request: dict = {
182
+ 'id': requestId,
183
+ 'type': 'unsubscribe',
184
+ 'topic': topic,
185
+ 'response': True,
186
+ }
187
+ message = self.extend(request, params)
188
+ if subscription is not None:
189
+ subscription[requestId] = requestId
190
+ client = self.client(url)
191
+ for i in range(0, len(subscriptionHashes)):
192
+ subscriptionHash = subscriptionHashes[i]
193
+ if not (subscriptionHash in client.subscriptions):
194
+ client.subscriptions[requestId] = subscriptionHash
195
+ return await self.watch_multiple(url, messageHashes, message, subscriptionHashes, subscription)
196
+
178
197
  async def watch_ticker(self, symbol: str, params={}) -> Ticker:
179
198
  """
180
199
  watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
@@ -526,6 +545,44 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
526
545
  limit = trades.getLimit(tradeSymbol, limit)
527
546
  return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
528
547
 
548
+ async def un_watch_trades(self, symbol: str, params={}) -> Any:
549
+ """
550
+ unWatches trades stream
551
+ :see: https://docs.kucoin.com/futures/#execution-data
552
+ :param str symbol: unified symbol of the market to fetch trades for
553
+ :param dict [params]: extra parameters specific to the exchange API endpoint
554
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
555
+ """
556
+ return await self.un_watch_trades_for_symbols([symbol], params)
557
+
558
+ async def un_watch_trades_for_symbols(self, symbols: List[str], params={}) -> Any:
559
+ """
560
+ get the list of most recent trades for a particular symbol
561
+ :param str symbol: unified symbol of the market to fetch trades for
562
+ :param dict [params]: extra parameters specific to the exchange API endpoint
563
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
564
+ """
565
+ await self.load_markets()
566
+ symbols = self.market_symbols(symbols, None, False)
567
+ url = await self.negotiate(False)
568
+ symbols = self.market_symbols(symbols)
569
+ marketIds = self.market_ids(symbols)
570
+ topic = '/contractMarket/execution:' + ','.join(marketIds)
571
+ subscriptionHashes = []
572
+ messageHashes = []
573
+ for i in range(0, len(symbols)):
574
+ symbol = symbols[i]
575
+ messageHashes.append('unsubscribe:trades:' + symbol)
576
+ subscriptionHashes.append('trades:' + symbol)
577
+ subscription = {
578
+ 'messageHashes': messageHashes,
579
+ 'subMessageHashes': subscriptionHashes,
580
+ 'topic': 'trades',
581
+ 'unsubscribe': True,
582
+ 'symbols': symbols,
583
+ }
584
+ return await self.un_subscribe_multiple(url, messageHashes, topic, messageHashes, params, subscription)
585
+
529
586
  def handle_trade(self, client: Client, message):
530
587
  #
531
588
  # {
@@ -651,6 +708,7 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
651
708
  async def watch_order_book_for_symbols(self, symbols: List[str], limit: Int = None, params={}) -> OrderBook:
652
709
  """
653
710
  watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
711
+ :see: https://docs.kucoin.com/futures/#level-2-market-data
654
712
  :param str[] symbols: unified array of symbols
655
713
  :param int [limit]: the maximum amount of order book entries to return
656
714
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -680,6 +738,43 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
680
738
  orderbook = await self.subscribe_multiple(url, messageHashes, topic, subscriptionHashes, subscriptionArgs, params)
681
739
  return orderbook.limit()
682
740
 
741
+ async def un_watch_order_book(self, symbol: str, params={}) -> Any:
742
+ """
743
+ unWatches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
744
+ :see: https://docs.kucoin.com/futures/#level-2-market-data
745
+ :param str symbol: unified symbol of the market to fetch the order book for
746
+ :param dict [params]: extra parameters specific to the exchange API endpoint
747
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
748
+ """
749
+ return await self.un_watch_order_book_for_symbols([symbol], params)
750
+
751
+ async def un_watch_order_book_for_symbols(self, symbols: List[str], params={}) -> Any:
752
+ """
753
+ unWatches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
754
+ :param str[] symbols: unified array of symbols
755
+ :param dict [params]: extra parameters specific to the exchange API endpoint
756
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
757
+ """
758
+ await self.load_markets()
759
+ symbols = self.market_symbols(symbols)
760
+ marketIds = self.market_ids(symbols)
761
+ url = await self.negotiate(False)
762
+ topic = '/contractMarket/level2:' + ','.join(marketIds)
763
+ subscriptionHashes = []
764
+ messageHashes = []
765
+ for i in range(0, len(symbols)):
766
+ symbol = symbols[i]
767
+ messageHashes.append('unsubscribe:orderbook:' + symbol)
768
+ subscriptionHashes.append('orderbook:' + symbol)
769
+ subscription = {
770
+ 'messageHashes': messageHashes,
771
+ 'symbols': symbols,
772
+ 'unsubscribe': True,
773
+ 'topic': 'orderbook',
774
+ 'subMessageHashes': subscriptionHashes,
775
+ }
776
+ return await self.un_subscribe_multiple(url, messageHashes, topic, messageHashes, params, subscription)
777
+
683
778
  def handle_delta(self, orderbook, delta):
684
779
  orderbook['nonce'] = self.safe_integer(delta, 'sequence')
685
780
  timestamp = self.safe_integer(delta, 'timestamp')
@@ -1067,6 +1162,32 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
1067
1162
  self.options['urls'][type] = None
1068
1163
  self.handle_errors(None, None, client.url, None, None, data, message, None, None)
1069
1164
 
1165
+ def handle_subscription_status(self, client: Client, message):
1166
+ #
1167
+ # {
1168
+ # "id": "1578090438322",
1169
+ # "type": "ack"
1170
+ # }
1171
+ #
1172
+ id = self.safe_string(message, 'id')
1173
+ if not (id in client.subscriptions):
1174
+ return
1175
+ subscriptionHash = self.safe_string(client.subscriptions, id)
1176
+ subscription = self.safe_value(client.subscriptions, subscriptionHash)
1177
+ del client.subscriptions[id]
1178
+ method = self.safe_value(subscription, 'method')
1179
+ if method is not None:
1180
+ method(client, message, subscription)
1181
+ isUnSub = self.safe_bool(subscription, 'unsubscribe', False)
1182
+ if isUnSub:
1183
+ messageHashes = self.safe_list(subscription, 'messageHashes', [])
1184
+ subMessageHashes = self.safe_list(subscription, 'subMessageHashes', [])
1185
+ for i in range(0, len(messageHashes)):
1186
+ messageHash = messageHashes[i]
1187
+ subHash = subMessageHashes[i]
1188
+ self.clean_unsubscription(client, subHash, messageHash)
1189
+ self.clean_cache(subscription)
1190
+
1070
1191
  def handle_message(self, client: Client, message):
1071
1192
  type = self.safe_string(message, 'type')
1072
1193
  methods: dict = {
@@ -1075,6 +1196,7 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
1075
1196
  'message': self.handle_subject,
1076
1197
  'pong': self.handle_pong,
1077
1198
  'error': self.handle_error_message,
1199
+ 'ack': self.handle_subscription_status,
1078
1200
  }
1079
1201
  method = self.safe_value(methods, type)
1080
1202
  if method is not None:
ccxt/pro/okx.py CHANGED
@@ -16,7 +16,6 @@ from ccxt.base.errors import ArgumentsRequired
16
16
  from ccxt.base.errors import BadRequest
17
17
  from ccxt.base.errors import InvalidNonce
18
18
  from ccxt.base.errors import ChecksumError
19
- from ccxt.base.errors import UnsubscribeError
20
19
 
21
20
 
22
21
  class okx(ccxt.async_support.okx):
@@ -2162,54 +2161,32 @@ class okx(ccxt.async_support.okx):
2162
2161
  def handle_un_subscription_trades(self, client: Client, symbol: str):
2163
2162
  subMessageHash = 'trades:' + symbol
2164
2163
  messageHash = 'unsubscribe:trades:' + symbol
2165
- if subMessageHash in client.subscriptions:
2166
- del client.subscriptions[subMessageHash]
2167
- if messageHash in client.subscriptions:
2168
- del client.subscriptions[messageHash]
2169
- del self.trades[symbol]
2170
- error = UnsubscribeError(self.id + ' ' + subMessageHash)
2171
- client.reject(error, subMessageHash)
2172
- client.resolve(True, messageHash)
2164
+ self.clean_unsubscription(client, subMessageHash, messageHash)
2165
+ if symbol in self.trades:
2166
+ del self.trades[symbol]
2173
2167
 
2174
2168
  def handle_unsubscription_order_book(self, client: Client, symbol: str, channel: str):
2175
2169
  subMessageHash = channel + ':' + symbol
2176
2170
  messageHash = 'unsubscribe:orderbook:' + symbol
2177
- if subMessageHash in client.subscriptions:
2178
- del client.subscriptions[subMessageHash]
2179
- if messageHash in client.subscriptions:
2180
- del client.subscriptions[messageHash]
2181
- del self.orderbooks[symbol]
2182
- error = UnsubscribeError(self.id + ' ' + subMessageHash)
2183
- client.reject(error, subMessageHash)
2184
- client.resolve(True, messageHash)
2171
+ self.clean_unsubscription(client, subMessageHash, messageHash)
2172
+ if symbol in self.orderbooks:
2173
+ del self.orderbooks[symbol]
2185
2174
 
2186
2175
  def handle_unsubscription_ohlcv(self, client: Client, symbol: str, channel: str):
2187
2176
  tf = channel.replace('candle', '')
2188
2177
  timeframe = self.find_timeframe(tf)
2189
2178
  subMessageHash = 'multi:' + channel + ':' + symbol
2190
2179
  messageHash = 'unsubscribe:' + subMessageHash
2191
- if subMessageHash in client.subscriptions:
2192
- del client.subscriptions[subMessageHash]
2193
- if messageHash in client.subscriptions:
2194
- del client.subscriptions[messageHash]
2180
+ self.clean_unsubscription(client, subMessageHash, messageHash)
2195
2181
  if timeframe in self.ohlcvs[symbol]:
2196
2182
  del self.ohlcvs[symbol][timeframe]
2197
- error = UnsubscribeError(self.id + ' ' + subMessageHash)
2198
- client.reject(error, subMessageHash)
2199
- client.resolve(True, messageHash)
2200
2183
 
2201
2184
  def handle_unsubscription_ticker(self, client: Client, symbol: str, channel):
2202
2185
  subMessageHash = channel + '::' + symbol
2203
2186
  messageHash = 'unsubscribe:ticker:' + symbol
2204
- if subMessageHash in client.subscriptions:
2205
- del client.subscriptions[subMessageHash]
2206
- if messageHash in client.subscriptions:
2207
- del client.subscriptions[messageHash]
2187
+ self.clean_unsubscription(client, subMessageHash, messageHash)
2208
2188
  if symbol in self.tickers:
2209
2189
  del self.tickers[symbol]
2210
- error = UnsubscribeError(self.id + ' ' + subMessageHash)
2211
- client.reject(error, subMessageHash)
2212
- client.resolve(True, messageHash)
2213
2190
 
2214
2191
  def handle_unsubscription(self, client: Client, message):
2215
2192
  #
ccxt/xt.py CHANGED
@@ -1355,7 +1355,7 @@ class xt(Exchange, ImplicitAPI):
1355
1355
  self.safe_number(ohlcv, 'h'),
1356
1356
  self.safe_number(ohlcv, 'l'),
1357
1357
  self.safe_number(ohlcv, 'c'),
1358
- self.safe_number_2(ohlcv, volumeIndex, 'v'),
1358
+ self.safe_number_2(ohlcv, 'q', volumeIndex),
1359
1359
  ]
1360
1360
 
1361
1361
  def fetch_order_book(self, symbol: str, limit: Int = None, params={}):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ccxt
3
- Version: 4.3.98
3
+ Version: 4.4.2
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
@@ -95,7 +95,7 @@ Current feature list:
95
95
  | [![coinbase](https://user-images.githubusercontent.com/1294454/40811661-b6eceae2-653a-11e8-829e-10bfadb078cf.jpg)](https://www.coinbase.com/join/58cbe25a355148797479dbd2) | coinbase | [Coinbase Advanced](https://www.coinbase.com/join/58cbe25a355148797479dbd2) | [![API Version 2](https://img.shields.io/badge/2-lightgray)](https://developers.coinbase.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) | |
96
96
  | [![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) | cex | [![CCXT Certified](https://img.shields.io/badge/CCXT-Certified-green.svg)](https://github.com/ccxt/ccxt/wiki/Certification) | [![CCXT Pro](https://img.shields.io/badge/CCXT-Pro-black)](https://ccxt.pro) | |
97
97
  | [![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) | |
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
+ | [![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 75% discount!](https://img.shields.io/static/v1?label=Fee&message=%2d75%25&color=orange)](https://crypto.com/exch/kdacthrnxt) |
99
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
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) | |
101
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) |
@@ -272,13 +272,13 @@ console.log(version, Object.keys(exchanges));
272
272
 
273
273
  All-in-one browser bundle (dependencies included), served from a CDN of your choice:
274
274
 
275
- * jsDelivr: https://cdn.jsdelivr.net/npm/ccxt@4.3.98/dist/ccxt.browser.min.js
276
- * unpkg: https://unpkg.com/ccxt@4.3.98/dist/ccxt.browser.min.js
275
+ * jsDelivr: https://cdn.jsdelivr.net/npm/ccxt@4.4.2/dist/ccxt.browser.min.js
276
+ * unpkg: https://unpkg.com/ccxt@4.4.2/dist/ccxt.browser.min.js
277
277
 
278
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.
279
279
 
280
280
  ```HTML
281
- <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ccxt@4.3.98/dist/ccxt.browser.min.js"></script>
281
+ <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ccxt@4.4.2/dist/ccxt.browser.min.js"></script>
282
282
  ```
283
283
 
284
284
  Creates a global `ccxt` object: