ccxt 4.2.58__py2.py3-none-any.whl → 4.2.60__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.
Potentially problematic release.
This version of ccxt might be problematic. Click here for more details.
- ccxt/__init__.py +1 -1
- ccxt/abstract/blofin.py +1 -0
- ccxt/abstract/kraken.py +37 -37
- ccxt/abstract/wazirx.py +6 -1
- ccxt/ascendex.py +10 -12
- ccxt/async_support/__init__.py +1 -1
- ccxt/async_support/ascendex.py +10 -12
- ccxt/async_support/base/exchange.py +1 -1
- ccxt/async_support/binance.py +2 -2
- ccxt/async_support/bingx.py +40 -4
- ccxt/async_support/bitfinex2.py +20 -3
- ccxt/async_support/bitget.py +8 -3
- ccxt/async_support/bitmart.py +40 -23
- ccxt/async_support/bitmex.py +1 -1
- ccxt/async_support/blofin.py +53 -3
- ccxt/async_support/coinbase.py +21 -12
- ccxt/async_support/hitbtc.py +1 -1
- ccxt/async_support/htx.py +3 -1
- ccxt/async_support/kraken.py +42 -39
- ccxt/async_support/kucoinfutures.py +1 -0
- ccxt/async_support/lbank.py +1 -1
- ccxt/async_support/mexc.py +1 -1
- ccxt/async_support/okx.py +1 -1
- ccxt/async_support/phemex.py +1 -1
- ccxt/async_support/wazirx.py +6 -1
- ccxt/async_support/woo.py +148 -76
- ccxt/base/exchange.py +3 -1
- ccxt/binance.py +2 -2
- ccxt/bingx.py +40 -4
- ccxt/bitfinex2.py +20 -3
- ccxt/bitget.py +8 -3
- ccxt/bitmart.py +40 -23
- ccxt/bitmex.py +1 -1
- ccxt/blofin.py +53 -3
- ccxt/coinbase.py +21 -12
- ccxt/hitbtc.py +1 -1
- ccxt/htx.py +3 -1
- ccxt/kraken.py +42 -39
- ccxt/kucoinfutures.py +1 -0
- ccxt/lbank.py +1 -1
- ccxt/mexc.py +1 -1
- ccxt/okx.py +1 -1
- ccxt/phemex.py +1 -1
- ccxt/pro/__init__.py +1 -1
- ccxt/pro/binance.py +12 -3
- ccxt/pro/bitfinex2.py +1 -1
- ccxt/pro/bitget.py +1 -1
- ccxt/pro/bitmart.py +44 -78
- ccxt/pro/bitvavo.py +1 -1
- ccxt/pro/bybit.py +1 -1
- ccxt/pro/coinex.py +1 -1
- ccxt/pro/cryptocom.py +1 -1
- ccxt/pro/deribit.py +188 -84
- ccxt/pro/gate.py +1 -1
- ccxt/pro/independentreserve.py +1 -1
- ccxt/pro/kraken.py +1 -1
- ccxt/pro/kucoinfutures.py +1 -1
- ccxt/pro/mexc.py +5 -4
- ccxt/pro/okx.py +1 -1
- ccxt/pro/woo.py +1 -1
- ccxt/test/test_async.py +4 -4
- ccxt/test/test_sync.py +4 -4
- ccxt/wazirx.py +6 -1
- ccxt/woo.py +148 -76
- {ccxt-4.2.58.dist-info → ccxt-4.2.60.dist-info}/METADATA +4 -4
- {ccxt-4.2.58.dist-info → ccxt-4.2.60.dist-info}/RECORD +68 -68
- {ccxt-4.2.58.dist-info → ccxt-4.2.60.dist-info}/WHEEL +0 -0
- {ccxt-4.2.58.dist-info → ccxt-4.2.60.dist-info}/top_level.txt +0 -0
ccxt/pro/bitmart.py
CHANGED
@@ -114,7 +114,8 @@ class bitmart(ccxt.async_support.bitmart):
|
|
114
114
|
}
|
115
115
|
return await self.watch(url, messageHash, self.deep_extend(request, params), messageHash)
|
116
116
|
|
117
|
-
async def subscribe_multiple(self, channel: str, type: str, symbols:
|
117
|
+
async def subscribe_multiple(self, channel: str, type: str, symbols: Strings = None, params={}):
|
118
|
+
symbols = self.market_symbols(symbols, type, False, True)
|
118
119
|
url = self.implode_hostname(self.urls['api']['ws'][type]['public'])
|
119
120
|
channelType = 'spot' if (type == 'spot') else 'futures'
|
120
121
|
actionType = 'op' if (type == 'spot') else 'action'
|
@@ -125,6 +126,9 @@ class bitmart(ccxt.async_support.bitmart):
|
|
125
126
|
message = channelType + '/' + channel + ':' + market['id']
|
126
127
|
rawSubscriptions.append(message)
|
127
128
|
messageHashes.append(channel + ':' + market['symbol'])
|
129
|
+
# exclusion, futures "tickers" need one generic request for all symbols
|
130
|
+
if (type != 'spot') and (channel == 'ticker'):
|
131
|
+
rawSubscriptions = [channelType + '/' + channel]
|
128
132
|
request = {
|
129
133
|
'args': rawSubscriptions,
|
130
134
|
}
|
@@ -305,12 +309,8 @@ class bitmart(ccxt.async_support.bitmart):
|
|
305
309
|
"""
|
306
310
|
await self.load_markets()
|
307
311
|
symbol = self.symbol(symbol)
|
308
|
-
|
309
|
-
|
310
|
-
type, params = self.handle_market_type_and_params('watchTicker', market, params)
|
311
|
-
if type == 'swap':
|
312
|
-
raise NotSupported(self.id + ' watchTicker() does not support ' + type + ' markets. Use watchTickers() instead')
|
313
|
-
return await self.subscribe('ticker', symbol, type, params)
|
312
|
+
tickers = await self.watch_tickers([symbol], params)
|
313
|
+
return tickers[symbol]
|
314
314
|
|
315
315
|
async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
|
316
316
|
"""
|
@@ -322,35 +322,12 @@ class bitmart(ccxt.async_support.bitmart):
|
|
322
322
|
"""
|
323
323
|
await self.load_markets()
|
324
324
|
market = self.get_market_from_symbols(symbols)
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
symbols = self.market_symbols(symbols)
|
329
|
-
messageHash = 'tickers::' + type
|
330
|
-
if symbols is not None:
|
331
|
-
messageHash += '::' + ','.join(symbols)
|
332
|
-
request = None
|
333
|
-
tickers = None
|
334
|
-
isSpot = (type == 'spot')
|
335
|
-
if isSpot:
|
336
|
-
if symbols is None:
|
337
|
-
raise ArgumentsRequired(self.id + ' watchTickers() for ' + type + ' market type requires symbols argument to be provided')
|
338
|
-
marketIds = self.market_ids(symbols)
|
339
|
-
finalArray = []
|
340
|
-
for i in range(0, len(marketIds)):
|
341
|
-
finalArray.append('spot/ticker:' + marketIds[i])
|
342
|
-
request = {
|
343
|
-
'op': 'subscribe',
|
344
|
-
'args': finalArray,
|
345
|
-
}
|
346
|
-
tickers = await self.watch(url, messageHash, self.deep_extend(request, params), messageHash)
|
347
|
-
else:
|
348
|
-
request = {
|
349
|
-
'action': 'subscribe',
|
350
|
-
'args': ['futures/ticker'],
|
351
|
-
}
|
352
|
-
tickers = await self.watch(url, messageHash, self.deep_extend(request, params), messageHash)
|
325
|
+
marketType = None
|
326
|
+
marketType, params = self.handle_market_type_and_params('watchTickers', market, params)
|
327
|
+
ticker = await self.subscribe_multiple('ticker', marketType, symbols, params)
|
353
328
|
if self.newUpdates:
|
329
|
+
tickers = {}
|
330
|
+
tickers[ticker['symbol']] = ticker
|
354
331
|
return tickers
|
355
332
|
return self.filter_by_array(self.tickers, 'symbol', symbols)
|
356
333
|
|
@@ -799,19 +776,29 @@ class bitmart(ccxt.async_support.bitmart):
|
|
799
776
|
data = self.safe_value(message, 'data')
|
800
777
|
if data is None:
|
801
778
|
return
|
802
|
-
stored = None
|
803
779
|
symbol = None
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
780
|
+
length = len(data)
|
781
|
+
isSwap = ('group' in message)
|
782
|
+
if isSwap:
|
783
|
+
# in swap, chronologically decreasing: 1709536849322, 1709536848954,
|
784
|
+
maxLen = max(length - 1, 0)
|
785
|
+
for i in range(maxLen, 0):
|
786
|
+
symbol = self.handle_trade_loop(data[i])
|
787
|
+
else:
|
788
|
+
# in spot, chronologically increasing: 1709536771200, 1709536771226,
|
789
|
+
for i in range(0, length):
|
790
|
+
symbol = self.handle_trade_loop(data[i])
|
791
|
+
client.resolve(self.trades[symbol], 'trade:' + symbol)
|
792
|
+
|
793
|
+
def handle_trade_loop(self, entry):
|
794
|
+
trade = self.parse_ws_trade(entry)
|
795
|
+
symbol = trade['symbol']
|
796
|
+
tradesLimit = self.safe_integer(self.options, 'tradesLimit', 1000)
|
797
|
+
if self.safe_value(self.trades, symbol) is None:
|
798
|
+
self.trades[symbol] = ArrayCache(tradesLimit)
|
799
|
+
stored = self.trades[symbol]
|
800
|
+
stored.append(trade)
|
801
|
+
return symbol
|
815
802
|
|
816
803
|
def parse_ws_trade(self, trade, market: Market = None):
|
817
804
|
# spot
|
@@ -890,40 +877,19 @@ class bitmart(ccxt.async_support.bitmart):
|
|
890
877
|
#
|
891
878
|
table = self.safe_string(message, 'table')
|
892
879
|
isSpot = (table is not None)
|
893
|
-
|
894
|
-
if data is None:
|
895
|
-
return
|
880
|
+
rawTickers = []
|
896
881
|
if isSpot:
|
897
|
-
|
898
|
-
ticker = self.parse_ticker(data[i])
|
899
|
-
symbol = ticker['symbol']
|
900
|
-
marketId = self.safe_string(ticker['info'], 'symbol')
|
901
|
-
messageHash = table + ':' + marketId
|
902
|
-
self.tickers[symbol] = ticker
|
903
|
-
client.resolve(ticker, messageHash)
|
904
|
-
self.resolve_message_hashes_for_symbol(client, symbol, ticker, 'tickers::')
|
882
|
+
rawTickers = self.safe_list(message, 'data', [])
|
905
883
|
else:
|
906
|
-
|
907
|
-
|
908
|
-
|
884
|
+
rawTickers = [self.safe_value(message, 'data', {})]
|
885
|
+
if not len(rawTickers):
|
886
|
+
return
|
887
|
+
for i in range(0, len(rawTickers)):
|
888
|
+
ticker = self.parse_ticker(rawTickers[i]) if isSpot else self.parse_ws_swap_ticker(rawTickers[i])
|
889
|
+
symbol = ticker['symbol']
|
909
890
|
self.tickers[symbol] = ticker
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
def resolve_message_hashes_for_symbol(self, client, symbol, result, prexif):
|
914
|
-
prefixSeparator = '::'
|
915
|
-
symbolsSeparator = ','
|
916
|
-
messageHashes = self.find_message_hashes(client, prexif)
|
917
|
-
for i in range(0, len(messageHashes)):
|
918
|
-
messageHash = messageHashes[i]
|
919
|
-
parts = messageHash.split(prefixSeparator)
|
920
|
-
length = len(parts)
|
921
|
-
symbolsString = parts[length - 1]
|
922
|
-
symbols = symbolsString.split(symbolsSeparator)
|
923
|
-
if self.in_array(symbol, symbols):
|
924
|
-
response = {}
|
925
|
-
response[symbol] = result
|
926
|
-
client.resolve(response, messageHash)
|
891
|
+
messageHash = 'ticker:' + symbol
|
892
|
+
client.resolve(ticker, messageHash)
|
927
893
|
|
928
894
|
def parse_ws_swap_ticker(self, ticker, market: Market = None):
|
929
895
|
#
|
ccxt/pro/bitvavo.py
CHANGED
@@ -1020,7 +1020,7 @@ class bitvavo(ccxt.async_support.bitvavo):
|
|
1020
1020
|
return messageHash
|
1021
1021
|
|
1022
1022
|
def check_message_hash_does_not_exist(self, messageHash):
|
1023
|
-
supressMultipleWsRequestsError = self.
|
1023
|
+
supressMultipleWsRequestsError = self.safe_bool(self.options, 'supressMultipleWsRequestsError', False)
|
1024
1024
|
if not supressMultipleWsRequestsError:
|
1025
1025
|
client = self.safe_value(self.clients, self.urls['api']['ws'])
|
1026
1026
|
if client is not None:
|
ccxt/pro/bybit.py
CHANGED
@@ -885,7 +885,7 @@ class bybit(ccxt.async_support.bybit):
|
|
885
885
|
self.set_positions_cache(client, symbols)
|
886
886
|
cache = self.positions
|
887
887
|
fetchPositionsSnapshot = self.handle_option('watchPositions', 'fetchPositionsSnapshot', True)
|
888
|
-
awaitPositionsSnapshot = self.
|
888
|
+
awaitPositionsSnapshot = self.safe_bool('watchPositions', 'awaitPositionsSnapshot', True)
|
889
889
|
if fetchPositionsSnapshot and awaitPositionsSnapshot and cache is None:
|
890
890
|
snapshot = await client.future('fetchPositionsSnapshot')
|
891
891
|
return self.filter_by_symbols_since_limit(snapshot, symbols, since, limit, True)
|
ccxt/pro/coinex.py
CHANGED
@@ -529,7 +529,7 @@ class coinex(ccxt.async_support.coinex):
|
|
529
529
|
raise NotSupported(self.id + ' watchOHLCV() is only supported for swap markets. Try using fetchOHLCV() instead')
|
530
530
|
url = self.urls['api']['ws'][type]
|
531
531
|
messageHash = 'ohlcv'
|
532
|
-
watchOHLCVWarning = self.
|
532
|
+
watchOHLCVWarning = self.safe_bool(self.options, 'watchOHLCVWarning', True)
|
533
533
|
client = self.safe_value(self.clients, url, {})
|
534
534
|
clientSub = self.safe_value(client, 'subscriptions', {})
|
535
535
|
existingSubscription = self.safe_value(clientSub, messageHash)
|
ccxt/pro/cryptocom.py
CHANGED
@@ -515,7 +515,7 @@ class cryptocom(ccxt.async_support.cryptocom):
|
|
515
515
|
client = self.client(url)
|
516
516
|
self.set_positions_cache(client, symbols)
|
517
517
|
fetchPositionsSnapshot = self.handle_option('watchPositions', 'fetchPositionsSnapshot', True)
|
518
|
-
awaitPositionsSnapshot = self.
|
518
|
+
awaitPositionsSnapshot = self.safe_bool('watchPositions', 'awaitPositionsSnapshot', True)
|
519
519
|
if fetchPositionsSnapshot and awaitPositionsSnapshot and self.positions is None:
|
520
520
|
snapshot = await client.future('fetchPositionsSnapshot')
|
521
521
|
return self.filter_by_symbols_since_limit(snapshot, symbols, since, limit, True)
|
ccxt/pro/deribit.py
CHANGED
@@ -10,6 +10,7 @@ from ccxt.base.types import Balances, Int, Order, OrderBook, Str, Ticker, Trade
|
|
10
10
|
from ccxt.async_support.base.ws.client import Client
|
11
11
|
from typing import List
|
12
12
|
from ccxt.base.errors import ExchangeError
|
13
|
+
from ccxt.base.errors import ArgumentsRequired
|
13
14
|
from ccxt.base.errors import NotSupported
|
14
15
|
|
15
16
|
|
@@ -23,10 +24,13 @@ class deribit(ccxt.async_support.deribit):
|
|
23
24
|
'watchTicker': True,
|
24
25
|
'watchTickers': False,
|
25
26
|
'watchTrades': True,
|
27
|
+
'watchTradesForSymbols': True,
|
26
28
|
'watchMyTrades': True,
|
27
29
|
'watchOrders': True,
|
28
30
|
'watchOrderBook': True,
|
31
|
+
'watchOrderBookForSymbols': True,
|
29
32
|
'watchOHLCV': True,
|
33
|
+
'watchOHLCVForSymbols': True,
|
30
34
|
},
|
31
35
|
'urls': {
|
32
36
|
'test': {
|
@@ -37,18 +41,31 @@ class deribit(ccxt.async_support.deribit):
|
|
37
41
|
},
|
38
42
|
},
|
39
43
|
'options': {
|
40
|
-
'
|
41
|
-
'
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
44
|
+
'ws': {
|
45
|
+
'timeframes': {
|
46
|
+
'1m': '1',
|
47
|
+
'3m': '3',
|
48
|
+
'5m': '5',
|
49
|
+
'15m': '15',
|
50
|
+
'30m': '30',
|
51
|
+
'1h': '60',
|
52
|
+
'2h': '120',
|
53
|
+
'4h': '180',
|
54
|
+
'6h': '360',
|
55
|
+
'12h': '720',
|
56
|
+
'1d': '1D',
|
57
|
+
},
|
58
|
+
# watchTrades replacement
|
59
|
+
'watchTradesForSymbols': {
|
60
|
+
'interval': '100ms', # 100ms, agg2, raw
|
61
|
+
},
|
62
|
+
# watchOrderBook replacement
|
63
|
+
'watchOrderBookForSymbols': {
|
64
|
+
'interval': '100ms', # 100ms, agg2, raw
|
65
|
+
'useDepthEndpoint': False, # if True, it will use the {books.group.depth.interval} endpoint instead of the {books.interval} endpoint
|
66
|
+
'depth': '20', # 1, 10, 20
|
67
|
+
'group': 'none', # none, 1, 2, 5, 10, 25, 100, 250
|
68
|
+
},
|
52
69
|
},
|
53
70
|
'currencies': ['BTC', 'ETH', 'SOL', 'USDC'],
|
54
71
|
},
|
@@ -222,26 +239,28 @@ class deribit(ccxt.async_support.deribit):
|
|
222
239
|
:param str [params.interval]: specify aggregation and frequency of notifications. Possible values: 100ms, raw
|
223
240
|
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
|
224
241
|
"""
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
242
|
+
params['callerMethodName'] = 'watchTrades'
|
243
|
+
return await self.watch_trades_for_symbols([symbol], since, limit, params)
|
244
|
+
|
245
|
+
async def watch_trades_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
246
|
+
"""
|
247
|
+
get the list of most recent trades for a list of symbols
|
248
|
+
:see: https://docs.deribit.com/#trades-instrument_name-interval
|
249
|
+
:param str[] symbols: unified symbol of the market to fetch trades for
|
250
|
+
:param int [since]: timestamp in ms of the earliest trade to fetch
|
251
|
+
:param int [limit]: the maximum amount of trades to fetch
|
252
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
253
|
+
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
|
254
|
+
"""
|
255
|
+
interval = None
|
256
|
+
interval, params = self.handle_option_and_params(params, 'watchTradesForSymbols', 'interval', '100ms')
|
231
257
|
if interval == 'raw':
|
232
258
|
await self.authenticate()
|
233
|
-
|
234
|
-
'jsonrpc': '2.0',
|
235
|
-
'method': 'public/subscribe',
|
236
|
-
'params': {
|
237
|
-
'channels': [channel],
|
238
|
-
},
|
239
|
-
'id': self.request_id(),
|
240
|
-
}
|
241
|
-
request = self.deep_extend(message, params)
|
242
|
-
trades = await self.watch(url, channel, request, channel, request)
|
259
|
+
trades = await self.watch_multiple_wrapper('trades', interval, symbols, params)
|
243
260
|
if self.newUpdates:
|
244
|
-
|
261
|
+
first = self.safe_dict(trades, 0)
|
262
|
+
tradeSymbol = self.safe_string(first, 'symbol')
|
263
|
+
limit = trades.getLimit(tradeSymbol, limit)
|
245
264
|
return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
|
246
265
|
|
247
266
|
def handle_trades(self, client: Client, message):
|
@@ -266,24 +285,25 @@ class deribit(ccxt.async_support.deribit):
|
|
266
285
|
# }
|
267
286
|
# }
|
268
287
|
#
|
269
|
-
params = self.
|
288
|
+
params = self.safe_dict(message, 'params', {})
|
270
289
|
channel = self.safe_string(params, 'channel', '')
|
271
290
|
parts = channel.split('.')
|
272
291
|
marketId = self.safe_string(parts, 1)
|
292
|
+
interval = self.safe_string(parts, 2)
|
273
293
|
symbol = self.safe_symbol(marketId)
|
274
294
|
market = self.safe_market(marketId)
|
275
|
-
trades = self.
|
276
|
-
|
277
|
-
if stored is None:
|
295
|
+
trades = self.safe_list(params, 'data', [])
|
296
|
+
if self.safe_value(self.trades, symbol) is None:
|
278
297
|
limit = self.safe_integer(self.options, 'tradesLimit', 1000)
|
279
|
-
|
280
|
-
|
298
|
+
self.trades[symbol] = ArrayCache(limit)
|
299
|
+
stored = self.trades[symbol]
|
281
300
|
for i in range(0, len(trades)):
|
282
301
|
trade = trades[i]
|
283
302
|
parsed = self.parse_trade(trade, market)
|
284
303
|
stored.append(parsed)
|
285
304
|
self.trades[symbol] = stored
|
286
|
-
|
305
|
+
messageHash = 'trades|' + symbol + '|' + interval
|
306
|
+
client.resolve(self.trades[symbol], messageHash)
|
287
307
|
|
288
308
|
async def watch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
289
309
|
"""
|
@@ -367,7 +387,7 @@ class deribit(ccxt.async_support.deribit):
|
|
367
387
|
|
368
388
|
async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
|
369
389
|
"""
|
370
|
-
:see: https://docs.deribit.com/#
|
390
|
+
:see: https://docs.deribit.com/#book-instrument_name-group-depth-interval
|
371
391
|
watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
|
372
392
|
:param str symbol: unified symbol of the market to fetch the order book for
|
373
393
|
:param int [limit]: the maximum amount of order book entries to return
|
@@ -375,24 +395,34 @@ class deribit(ccxt.async_support.deribit):
|
|
375
395
|
:param str [params.interval]: Frequency of notifications. Events will be aggregated over self interval. Possible values: 100ms, raw
|
376
396
|
:returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
|
377
397
|
"""
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
398
|
+
params['callerMethodName'] = 'watchOrderBook'
|
399
|
+
return await self.watch_order_book_for_symbols([symbol], limit, params)
|
400
|
+
|
401
|
+
async def watch_order_book_for_symbols(self, symbols: List[str], limit: Int = None, params={}) -> OrderBook:
|
402
|
+
"""
|
403
|
+
watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
|
404
|
+
:see: https://docs.deribit.com/#book-instrument_name-group-depth-interval
|
405
|
+
:param str[] symbols: unified array of symbols
|
406
|
+
:param int [limit]: the maximum amount of order book entries to return
|
407
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
408
|
+
:returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
|
409
|
+
"""
|
410
|
+
interval = None
|
411
|
+
interval, params = self.handle_option_and_params(params, 'watchOrderBookForSymbols', 'interval', '100ms')
|
383
412
|
if interval == 'raw':
|
384
413
|
await self.authenticate()
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
414
|
+
descriptor = ''
|
415
|
+
useDepthEndpoint = None # for more info, see comment in .options
|
416
|
+
useDepthEndpoint, params = self.handle_option_and_params(params, 'watchOrderBookForSymbols', 'useDepthEndpoint', False)
|
417
|
+
if useDepthEndpoint:
|
418
|
+
depth = None
|
419
|
+
depth, params = self.handle_option_and_params(params, 'watchOrderBookForSymbols', 'depth', '20')
|
420
|
+
group = None
|
421
|
+
group, params = self.handle_option_and_params(params, 'watchOrderBookForSymbols', 'group', 'none')
|
422
|
+
descriptor = group + '.' + depth + '.' + interval
|
423
|
+
else:
|
424
|
+
descriptor = interval
|
425
|
+
orderbook = await self.watch_multiple_wrapper('book', descriptor, symbols, params)
|
396
426
|
return orderbook.limit()
|
397
427
|
|
398
428
|
def handle_order_book(self, client: Client, message):
|
@@ -444,6 +474,18 @@ class deribit(ccxt.async_support.deribit):
|
|
444
474
|
params = self.safe_value(message, 'params', {})
|
445
475
|
data = self.safe_value(params, 'data', {})
|
446
476
|
channel = self.safe_string(params, 'channel')
|
477
|
+
parts = channel.split('.')
|
478
|
+
descriptor = ''
|
479
|
+
partsLength = len(parts)
|
480
|
+
isDetailed = partsLength == 5
|
481
|
+
if isDetailed:
|
482
|
+
group = self.safe_string(parts, 2)
|
483
|
+
depth = self.safe_string(parts, 3)
|
484
|
+
interval = self.safe_string(parts, 4)
|
485
|
+
descriptor = group + '.' + depth + '.' + interval
|
486
|
+
else:
|
487
|
+
interval = self.safe_string(parts, 2)
|
488
|
+
descriptor = interval
|
447
489
|
marketId = self.safe_string(data, 'instrument_name')
|
448
490
|
symbol = self.safe_symbol(marketId)
|
449
491
|
timestamp = self.safe_integer(data, 'timestamp')
|
@@ -459,7 +501,8 @@ class deribit(ccxt.async_support.deribit):
|
|
459
501
|
storedOrderBook['datetime'] = self.iso8601(timestamp)
|
460
502
|
storedOrderBook['symbol'] = symbol
|
461
503
|
self.orderbooks[symbol] = storedOrderBook
|
462
|
-
|
504
|
+
messageHash = 'book|' + symbol + '|' + descriptor
|
505
|
+
client.resolve(storedOrderBook, messageHash)
|
463
506
|
|
464
507
|
def clean_order_book(self, data):
|
465
508
|
bids = self.safe_value(data, 'bids', [])
|
@@ -584,26 +627,28 @@ class deribit(ccxt.async_support.deribit):
|
|
584
627
|
:returns int[][]: A list of candles ordered, open, high, low, close, volume
|
585
628
|
"""
|
586
629
|
await self.load_markets()
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
630
|
+
symbol = self.symbol(symbol)
|
631
|
+
ohlcvs = await self.watch_ohlcv_for_symbols([[symbol, timeframe]], since, limit, params)
|
632
|
+
return ohlcvs[symbol][timeframe]
|
633
|
+
|
634
|
+
async def watch_ohlcv_for_symbols(self, symbolsAndTimeframes: List[List[str]], since: Int = None, limit: Int = None, params={}):
|
635
|
+
"""
|
636
|
+
watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
637
|
+
:see: https://docs.deribit.com/#chart-trades-instrument_name-resolution
|
638
|
+
:param str[][] symbolsAndTimeframes: array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
|
639
|
+
:param int [since]: timestamp in ms of the earliest candle to fetch
|
640
|
+
:param int [limit]: the maximum amount of candles to fetch
|
641
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
642
|
+
:returns int[][]: A list of candles ordered, open, high, low, close, volume
|
643
|
+
"""
|
644
|
+
symbolsLength = len(symbolsAndTimeframes)
|
645
|
+
if symbolsLength == 0 or not isinstance(symbolsAndTimeframes[0], list):
|
646
|
+
raise ArgumentsRequired(self.id + " watchOHLCVForSymbols() requires a an array of symbols and timeframes, like [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]")
|
647
|
+
symbol, timeframe, candles = await self.watch_multiple_wrapper('chart.trades', None, symbolsAndTimeframes, params)
|
604
648
|
if self.newUpdates:
|
605
|
-
limit =
|
606
|
-
|
649
|
+
limit = candles.getLimit(symbol, limit)
|
650
|
+
filtered = self.filter_by_since_limit(candles, since, limit, 0, True)
|
651
|
+
return self.create_ohlcv_object(symbol, timeframe, filtered)
|
607
652
|
|
608
653
|
def handle_ohlcv(self, client: Client, message):
|
609
654
|
#
|
@@ -624,13 +669,43 @@ class deribit(ccxt.async_support.deribit):
|
|
624
669
|
# }
|
625
670
|
# }
|
626
671
|
#
|
627
|
-
params = self.
|
672
|
+
params = self.safe_dict(message, 'params', {})
|
628
673
|
channel = self.safe_string(params, 'channel', '')
|
629
674
|
parts = channel.split('.')
|
630
675
|
marketId = self.safe_string(parts, 2)
|
631
|
-
|
632
|
-
|
633
|
-
|
676
|
+
rawTimeframe = self.safe_string(parts, 3)
|
677
|
+
market = self.safe_market(marketId)
|
678
|
+
symbol = market['symbol']
|
679
|
+
wsOptions = self.safe_dict(self.options, 'ws', {})
|
680
|
+
timeframes = self.safe_dict(wsOptions, 'timeframes', {})
|
681
|
+
unifiedTimeframe = self.find_timeframe(rawTimeframe, timeframes)
|
682
|
+
self.ohlcvs[symbol] = self.safe_dict(self.ohlcvs, symbol, {})
|
683
|
+
if self.safe_value(self.ohlcvs[symbol], unifiedTimeframe) is None:
|
684
|
+
limit = self.safe_integer(self.options, 'OHLCVLimit', 1000)
|
685
|
+
self.ohlcvs[symbol][unifiedTimeframe] = ArrayCacheByTimestamp(limit)
|
686
|
+
stored = self.ohlcvs[symbol][unifiedTimeframe]
|
687
|
+
ohlcv = self.safe_dict(params, 'data', {})
|
688
|
+
# data contains a single OHLCV candle
|
689
|
+
parsed = self.parse_ws_ohlcv(ohlcv, market)
|
690
|
+
stored.append(parsed)
|
691
|
+
self.ohlcvs[symbol][unifiedTimeframe] = stored
|
692
|
+
resolveData = [symbol, unifiedTimeframe, stored]
|
693
|
+
messageHash = 'chart.trades|' + symbol + '|' + rawTimeframe
|
694
|
+
client.resolve(resolveData, messageHash)
|
695
|
+
|
696
|
+
def parse_ws_ohlcv(self, ohlcv, market=None) -> list:
|
697
|
+
#
|
698
|
+
# {
|
699
|
+
# "c": "28909.0",
|
700
|
+
# "o": "28915.4",
|
701
|
+
# "h": "28915.4",
|
702
|
+
# "l": "28896.1",
|
703
|
+
# "v": "27.6919",
|
704
|
+
# "T": 1696687499999,
|
705
|
+
# "t": 1696687440000
|
706
|
+
# }
|
707
|
+
#
|
708
|
+
return [
|
634
709
|
self.safe_integer(ohlcv, 'tick'),
|
635
710
|
self.safe_number(ohlcv, 'open'),
|
636
711
|
self.safe_number(ohlcv, 'high'),
|
@@ -638,13 +713,42 @@ class deribit(ccxt.async_support.deribit):
|
|
638
713
|
self.safe_number(ohlcv, 'close'),
|
639
714
|
self.safe_number(ohlcv, 'volume'),
|
640
715
|
]
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
716
|
+
|
717
|
+
async def watch_multiple_wrapper(self, channelName: str, channelDescriptor: Str, symbolsArray=None, params={}):
|
718
|
+
await self.load_markets()
|
719
|
+
url = self.urls['api']['ws']
|
720
|
+
rawSubscriptions = []
|
721
|
+
messageHashes = []
|
722
|
+
isOHLCV = (channelName == 'chart.trades')
|
723
|
+
symbols = self.get_list_from_object_values(symbolsArray, 0) if isOHLCV else symbolsArray
|
724
|
+
self.market_symbols(symbols, None, False)
|
725
|
+
for i in range(0, len(symbolsArray)):
|
726
|
+
current = symbolsArray[i]
|
727
|
+
market = None
|
728
|
+
if isOHLCV:
|
729
|
+
market = self.market(current[0])
|
730
|
+
unifiedTf = current[1]
|
731
|
+
rawTf = self.safe_string(self.timeframes, unifiedTf, unifiedTf)
|
732
|
+
channelDescriptor = rawTf
|
733
|
+
else:
|
734
|
+
market = self.market(current)
|
735
|
+
message = channelName + '.' + market['id'] + '.' + channelDescriptor
|
736
|
+
rawSubscriptions.append(message)
|
737
|
+
messageHashes.append(channelName + '|' + market['symbol'] + '|' + channelDescriptor)
|
738
|
+
request = {
|
739
|
+
'jsonrpc': '2.0',
|
740
|
+
'method': 'public/subscribe',
|
741
|
+
'params': {
|
742
|
+
'channels': rawSubscriptions,
|
743
|
+
},
|
744
|
+
'id': self.request_id(),
|
745
|
+
}
|
746
|
+
extendedRequest = self.deep_extend(request, params)
|
747
|
+
maxMessageByteLimit = 32768 - 1 # 'Message Too Big: limit 32768B'
|
748
|
+
jsonedText = self.json(extendedRequest)
|
749
|
+
if len(jsonedText) >= maxMessageByteLimit:
|
750
|
+
raise ExchangeError(self.id + ' requested subscription length over limit, try to reduce symbols amount')
|
751
|
+
return await self.watch_multiple(url, messageHashes, extendedRequest, rawSubscriptions)
|
648
752
|
|
649
753
|
def handle_message(self, client: Client, message):
|
650
754
|
#
|
ccxt/pro/gate.py
CHANGED
@@ -769,7 +769,7 @@ class gate(ccxt.async_support.gate):
|
|
769
769
|
client = self.client(url)
|
770
770
|
self.set_positions_cache(client, type, symbols)
|
771
771
|
fetchPositionsSnapshot = self.handle_option('watchPositions', 'fetchPositionsSnapshot', True)
|
772
|
-
awaitPositionsSnapshot = self.
|
772
|
+
awaitPositionsSnapshot = self.safe_bool('watchPositions', 'awaitPositionsSnapshot', True)
|
773
773
|
cache = self.safe_value(self.positions, type)
|
774
774
|
if fetchPositionsSnapshot and awaitPositionsSnapshot and cache is None:
|
775
775
|
return await client.future(type + ':fetchPositionsSnapshot')
|
ccxt/pro/independentreserve.py
CHANGED
@@ -196,7 +196,7 @@ class independentreserve(ccxt.async_support.independentreserve):
|
|
196
196
|
self.handle_deltas(orderbook['bids'], bids)
|
197
197
|
orderbook['timestamp'] = timestamp
|
198
198
|
orderbook['datetime'] = self.iso8601(timestamp)
|
199
|
-
checksum = self.
|
199
|
+
checksum = self.safe_bool(self.options, 'checksum', True)
|
200
200
|
if checksum and receivedSnapshot:
|
201
201
|
storedAsks = orderbook['asks']
|
202
202
|
storedBids = orderbook['bids']
|
ccxt/pro/kraken.py
CHANGED
@@ -674,7 +674,7 @@ class kraken(ccxt.async_support.kraken):
|
|
674
674
|
example = self.safe_value(b, 0)
|
675
675
|
# don't remove self line or I will poop on your face
|
676
676
|
orderbook.limit()
|
677
|
-
checksum = self.
|
677
|
+
checksum = self.safe_bool(self.options, 'checksum', True)
|
678
678
|
if checksum:
|
679
679
|
priceString = self.safe_string(example, 0)
|
680
680
|
amountString = self.safe_string(example, 1)
|
ccxt/pro/kucoinfutures.py
CHANGED
@@ -231,7 +231,7 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
|
|
231
231
|
client = self.client(url)
|
232
232
|
self.set_position_cache(client, symbol)
|
233
233
|
fetchPositionSnapshot = self.handle_option('watchPosition', 'fetchPositionSnapshot', True)
|
234
|
-
awaitPositionSnapshot = self.
|
234
|
+
awaitPositionSnapshot = self.safe_bool('watchPosition', 'awaitPositionSnapshot', True)
|
235
235
|
currentPosition = self.get_current_position(symbol)
|
236
236
|
if fetchPositionSnapshot and awaitPositionSnapshot and currentPosition is None:
|
237
237
|
snapshot = await client.future('fetchPositionSnapshot:' + symbol)
|