ccxt 4.3.95__py2.py3-none-any.whl → 4.3.97__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/gate.py CHANGED
@@ -9,12 +9,14 @@ import hashlib
9
9
  from ccxt.base.types import Balances, Int, Liquidation, Market, MarketType, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, Trade
10
10
  from ccxt.async_support.base.ws.client import Client
11
11
  from typing import List
12
+ from typing import Any
12
13
  from ccxt.base.errors import ExchangeError
13
14
  from ccxt.base.errors import AuthenticationError
14
15
  from ccxt.base.errors import ArgumentsRequired
15
16
  from ccxt.base.errors import BadRequest
16
17
  from ccxt.base.errors import NotSupported
17
18
  from ccxt.base.errors import ChecksumError
19
+ from ccxt.base.errors import UnsubscribeError
18
20
  from ccxt.base.precise import Precise
19
21
 
20
22
 
@@ -371,6 +373,31 @@ class gate(ccxt.async_support.gate):
371
373
  orderbook = await self.subscribe_public(url, messageHash, payload, channel, query, subscription)
372
374
  return orderbook.limit()
373
375
 
376
+ async def un_watch_order_book(self, symbol: str, params={}) -> Any:
377
+ """
378
+ unWatches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
379
+ :param str symbol: unified symbol of the market to fetch the order book for
380
+ :param dict [params]: extra parameters specific to the exchange API endpoint
381
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
382
+ """
383
+ await self.load_markets()
384
+ market = self.market(symbol)
385
+ symbol = market['symbol']
386
+ marketId = market['id']
387
+ interval = '100ms'
388
+ interval, params = self.handle_option_and_params(params, 'watchOrderBook', 'interval', interval)
389
+ messageType = self.get_type_by_market(market)
390
+ channel = messageType + '.order_book_update'
391
+ subMessageHash = 'orderbook' + ':' + symbol
392
+ messageHash = 'unsubscribe:orderbook' + ':' + symbol
393
+ url = self.get_url_by_market(market)
394
+ payload = [marketId, interval]
395
+ limit = self.safe_integer(params, 'limit', 100)
396
+ if market['contract']:
397
+ stringLimit = str(limit)
398
+ payload.append(stringLimit)
399
+ return await self.un_subscribe_public_multiple(url, 'orderbook', [symbol], [messageHash], [subMessageHash], payload, channel, params)
400
+
374
401
  def handle_order_book_subscription(self, client: Client, message, subscription):
375
402
  symbol = self.safe_string(subscription, 'symbol')
376
403
  limit = self.safe_integer(subscription, 'limit')
@@ -671,6 +698,37 @@ class gate(ccxt.async_support.gate):
671
698
  limit = trades.getLimit(tradeSymbol, limit)
672
699
  return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
673
700
 
701
+ async def un_watch_trades_for_symbols(self, symbols: List[str], params={}) -> Any:
702
+ """
703
+ get the list of most recent trades for a particular symbol
704
+ :param str symbol: unified symbol of the market to fetch trades for
705
+ :param dict [params]: extra parameters specific to the exchange API endpoint
706
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
707
+ """
708
+ await self.load_markets()
709
+ symbols = self.market_symbols(symbols)
710
+ marketIds = self.market_ids(symbols)
711
+ market = self.market(symbols[0])
712
+ messageType = self.get_type_by_market(market)
713
+ channel = messageType + '.trades'
714
+ subMessageHashes = []
715
+ messageHashes = []
716
+ for i in range(0, len(symbols)):
717
+ symbol = symbols[i]
718
+ subMessageHashes.append('trades:' + symbol)
719
+ messageHashes.append('unsubscribe:trades:' + symbol)
720
+ url = self.get_url_by_market(market)
721
+ return await self.un_subscribe_public_multiple(url, 'trades', symbols, messageHashes, subMessageHashes, marketIds, channel, params)
722
+
723
+ async def un_watch_trades(self, symbol: str, params={}) -> Any:
724
+ """
725
+ get the list of most recent trades for a particular symbol
726
+ :param str symbol: unified symbol of the market to fetch trades for
727
+ :param dict [params]: extra parameters specific to the exchange API endpoint
728
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
729
+ """
730
+ return await self.un_watch_trades_for_symbols([symbol], params)
731
+
674
732
  def handle_trades(self, client: Client, message):
675
733
  #
676
734
  # {
@@ -1445,6 +1503,79 @@ class gate(ccxt.async_support.gate):
1445
1503
  if id in client.subscriptions:
1446
1504
  del client.subscriptions[id]
1447
1505
 
1506
+ def handle_un_subscribe(self, client: Client, message):
1507
+ #
1508
+ # {
1509
+ # "time":1725534679,
1510
+ # "time_ms":1725534679786,
1511
+ # "id":2,
1512
+ # "conn_id":"fac539b443fd7002",
1513
+ # "trace_id":"efe1d282b630b4aa266b84bee177791a",
1514
+ # "channel":"spot.trades",
1515
+ # "event":"unsubscribe",
1516
+ # "payload":[
1517
+ # "LTC_USDT"
1518
+ # ],
1519
+ # "result":{
1520
+ # "status":"success"
1521
+ # },
1522
+ # "requestId":"efe1d282b630b4aa266b84bee177791a"
1523
+ # }
1524
+ #
1525
+ id = self.safe_string(message, 'id')
1526
+ keys = list(client.subscriptions.keys())
1527
+ for i in range(0, len(keys)):
1528
+ messageHash = keys[i]
1529
+ if not (messageHash in client.subscriptions):
1530
+ continue
1531
+ # the previous iteration can have deleted the messageHash from the subscriptions
1532
+ if messageHash.startswith('unsubscribe'):
1533
+ subscription = client.subscriptions[messageHash]
1534
+ subId = self.safe_string(subscription, 'id')
1535
+ if id != subId:
1536
+ continue
1537
+ messageHashes = self.safe_list(subscription, 'messageHashes', [])
1538
+ subMessageHashes = self.safe_list(subscription, 'subMessageHashes', [])
1539
+ for j in range(0, len(messageHashes)):
1540
+ unsubHash = messageHashes[j]
1541
+ subHash = subMessageHashes[j]
1542
+ if unsubHash in client.subscriptions:
1543
+ del client.subscriptions[unsubHash]
1544
+ if subHash in client.subscriptions:
1545
+ del client.subscriptions[subHash]
1546
+ error = UnsubscribeError(self.id + ' ' + messageHash)
1547
+ client.reject(error, subHash)
1548
+ client.resolve(True, unsubHash)
1549
+ self.clean_cache(subscription)
1550
+
1551
+ def clean_cache(self, subscription: dict):
1552
+ topic = self.safe_string(subscription, 'topic', '')
1553
+ symbols = self.safe_list(subscription, 'symbols', [])
1554
+ symbolsLength = len(symbols)
1555
+ if topic == 'ohlcv':
1556
+ symbolsAndTimeFrames = self.safe_list(subscription, 'symbolsAndTimeframes', [])
1557
+ for i in range(0, len(symbolsAndTimeFrames)):
1558
+ symbolAndTimeFrame = symbolsAndTimeFrames[i]
1559
+ symbol = self.safe_string(symbolAndTimeFrame, 0)
1560
+ timeframe = self.safe_string(symbolAndTimeFrame, 1)
1561
+ del self.ohlcvs[symbol][timeframe]
1562
+ elif symbolsLength > 0:
1563
+ for i in range(0, len(symbols)):
1564
+ symbol = symbols[i]
1565
+ if topic.endswith('trades'):
1566
+ del self.trades[symbol]
1567
+ elif topic == 'orderbook':
1568
+ del self.orderbooks[symbol]
1569
+ elif topic == 'ticker':
1570
+ del self.tickers[symbol]
1571
+ else:
1572
+ if topic.endswith('trades'):
1573
+ # don't reset self.myTrades directly here
1574
+ # because in c# we need to use a different object
1575
+ keys = list(self.trades.keys())
1576
+ for i in range(0, len(keys)):
1577
+ del self.trades[keys[i]]
1578
+
1448
1579
  def handle_message(self, client: Client, message):
1449
1580
  #
1450
1581
  # subscribe
@@ -1541,6 +1672,9 @@ class gate(ccxt.async_support.gate):
1541
1672
  if event == 'subscribe':
1542
1673
  self.handle_subscription_status(client, message)
1543
1674
  return
1675
+ if event == 'unsubscribe':
1676
+ self.handle_un_subscribe(client, message)
1677
+ return
1544
1678
  channel = self.safe_string(message, 'channel', '')
1545
1679
  channelParts = channel.split('.')
1546
1680
  channelType = self.safe_value(channelParts, 1)
@@ -1645,6 +1779,27 @@ class gate(ccxt.async_support.gate):
1645
1779
  message = self.extend(request, params)
1646
1780
  return await self.watch_multiple(url, messageHashes, message, messageHashes)
1647
1781
 
1782
+ async def un_subscribe_public_multiple(self, url, topic, symbols, messageHashes, subMessageHashes, payload, channel, params={}):
1783
+ requestId = self.request_id()
1784
+ time = self.seconds()
1785
+ request: dict = {
1786
+ 'id': requestId,
1787
+ 'time': time,
1788
+ 'channel': channel,
1789
+ 'event': 'unsubscribe',
1790
+ 'payload': payload,
1791
+ }
1792
+ sub = {
1793
+ 'id': str(requestId),
1794
+ 'topic': topic,
1795
+ 'unsubscribe': True,
1796
+ 'messageHashes': messageHashes,
1797
+ 'subMessageHashes': subMessageHashes,
1798
+ 'symbols': symbols,
1799
+ }
1800
+ message = self.extend(request, params)
1801
+ return await self.watch_multiple(url, messageHashes, message, messageHashes, sub)
1802
+
1648
1803
  async def authenticate(self, url, messageType):
1649
1804
  channel = messageType + '.login'
1650
1805
  client = self.client(url)
ccxt/pro/kucoin.py CHANGED
@@ -8,8 +8,10 @@ from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById,
8
8
  from ccxt.base.types import 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 typing import Any
11
12
  from ccxt.base.errors import ExchangeError
12
13
  from ccxt.base.errors import ArgumentsRequired
14
+ from ccxt.base.errors import UnsubscribeError
13
15
 
14
16
 
15
17
  class kucoin(ccxt.async_support.kucoin):
@@ -153,6 +155,24 @@ class kucoin(ccxt.async_support.kucoin):
153
155
  client.subscriptions[requestId] = subscriptionHash
154
156
  return await self.watch_multiple(url, messageHashes, message, subscriptionHashes, subscription)
155
157
 
158
+ async def un_subscribe_multiple(self, url, messageHashes, topic, subscriptionHashes, params={}, subscription: dict = None):
159
+ requestId = str(self.request_id())
160
+ request: dict = {
161
+ 'id': requestId,
162
+ 'type': 'unsubscribe',
163
+ 'topic': topic,
164
+ 'response': True,
165
+ }
166
+ message = self.extend(request, params)
167
+ if subscription is not None:
168
+ subscription[requestId] = requestId
169
+ client = self.client(url)
170
+ for i in range(0, len(subscriptionHashes)):
171
+ subscriptionHash = subscriptionHashes[i]
172
+ if not (subscriptionHash in client.subscriptions):
173
+ client.subscriptions[requestId] = subscriptionHash
174
+ return await self.watch_multiple(url, messageHashes, message, subscriptionHashes, subscription)
175
+
156
176
  async def watch_ticker(self, symbol: str, params={}) -> Ticker:
157
177
  """
158
178
  watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
@@ -477,6 +497,46 @@ class kucoin(ccxt.async_support.kucoin):
477
497
  limit = trades.getLimit(tradeSymbol, limit)
478
498
  return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
479
499
 
500
+ async def un_watch_trades_for_symbols(self, symbols: List[str], params={}) -> Any:
501
+ """
502
+ unWatches trades stream
503
+ :see: https://www.kucoin.com/docs/websocket/spot-trading/public-channels/match-execution-data
504
+ :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
+ :param dict [params]: extra parameters specific to the exchange API endpoint
508
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
509
+ """
510
+ await self.load_markets()
511
+ symbols = self.market_symbols(symbols, None, False)
512
+ marketIds = self.market_ids(symbols)
513
+ url = await self.negotiate(False)
514
+ messageHashes = []
515
+ subscriptionHashes = []
516
+ topic = '/market/match:' + ','.join(marketIds)
517
+ for i in range(0, len(symbols)):
518
+ symbol = symbols[i]
519
+ messageHashes.append('unsubscribe:trades:' + symbol)
520
+ subscriptionHashes.append('trades:' + symbol)
521
+ subscription = {
522
+ 'messageHashes': messageHashes,
523
+ 'subMessageHashes': subscriptionHashes,
524
+ 'topic': 'trades',
525
+ 'unsubscribe': True,
526
+ 'symbols': symbols,
527
+ }
528
+ return await self.un_subscribe_multiple(url, messageHashes, topic, messageHashes, params, subscription)
529
+
530
+ async def un_watch_trades(self, symbol: str, params={}) -> Any:
531
+ """
532
+ unWatches trades stream
533
+ :see: https://www.kucoin.com/docs/websocket/spot-trading/public-channels/match-execution-data
534
+ :param str symbol: unified symbol of the market to fetch trades for
535
+ :param dict [params]: extra parameters specific to the exchange API endpoint
536
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
537
+ """
538
+ return await self.un_watch_trades_for_symbols([symbol], params)
539
+
480
540
  def handle_trade(self, client: Client, message):
481
541
  #
482
542
  # {
@@ -731,6 +791,53 @@ class kucoin(ccxt.async_support.kucoin):
731
791
  method = self.safe_value(subscription, 'method')
732
792
  if method is not None:
733
793
  method(client, message, subscription)
794
+ isUnSub = self.safe_bool(subscription, 'unsubscribe', False)
795
+ if isUnSub:
796
+ messageHashes = self.safe_list(subscription, 'messageHashes', [])
797
+ subMessageHashes = self.safe_list(subscription, 'subMessageHashes', [])
798
+ for i in range(0, len(messageHashes)):
799
+ messageHash = messageHashes[i]
800
+ subHash = subMessageHashes[i]
801
+ if messageHash in client.subscriptions:
802
+ del client.subscriptions[messageHash]
803
+ if subHash in client.subscriptions:
804
+ del client.subscriptions[subHash]
805
+ error = UnsubscribeError(self.id + ' ' + subHash)
806
+ client.reject(error, subHash)
807
+ client.resolve(True, messageHash)
808
+ self.clean_cache(subscription)
809
+
810
+ def clean_cache(self, subscription: dict):
811
+ topic = self.safe_string(subscription, 'topic')
812
+ symbols = self.safe_list(subscription, 'symbols', [])
813
+ symbolsLength = len(symbols)
814
+ if symbolsLength > 0:
815
+ for i in range(0, len(symbols)):
816
+ symbol = symbols[i]
817
+ if topic == 'trades':
818
+ if symbol in self.trades:
819
+ del self.trades[symbol]
820
+ elif topic == 'orderbook':
821
+ if symbol in self.orderbooks:
822
+ del self.orderbooks[symbol]
823
+ elif topic == 'ticker':
824
+ if symbol in self.tickers:
825
+ del self.tickers[symbol]
826
+ else:
827
+ if topic == 'myTrades':
828
+ # don't reset self.myTrades directly here
829
+ # because in c# we need to use a different object
830
+ keys = list(self.myTrades.keys())
831
+ for i in range(0, len(keys)):
832
+ del self.myTrades[keys[i]]
833
+ elif topic == 'orders':
834
+ orderSymbols = list(self.orders.keys())
835
+ for i in range(0, len(orderSymbols)):
836
+ del self.orders[orderSymbols[i]]
837
+ elif topic == 'ticker':
838
+ tickerSymbols = list(self.tickers.keys())
839
+ for i in range(0, len(tickerSymbols)):
840
+ del self.tickers[tickerSymbols[i]]
734
841
 
735
842
  def handle_system_status(self, client: Client, message):
736
843
  #