ccxt 4.3.95__py2.py3-none-any.whl → 4.3.96__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/bybit.py CHANGED
@@ -609,6 +609,53 @@ class bybit(ccxt.async_support.bybit):
609
609
  filtered = self.filter_by_since_limit(stored, since, limit, 0, True)
610
610
  return self.create_ohlcv_object(symbol, timeframe, filtered)
611
611
 
612
+ async def un_watch_ohlcv_for_symbols(self, symbolsAndTimeframes: List[List[str]], params={}):
613
+ """
614
+ unWatches historical candlestick data containing the open, high, low, and close price, and the volume of a market
615
+ :see: https://bybit-exchange.github.io/docs/v5/websocket/public/kline
616
+ :see: https://bybit-exchange.github.io/docs/v5/websocket/public/etp-kline
617
+ :param str[][] symbolsAndTimeframes: array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
618
+ :param dict [params]: extra parameters specific to the exchange API endpoint
619
+ :returns dict: A list of candles ordered, open, high, low, close, volume
620
+ """
621
+ await self.load_markets()
622
+ symbols = self.get_list_from_object_values(symbolsAndTimeframes, 0)
623
+ marketSymbols = self.market_symbols(symbols, None, False, True, True)
624
+ firstSymbol = marketSymbols[0]
625
+ url = await self.get_url_by_market_type(firstSymbol, False, 'watchOHLCVForSymbols', params)
626
+ rawHashes = []
627
+ subMessageHashes = []
628
+ messageHashes = []
629
+ for i in range(0, len(symbolsAndTimeframes)):
630
+ data = symbolsAndTimeframes[i]
631
+ symbolString = self.safe_string(data, 0)
632
+ market = self.market(symbolString)
633
+ symbolString = market['symbol']
634
+ unfiedTimeframe = self.safe_string(data, 1)
635
+ timeframeId = self.safe_string(self.timeframes, unfiedTimeframe, unfiedTimeframe)
636
+ rawHashes.append('kline.' + timeframeId + '.' + market['id'])
637
+ subMessageHashes.append('ohlcv::' + symbolString + '::' + unfiedTimeframe)
638
+ messageHashes.append('unsubscribe::ohlcv::' + symbolString + '::' + unfiedTimeframe)
639
+ subExtension = {
640
+ 'symbolsAndTimeframes': symbolsAndTimeframes,
641
+ }
642
+ return await self.un_watch_topics(url, 'ohlcv', symbols, messageHashes, subMessageHashes, rawHashes, params, subExtension)
643
+
644
+ async def un_watch_ohlcv(self, symbol: str, timeframe='1m', params={}) -> Any:
645
+ """
646
+ unWatches historical candlestick data containing the open, high, low, and close price, and the volume of a market
647
+ :see: https://bybit-exchange.github.io/docs/v5/websocket/public/kline
648
+ :see: https://bybit-exchange.github.io/docs/v5/websocket/public/etp-kline
649
+ :param str symbol: unified symbol of the market to fetch OHLCV data for
650
+ :param str timeframe: the length of time each candle represents
651
+ :param int [since]: timestamp in ms of the earliest candle to fetch
652
+ :param int [limit]: the maximum amount of candles to fetch
653
+ :param dict [params]: extra parameters specific to the exchange API endpoint
654
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
655
+ """
656
+ params['callerMethodName'] = 'watchOHLCV'
657
+ return await self.un_watch_ohlcv_for_symbols([[symbol, timeframe]], params)
658
+
612
659
  def handle_ohlcv(self, client: Client, message):
613
660
  #
614
661
  # {
@@ -1997,7 +2044,7 @@ class bybit(ccxt.async_support.bybit):
1997
2044
  message = self.extend(request, params)
1998
2045
  return await self.watch_multiple(url, messageHashes, message, messageHashes)
1999
2046
 
2000
- async def un_watch_topics(self, url: str, topic: str, symbols: List[str], messageHashes: List[str], subMessageHashes: List[str], topics, params={}):
2047
+ async def un_watch_topics(self, url: str, topic: str, symbols: List[str], messageHashes: List[str], subMessageHashes: List[str], topics, params={}, subExtension={}):
2001
2048
  reqId = self.request_id()
2002
2049
  request: dict = {
2003
2050
  'op': 'unsubscribe',
@@ -2012,7 +2059,7 @@ class bybit(ccxt.async_support.bybit):
2012
2059
  'symbols': symbols,
2013
2060
  }
2014
2061
  message = self.extend(request, params)
2015
- return await self.watch_multiple(url, messageHashes, message, messageHashes, subscription)
2062
+ return await self.watch_multiple(url, messageHashes, message, messageHashes, self.extend(subscription, subExtension))
2016
2063
 
2017
2064
  async def authenticate(self, url, params={}):
2018
2065
  self.check_required_credentials()
@@ -2270,14 +2317,21 @@ class bybit(ccxt.async_support.bybit):
2270
2317
  error = UnsubscribeError(self.id + ' ' + messageHash)
2271
2318
  client.reject(error, subHash)
2272
2319
  client.resolve(True, unsubHash)
2273
- self.clean_cache(subscription)
2320
+ self.clean_cache(subscription)
2274
2321
  return message
2275
2322
 
2276
2323
  def clean_cache(self, subscription: dict):
2277
2324
  topic = self.safe_string(subscription, 'topic')
2278
2325
  symbols = self.safe_list(subscription, 'symbols', [])
2279
2326
  symbolsLength = len(symbols)
2280
- if symbolsLength > 0:
2327
+ if topic == 'ohlcv':
2328
+ symbolsAndTimeFrames = self.safe_list(subscription, 'symbolsAndTimeframes', [])
2329
+ for i in range(0, len(symbolsAndTimeFrames)):
2330
+ symbolAndTimeFrame = symbolsAndTimeFrames[i]
2331
+ symbol = self.safe_string(symbolAndTimeFrame, 0)
2332
+ timeframe = self.safe_string(symbolAndTimeFrame, 1)
2333
+ del self.ohlcvs[symbol][timeframe]
2334
+ elif symbolsLength > 0:
2281
2335
  for i in range(0, len(symbols)):
2282
2336
  symbol = symbols[i]
2283
2337
  if topic == 'trade':
ccxt/pro/cryptocom.py CHANGED
@@ -9,10 +9,12 @@ import hashlib
9
9
  from ccxt.base.types import Balances, Int, Num, Order, OrderBook, OrderSide, OrderType, Position, Str, Strings, Ticker, 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 NetworkError
15
16
  from ccxt.base.errors import ChecksumError
17
+ from ccxt.base.errors import UnsubscribeError
16
18
 
17
19
 
18
20
  class cryptocom(ccxt.async_support.cryptocom):
@@ -86,6 +88,18 @@ class cryptocom(ccxt.async_support.cryptocom):
86
88
  """
87
89
  return await self.watch_order_book_for_symbols([symbol], limit, params)
88
90
 
91
+ async def un_watch_order_book(self, symbol: str, params={}) -> Any:
92
+ """
93
+ unWatches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
94
+ :see: https://exchange-docs.crypto.com/exchange/v1/rest-ws/index.html#book-instrument_name
95
+ :param str symbol: unified symbol of the market to fetch the order book for
96
+ :param dict [params]: extra parameters specific to the exchange API endpoint
97
+ :param str [params.bookSubscriptionType]: The subscription type. Allowed values: SNAPSHOT full snapshot. This is the default if not specified. SNAPSHOT_AND_UPDATE delta updates
98
+ :param int [params.bookUpdateFrequency]: Book update interval in ms. Allowed values: 100 for snapshot subscription 10 for delta subscription
99
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
100
+ """
101
+ return await self.un_watch_order_book_for_symbols([symbol], params)
102
+
89
103
  async def watch_order_book_for_symbols(self, symbols: List[str], limit: Int = None, params={}) -> OrderBook:
90
104
  """
91
105
  watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
@@ -127,6 +141,47 @@ class cryptocom(ccxt.async_support.cryptocom):
127
141
  orderbook = await self.watch_public_multiple(messageHashes, topics, params)
128
142
  return orderbook.limit()
129
143
 
144
+ async def un_watch_order_book_for_symbols(self, symbols: List[str], params={}) -> OrderBook:
145
+ """
146
+ unWatches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
147
+ :see: https://exchange-docs.crypto.com/exchange/v1/rest-ws/index.html#book-instrument_name
148
+ :param str[] symbols: unified array of symbols
149
+ :param dict [params]: extra parameters specific to the exchange API endpoint
150
+ :param int [params.limit]: orderbook limit, default is 50
151
+ :param str [params.bookSubscriptionType]: The subscription type. Allowed values: SNAPSHOT full snapshot. This is the default if not specified. SNAPSHOT_AND_UPDATE delta updates
152
+ :param int [params.bookUpdateFrequency]: Book update interval in ms. Allowed values: 100 for snapshot subscription 10 for delta subscription
153
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
154
+ """
155
+ await self.load_markets()
156
+ symbols = self.market_symbols(symbols)
157
+ topics = []
158
+ subMessageHashes = []
159
+ messageHashes = []
160
+ limit = self.safe_integer(params, 'limit', 50)
161
+ topicParams = self.safe_value(params, 'params')
162
+ if topicParams is None:
163
+ params['params'] = {}
164
+ bookSubscriptionType = None
165
+ bookSubscriptionType2 = None
166
+ bookSubscriptionType, params = self.handle_option_and_params(params, 'watchOrderBook', 'bookSubscriptionType', 'SNAPSHOT_AND_UPDATE')
167
+ bookSubscriptionType2, params = self.handle_option_and_params(params, 'watchOrderBookForSymbols', 'bookSubscriptionType', bookSubscriptionType)
168
+ params['params']['bookSubscriptionType'] = bookSubscriptionType2
169
+ bookUpdateFrequency = None
170
+ bookUpdateFrequency2 = None
171
+ bookUpdateFrequency, params = self.handle_option_and_params(params, 'watchOrderBook', 'bookUpdateFrequency')
172
+ bookUpdateFrequency2, params = self.handle_option_and_params(params, 'watchOrderBookForSymbols', 'bookUpdateFrequency', bookUpdateFrequency)
173
+ if bookUpdateFrequency2 is not None:
174
+ params['params']['bookSubscriptionType'] = bookUpdateFrequency2
175
+ for i in range(0, len(symbols)):
176
+ symbol = symbols[i]
177
+ market = self.market(symbol)
178
+ currentTopic = 'book' + '.' + market['id'] + '.' + str(limit)
179
+ messageHash = 'orderbook:' + market['symbol']
180
+ subMessageHashes.append(messageHash)
181
+ messageHashes.append('unsubscribe:' + messageHash)
182
+ topics.append(currentTopic)
183
+ return await self.un_watch_public_multiple('orderbook', symbols, messageHashes, subMessageHashes, topics, params)
184
+
130
185
  def handle_delta(self, bookside, delta):
131
186
  price = self.safe_float(delta, 0)
132
187
  amount = self.safe_float(delta, 1)
@@ -239,6 +294,18 @@ class cryptocom(ccxt.async_support.cryptocom):
239
294
  """
240
295
  return await self.watch_trades_for_symbols([symbol], since, limit, params)
241
296
 
297
+ async def un_watch_trades(self, symbol: str, params={}) -> List[Trade]:
298
+ """
299
+ get the list of most recent trades for a particular symbol
300
+ :see: https://exchange-docs.crypto.com/exchange/v1/rest-ws/index.html#trade-instrument_name
301
+ :param str symbol: unified symbol of the market to fetch trades for
302
+ :param int [since]: timestamp in ms of the earliest trade to fetch
303
+ :param int [limit]: the maximum amount of trades to fetch
304
+ :param dict [params]: extra parameters specific to the exchange API endpoint
305
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
306
+ """
307
+ return await self.un_watch_trades_for_symbols([symbol], params)
308
+
242
309
  async def watch_trades_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}) -> List[Trade]:
243
310
  """
244
311
  get the list of most recent trades for a particular symbol
@@ -264,6 +331,26 @@ class cryptocom(ccxt.async_support.cryptocom):
264
331
  limit = trades.getLimit(tradeSymbol, limit)
265
332
  return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
266
333
 
334
+ async def un_watch_trades_for_symbols(self, symbols: List[str], params={}) -> Any:
335
+ """
336
+ get the list of most recent trades for a particular symbol
337
+ :see: https://exchange-docs.crypto.com/exchange/v1/rest-ws/index.html#trade-instrument_name
338
+ :param str symbol: unified symbol of the market to fetch trades for
339
+ :param dict [params]: extra parameters specific to the exchange API endpoint
340
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
341
+ """
342
+ await self.load_markets()
343
+ symbols = self.market_symbols(symbols)
344
+ topics = []
345
+ messageHashes = []
346
+ for i in range(0, len(symbols)):
347
+ symbol = symbols[i]
348
+ market = self.market(symbol)
349
+ currentTopic = 'trade' + '.' + market['id']
350
+ messageHashes.append('unsubscribe:trades:' + market['symbol'])
351
+ topics.append(currentTopic)
352
+ return await self.un_watch_public_multiple('trade', symbols, messageHashes, topics, topics, params)
353
+
267
354
  def handle_trades(self, client: Client, message):
268
355
  #
269
356
  # {
@@ -343,6 +430,20 @@ class cryptocom(ccxt.async_support.cryptocom):
343
430
  messageHash = 'ticker' + '.' + market['id']
344
431
  return await self.watch_public(messageHash, params)
345
432
 
433
+ async def un_watch_ticker(self, symbol: str, params={}) -> Any:
434
+ """
435
+ unWatches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
436
+ :see: https://exchange-docs.crypto.com/exchange/v1/rest-ws/index.html#ticker-instrument_name
437
+ :param str symbol: unified symbol of the market to fetch the ticker for
438
+ :param dict [params]: extra parameters specific to the exchange API endpoint
439
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
440
+ """
441
+ await self.load_markets()
442
+ market = self.market(symbol)
443
+ subMessageHash = 'ticker' + '.' + market['id']
444
+ messageHash = 'unsubscribe:ticker:' + market['symbol']
445
+ return await self.un_watch_public_multiple('ticker', [market['symbol']], [messageHash], [subMessageHash], [subMessageHash], params)
446
+
346
447
  def handle_ticker(self, client: Client, message):
347
448
  #
348
449
  # {
@@ -398,6 +499,26 @@ class cryptocom(ccxt.async_support.cryptocom):
398
499
  limit = ohlcv.getLimit(symbol, limit)
399
500
  return self.filter_by_since_limit(ohlcv, since, limit, 0, True)
400
501
 
502
+ async def un_watch_ohlcv(self, symbol: str, timeframe='1m', params={}) -> Any:
503
+ """
504
+ unWatches historical candlestick data containing the open, high, low, and close price, and the volume of a market
505
+ :see: https://exchange-docs.crypto.com/exchange/v1/rest-ws/index.html#candlestick-time_frame-instrument_name
506
+ :param str symbol: unified symbol of the market to fetch OHLCV data for
507
+ :param str timeframe: the length of time each candle represents
508
+ :param dict [params]: extra parameters specific to the exchange API endpoint
509
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
510
+ """
511
+ await self.load_markets()
512
+ market = self.market(symbol)
513
+ symbol = market['symbol']
514
+ interval = self.safe_string(self.timeframes, timeframe, timeframe)
515
+ subMessageHash = 'candlestick' + '.' + interval + '.' + market['id']
516
+ messageHash = 'unsubscribe:ohlcv:' + market['symbol'] + ':' + timeframe
517
+ subExtend = {
518
+ 'symbolsAndTimeframes': [[market['symbol'], timeframe]],
519
+ }
520
+ return await self.un_watch_public_multiple('ohlcv', [market['symbol']], [messageHash], [subMessageHash], [subMessageHash], params, subExtend)
521
+
401
522
  def handle_ohlcv(self, client: Client, message):
402
523
  #
403
524
  # {
@@ -795,6 +916,27 @@ class cryptocom(ccxt.async_support.cryptocom):
795
916
  message = self.deep_extend(request, params)
796
917
  return await self.watch_multiple(url, messageHashes, message, messageHashes)
797
918
 
919
+ async def un_watch_public_multiple(self, topic: str, symbols: List[str], messageHashes: List[str], subMessageHashes: List[str], topics: List[str], params={}, subExtend={}):
920
+ url = self.urls['api']['ws']['public']
921
+ id = self.nonce()
922
+ request: dict = {
923
+ 'method': 'unsubscribe',
924
+ 'params': {
925
+ 'channels': topics,
926
+ },
927
+ 'nonce': id,
928
+ 'id': str(id),
929
+ }
930
+ subscription = {
931
+ 'id': str(id),
932
+ 'topic': topic,
933
+ 'symbols': symbols,
934
+ 'subMessageHashes': subMessageHashes,
935
+ 'messageHashes': messageHashes,
936
+ }
937
+ message = self.deep_extend(request, params)
938
+ return await self.watch_multiple(url, messageHashes, message, messageHashes, self.extend(subscription, subExtend))
939
+
798
940
  async def watch_private_request(self, nonce, params={}):
799
941
  await self.authenticate()
800
942
  url = self.urls['api']['ws']['private']
@@ -904,6 +1046,9 @@ class cryptocom(ccxt.async_support.cryptocom):
904
1046
  # "channel":"ticker",
905
1047
  # "data":[{}]
906
1048
  #
1049
+ # handle unsubscribe
1050
+ # {"id":1725448572836,"method":"unsubscribe","code":0}
1051
+ #
907
1052
  if self.handle_error_message(client, message):
908
1053
  return
909
1054
  method = self.safe_string(message, 'method')
@@ -916,6 +1061,7 @@ class cryptocom(ccxt.async_support.cryptocom):
916
1061
  'private/cancel-all-orders': self.handle_cancel_all_orders,
917
1062
  'private/close-position': self.handle_order,
918
1063
  'subscribe': self.handle_subscribe,
1064
+ 'unsubscribe': self.handle_unsubscribe,
919
1065
  }
920
1066
  callMethod = self.safe_value(methods, method)
921
1067
  if callMethod is not None:
@@ -953,3 +1099,52 @@ class cryptocom(ccxt.async_support.cryptocom):
953
1099
  #
954
1100
  future = self.safe_value(client.futures, 'authenticated')
955
1101
  future.resolve(True)
1102
+
1103
+ def handle_unsubscribe(self, client: Client, message):
1104
+ id = self.safe_string(message, 'id')
1105
+ keys = list(client.subscriptions.keys())
1106
+ for i in range(0, len(keys)):
1107
+ messageHash = keys[i]
1108
+ if not (messageHash in client.subscriptions):
1109
+ continue
1110
+ # the previous iteration can have deleted the messageHash from the subscriptions
1111
+ if messageHash.startswith('unsubscribe'):
1112
+ subscription = client.subscriptions[messageHash]
1113
+ subId = self.safe_string(subscription, 'id')
1114
+ if id != subId:
1115
+ continue
1116
+ messageHashes = self.safe_list(subscription, 'messageHashes', [])
1117
+ subMessageHashes = self.safe_list(subscription, 'subMessageHashes', [])
1118
+ for j in range(0, len(messageHashes)):
1119
+ unsubHash = messageHashes[j]
1120
+ subHash = subMessageHashes[j]
1121
+ if unsubHash in client.subscriptions:
1122
+ del client.subscriptions[unsubHash]
1123
+ if subHash in client.subscriptions:
1124
+ del client.subscriptions[subHash]
1125
+ error = UnsubscribeError(self.id + ' ' + subHash)
1126
+ client.reject(error, subHash)
1127
+ client.resolve(True, unsubHash)
1128
+ self.clean_cache(subscription)
1129
+
1130
+ def clean_cache(self, subscription: dict):
1131
+ topic = self.safe_string(subscription, 'topic')
1132
+ symbols = self.safe_list(subscription, 'symbols', [])
1133
+ symbolsLength = len(symbols)
1134
+ if topic == 'ohlcv':
1135
+ symbolsAndTimeFrames = self.safe_list(subscription, 'symbolsAndTimeframes', [])
1136
+ for i in range(0, len(symbolsAndTimeFrames)):
1137
+ symbolAndTimeFrame = symbolsAndTimeFrames[i]
1138
+ symbol = self.safe_string(symbolAndTimeFrame, 0)
1139
+ timeframe = self.safe_string(symbolAndTimeFrame, 1)
1140
+ if timeframe in self.ohlcvs[symbol]:
1141
+ del self.ohlcvs[symbol][timeframe]
1142
+ elif symbolsLength > 0:
1143
+ for i in range(0, len(symbols)):
1144
+ symbol = symbols[i]
1145
+ if topic == 'trade':
1146
+ del self.trades[symbol]
1147
+ elif topic == 'orderbook':
1148
+ del self.orderbooks[symbol]
1149
+ elif topic == 'ticker':
1150
+ del self.tickers[symbol]