ccxt 4.2.90__py2.py3-none-any.whl → 4.2.91__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/__init__.py +1 -1
- ccxt/async_support/__init__.py +1 -1
- ccxt/async_support/base/exchange.py +1 -1
- ccxt/async_support/coinbase.py +3 -1
- ccxt/async_support/gemini.py +1 -0
- ccxt/async_support/kraken.py +11 -8
- ccxt/async_support/okx.py +30 -30
- ccxt/base/exchange.py +2 -9
- ccxt/coinbase.py +3 -1
- ccxt/gemini.py +1 -0
- ccxt/kraken.py +11 -8
- ccxt/okx.py +30 -30
- ccxt/pro/__init__.py +1 -1
- ccxt/pro/bitmex.py +35 -17
- ccxt/pro/kucoin.py +85 -0
- ccxt/pro/kucoinfutures.py +141 -76
- ccxt/test/test_async.py +15 -1
- ccxt/test/test_sync.py +15 -1
- {ccxt-4.2.90.dist-info → ccxt-4.2.91.dist-info}/METADATA +4 -4
- {ccxt-4.2.90.dist-info → ccxt-4.2.91.dist-info}/RECORD +22 -22
- {ccxt-4.2.90.dist-info → ccxt-4.2.91.dist-info}/WHEEL +0 -0
- {ccxt-4.2.90.dist-info → ccxt-4.2.91.dist-info}/top_level.txt +0 -0
ccxt/pro/bitmex.py
CHANGED
@@ -540,8 +540,8 @@ class bitmex(ccxt.async_support.bitmex):
|
|
540
540
|
for i in range(0, len(marketIds)):
|
541
541
|
marketId = marketIds[i]
|
542
542
|
market = self.safe_market(marketId)
|
543
|
-
messageHash = table + ':' + marketId
|
544
543
|
symbol = market['symbol']
|
544
|
+
messageHash = table + ':' + symbol
|
545
545
|
trades = self.parse_trades(dataByMarketIds[marketId], market)
|
546
546
|
stored = self.safe_value(self.trades, symbol)
|
547
547
|
if stored is None:
|
@@ -561,22 +561,7 @@ class bitmex(ccxt.async_support.bitmex):
|
|
561
561
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
562
562
|
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
|
563
563
|
"""
|
564
|
-
await self.
|
565
|
-
market = self.market(symbol)
|
566
|
-
symbol = market['symbol']
|
567
|
-
table = 'trade'
|
568
|
-
messageHash = table + ':' + market['id']
|
569
|
-
url = self.urls['api']['ws']
|
570
|
-
request = {
|
571
|
-
'op': 'subscribe',
|
572
|
-
'args': [
|
573
|
-
messageHash,
|
574
|
-
],
|
575
|
-
}
|
576
|
-
trades = await self.watch(url, messageHash, self.extend(request, params), messageHash)
|
577
|
-
if self.newUpdates:
|
578
|
-
limit = trades.getLimit(symbol, limit)
|
579
|
-
return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
|
564
|
+
return await self.watch_trades_for_symbols([symbol], since, limit, params)
|
580
565
|
|
581
566
|
async def authenticate(self, params={}):
|
582
567
|
url = self.urls['api']['ws']
|
@@ -1171,6 +1156,39 @@ class bitmex(ccxt.async_support.bitmex):
|
|
1171
1156
|
orderbook = await self.watch_multiple(url, messageHashes, self.deep_extend(request, params), topics)
|
1172
1157
|
return orderbook.limit()
|
1173
1158
|
|
1159
|
+
async def watch_trades_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
1160
|
+
"""
|
1161
|
+
get the list of most recent trades for a list of symbols
|
1162
|
+
:param str[] symbols: unified symbol of the market to fetch trades for
|
1163
|
+
:param int [since]: timestamp in ms of the earliest trade to fetch
|
1164
|
+
:param int [limit]: the maximum amount of trades to fetch
|
1165
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
1166
|
+
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
|
1167
|
+
"""
|
1168
|
+
await self.load_markets()
|
1169
|
+
symbols = self.market_symbols(symbols, None, False)
|
1170
|
+
table = 'trade'
|
1171
|
+
topics = []
|
1172
|
+
messageHashes = []
|
1173
|
+
for i in range(0, len(symbols)):
|
1174
|
+
symbol = symbols[i]
|
1175
|
+
market = self.market(symbol)
|
1176
|
+
topic = table + ':' + market['id']
|
1177
|
+
topics.append(topic)
|
1178
|
+
messageHash = table + ':' + symbol
|
1179
|
+
messageHashes.append(messageHash)
|
1180
|
+
url = self.urls['api']['ws']
|
1181
|
+
request = {
|
1182
|
+
'op': 'subscribe',
|
1183
|
+
'args': topics,
|
1184
|
+
}
|
1185
|
+
trades = await self.watch_multiple(url, messageHashes, self.deep_extend(request, params), topics)
|
1186
|
+
if self.newUpdates:
|
1187
|
+
first = self.safe_value(trades, 0)
|
1188
|
+
tradeSymbol = self.safe_string(first, 'symbol')
|
1189
|
+
limit = trades.getLimit(tradeSymbol, limit)
|
1190
|
+
return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
|
1191
|
+
|
1174
1192
|
async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
|
1175
1193
|
"""
|
1176
1194
|
watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
ccxt/pro/kucoin.py
CHANGED
@@ -25,6 +25,7 @@ class kucoin(ccxt.async_support.kucoin):
|
|
25
25
|
'cancelOrderWs': False,
|
26
26
|
'cancelOrdersWs': False,
|
27
27
|
'cancelAllOrdersWs': False,
|
28
|
+
'watchBidsAsks': True,
|
28
29
|
'watchOrderBook': True,
|
29
30
|
'watchOrders': True,
|
30
31
|
'watchMyTrades': True,
|
@@ -273,6 +274,87 @@ class kucoin(ccxt.async_support.kucoin):
|
|
273
274
|
if numTickers > 0:
|
274
275
|
client.resolve(tickers, currentMessageHash)
|
275
276
|
|
277
|
+
async def watch_bids_asks(self, symbols: Strings = None, params={}) -> Tickers:
|
278
|
+
"""
|
279
|
+
:see: https://www.kucoin.com/docs/websocket/spot-trading/public-channels/level1-bbo-market-data
|
280
|
+
watches best bid & ask for symbols
|
281
|
+
:param str[] symbols: unified symbol of the market to fetch the ticker for
|
282
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
283
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
284
|
+
"""
|
285
|
+
ticker = await self.watch_multi_helper('watchBidsAsks', '/spotMarket/level1:', symbols, params)
|
286
|
+
if self.newUpdates:
|
287
|
+
tickers = {}
|
288
|
+
tickers[ticker['symbol']] = ticker
|
289
|
+
return tickers
|
290
|
+
return self.filter_by_array(self.bidsasks, 'symbol', symbols)
|
291
|
+
|
292
|
+
async def watch_multi_helper(self, methodName, channelName: str, symbols: Strings = None, params={}):
|
293
|
+
await self.load_markets()
|
294
|
+
symbols = self.market_symbols(symbols, None, False, True, False)
|
295
|
+
length = len(symbols)
|
296
|
+
if length > 100:
|
297
|
+
raise ArgumentsRequired(self.id + ' ' + methodName + '() accepts a maximum of 100 symbols')
|
298
|
+
messageHashes = []
|
299
|
+
for i in range(0, len(symbols)):
|
300
|
+
symbol = symbols[i]
|
301
|
+
market = self.market(symbol)
|
302
|
+
messageHashes.append('bidask@' + market['symbol'])
|
303
|
+
url = await self.negotiate(False)
|
304
|
+
marketIds = self.market_ids(symbols)
|
305
|
+
joined = ','.join(marketIds)
|
306
|
+
requestId = str(self.request_id())
|
307
|
+
request = {
|
308
|
+
'id': requestId,
|
309
|
+
'type': 'subscribe',
|
310
|
+
'topic': channelName + joined,
|
311
|
+
'response': True,
|
312
|
+
}
|
313
|
+
message = self.extend(request, params)
|
314
|
+
return await self.watch_multiple(url, messageHashes, message, messageHashes)
|
315
|
+
|
316
|
+
def handle_bid_ask(self, client: Client, message):
|
317
|
+
#
|
318
|
+
# arrives one symbol dict
|
319
|
+
#
|
320
|
+
# {
|
321
|
+
# topic: '/spotMarket/level1:ETH-USDT',
|
322
|
+
# type: 'message',
|
323
|
+
# data: {
|
324
|
+
# asks: ['3347.42', '2.0778387'],
|
325
|
+
# bids: ['3347.41', '6.0411697'],
|
326
|
+
# timestamp: 1712231142085
|
327
|
+
# },
|
328
|
+
# subject: 'level1'
|
329
|
+
# }
|
330
|
+
#
|
331
|
+
parsedTicker = self.parse_ws_bid_ask(message)
|
332
|
+
symbol = parsedTicker['symbol']
|
333
|
+
self.bidsasks[symbol] = parsedTicker
|
334
|
+
messageHash = 'bidask@' + symbol
|
335
|
+
client.resolve(parsedTicker, messageHash)
|
336
|
+
|
337
|
+
def parse_ws_bid_ask(self, ticker, market=None):
|
338
|
+
topic = self.safe_string(ticker, 'topic')
|
339
|
+
parts = topic.split(':')
|
340
|
+
marketId = parts[1]
|
341
|
+
market = self.safe_market(marketId, market)
|
342
|
+
symbol = self.safe_string(market, 'symbol')
|
343
|
+
data = self.safe_dict(ticker, 'data', {})
|
344
|
+
ask = self.safe_list(data, 'asks', [])
|
345
|
+
bid = self.safe_list(data, 'bids', [])
|
346
|
+
timestamp = self.safe_integer(data, 'timestamp')
|
347
|
+
return self.safe_ticker({
|
348
|
+
'symbol': symbol,
|
349
|
+
'timestamp': timestamp,
|
350
|
+
'datetime': self.iso8601(timestamp),
|
351
|
+
'ask': self.safe_number(ask, 0),
|
352
|
+
'askVolume': self.safe_number(ask, 1),
|
353
|
+
'bid': self.safe_number(bid, 0),
|
354
|
+
'bidVolume': self.safe_number(bid, 1),
|
355
|
+
'info': ticker,
|
356
|
+
}, market)
|
357
|
+
|
276
358
|
async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
|
277
359
|
"""
|
278
360
|
watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
@@ -625,6 +707,8 @@ class kucoin(ccxt.async_support.kucoin):
|
|
625
707
|
# }
|
626
708
|
#
|
627
709
|
id = self.safe_string(message, 'id')
|
710
|
+
if not (id in client.subscriptions):
|
711
|
+
return
|
628
712
|
subscriptionHash = self.safe_string(client.subscriptions, id)
|
629
713
|
subscription = self.safe_value(client.subscriptions, subscriptionHash)
|
630
714
|
del client.subscriptions[id]
|
@@ -978,6 +1062,7 @@ class kucoin(ccxt.async_support.kucoin):
|
|
978
1062
|
return
|
979
1063
|
subject = self.safe_string(message, 'subject')
|
980
1064
|
methods = {
|
1065
|
+
'level1': self.handle_bid_ask,
|
981
1066
|
'level2': self.handle_order_book,
|
982
1067
|
'trade.l2update': self.handle_order_book,
|
983
1068
|
'trade.ticker': self.handle_ticker,
|
ccxt/pro/kucoinfutures.py
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
import ccxt.async_support
|
7
7
|
from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById
|
8
|
-
from ccxt.base.types import Balances, Int, Order, OrderBook, Position, Str, Ticker, Trade
|
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
11
|
from ccxt.base.errors import ExchangeError
|
@@ -19,6 +19,8 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
|
|
19
19
|
'has': {
|
20
20
|
'ws': True,
|
21
21
|
'watchTicker': True,
|
22
|
+
'watchTickers': True,
|
23
|
+
'watchBidsAsks': True,
|
22
24
|
'watchTrades': True,
|
23
25
|
'watchOrderBook': True,
|
24
26
|
'watchOrders': True,
|
@@ -48,9 +50,6 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
|
|
48
50
|
'snapshotDelay': 20,
|
49
51
|
'snapshotMaxRetries': 3,
|
50
52
|
},
|
51
|
-
'watchTicker': {
|
52
|
-
'name': 'contractMarket/tickerV2', # market/ticker
|
53
|
-
},
|
54
53
|
'watchPosition': {
|
55
54
|
'fetchPositionSnapshot': True, # or False
|
56
55
|
'awaitPositionSnapshot': True, # whether to wait for the position snapshot before providing updates
|
@@ -146,7 +145,7 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
|
|
146
145
|
subscription = self.extend(subscriptionRequest, subscription)
|
147
146
|
return await self.watch(url, messageHash, message, subscriptionHash, subscription)
|
148
147
|
|
149
|
-
async def subscribe_multiple(self, url, messageHashes, topic, subscriptionHashes,
|
148
|
+
async def subscribe_multiple(self, url, messageHashes, topic, subscriptionHashes, subscriptionArgs, params={}):
|
150
149
|
requestId = str(self.request_id())
|
151
150
|
request = {
|
152
151
|
'id': requestId,
|
@@ -154,20 +153,12 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
|
|
154
153
|
'topic': topic,
|
155
154
|
'response': True,
|
156
155
|
}
|
157
|
-
|
158
|
-
subscriptionRequest = {
|
159
|
-
'id': requestId,
|
160
|
-
}
|
161
|
-
if subscription is None:
|
162
|
-
subscription = subscriptionRequest
|
163
|
-
else:
|
164
|
-
subscription = self.extend(subscriptionRequest, subscription)
|
165
|
-
return await self.watch_multiple(url, messageHashes, message, subscriptionHashes, subscription)
|
156
|
+
return await self.watch_multiple(url, messageHashes, self.extend(request, params), subscriptionHashes, subscriptionArgs)
|
166
157
|
|
167
158
|
async def watch_ticker(self, symbol: str, params={}) -> Ticker:
|
168
159
|
"""
|
169
160
|
watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
|
170
|
-
:see: https://
|
161
|
+
:see: https://www.kucoin.com/docs/websocket/futures-trading/public-channels/get-ticker
|
171
162
|
:param str symbol: unified symbol of the market to fetch the ticker for
|
172
163
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
173
164
|
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
@@ -175,30 +166,45 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
|
|
175
166
|
await self.load_markets()
|
176
167
|
market = self.market(symbol)
|
177
168
|
symbol = market['symbol']
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
169
|
+
params['callerMethodName'] = 'watchTicker'
|
170
|
+
tickers = await self.watch_tickers([symbol], params)
|
171
|
+
return tickers[symbol]
|
172
|
+
|
173
|
+
async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
|
174
|
+
"""
|
175
|
+
watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
|
176
|
+
:param str[] symbols: unified symbol of the market to fetch the ticker for
|
177
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
178
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
179
|
+
"""
|
180
|
+
await self.load_markets()
|
181
|
+
ticker = await self.watch_multi_request('watchTickers', '/contractMarket/ticker:', symbols, params)
|
182
|
+
if self.newUpdates:
|
183
|
+
tickers = {}
|
184
|
+
tickers[ticker['symbol']] = ticker
|
185
|
+
return tickers
|
186
|
+
return self.filter_by_array(self.tickers, 'symbol', symbols)
|
184
187
|
|
185
188
|
def handle_ticker(self, client: Client, message):
|
186
189
|
#
|
187
|
-
#
|
190
|
+
# ticker(v1)
|
188
191
|
#
|
189
192
|
# {
|
190
|
-
#
|
191
|
-
#
|
192
|
-
#
|
193
|
-
#
|
194
|
-
#
|
195
|
-
#
|
196
|
-
#
|
197
|
-
#
|
198
|
-
#
|
199
|
-
#
|
200
|
-
#
|
201
|
-
#
|
193
|
+
# "subject": "ticker",
|
194
|
+
# "topic": "/contractMarket/ticker:XBTUSDM",
|
195
|
+
# "data": {
|
196
|
+
# "symbol": "XBTUSDM", #Market of the symbol
|
197
|
+
# "sequence": 45, #Sequence number which is used to judge the continuity of the pushed messages
|
198
|
+
# "side": "sell", #Transaction side of the last traded taker order
|
199
|
+
# "price": "3600.0", #Filled price
|
200
|
+
# "size": 16, #Filled quantity
|
201
|
+
# "tradeId": "5c9dcf4170744d6f5a3d32fb", #Order ID
|
202
|
+
# "bestBidSize": 795, #Best bid size
|
203
|
+
# "bestBidPrice": "3200.0", #Best bid
|
204
|
+
# "bestAskPrice": "3600.0", #Best ask size
|
205
|
+
# "bestAskSize": 284, #Best ask
|
206
|
+
# "ts": 1553846081210004941 #Filled time - nanosecond
|
207
|
+
# }
|
202
208
|
# }
|
203
209
|
#
|
204
210
|
data = self.safe_value(message, 'data', {})
|
@@ -206,9 +212,90 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
|
|
206
212
|
market = self.safe_market(marketId, None, '-')
|
207
213
|
ticker = self.parse_ticker(data, market)
|
208
214
|
self.tickers[market['symbol']] = ticker
|
209
|
-
|
210
|
-
|
211
|
-
|
215
|
+
client.resolve(ticker, self.get_message_hash('ticker', market['symbol']))
|
216
|
+
|
217
|
+
async def watch_bids_asks(self, symbols: Strings = None, params={}) -> Tickers:
|
218
|
+
"""
|
219
|
+
:see: https://www.kucoin.com/docs/websocket/futures-trading/public-channels/get-ticker-v2
|
220
|
+
watches best bid & ask for symbols
|
221
|
+
:param str[] symbols: unified symbol of the market to fetch the ticker for
|
222
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
223
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
224
|
+
"""
|
225
|
+
ticker = await self.watch_multi_request('watchBidsAsks', '/contractMarket/tickerV2:', symbols, params)
|
226
|
+
if self.newUpdates:
|
227
|
+
tickers = {}
|
228
|
+
tickers[ticker['symbol']] = ticker
|
229
|
+
return tickers
|
230
|
+
return self.filter_by_array(self.bidsasks, 'symbol', symbols)
|
231
|
+
|
232
|
+
async def watch_multi_request(self, methodName, channelName: str, symbols: Strings = None, params={}):
|
233
|
+
await self.load_markets()
|
234
|
+
methodName, params = self.handle_param_string(params, 'callerMethodName', methodName)
|
235
|
+
isBidsAsks = (methodName == 'watchBidsAsks')
|
236
|
+
symbols = self.market_symbols(symbols, None, False, True, False)
|
237
|
+
length = len(symbols)
|
238
|
+
if length > 100:
|
239
|
+
raise ArgumentsRequired(self.id + ' ' + methodName + '() accepts a maximum of 100 symbols')
|
240
|
+
messageHashes = []
|
241
|
+
for i in range(0, len(symbols)):
|
242
|
+
symbol = symbols[i]
|
243
|
+
market = self.market(symbol)
|
244
|
+
prefix = 'bidask' if isBidsAsks else 'ticker'
|
245
|
+
messageHashes.append(self.get_message_hash(prefix, market['symbol']))
|
246
|
+
url = await self.negotiate(False)
|
247
|
+
marketIds = self.market_ids(symbols)
|
248
|
+
joined = ','.join(marketIds)
|
249
|
+
requestId = str(self.request_id())
|
250
|
+
request = {
|
251
|
+
'id': requestId,
|
252
|
+
'type': 'subscribe',
|
253
|
+
'topic': channelName + joined,
|
254
|
+
'response': True,
|
255
|
+
}
|
256
|
+
subscription = {
|
257
|
+
'id': requestId,
|
258
|
+
}
|
259
|
+
return await self.watch_multiple(url, messageHashes, self.extend(request, params), messageHashes, subscription)
|
260
|
+
|
261
|
+
def handle_bid_ask(self, client: Client, message):
|
262
|
+
#
|
263
|
+
# arrives one symbol dict
|
264
|
+
#
|
265
|
+
# {
|
266
|
+
# "subject": "tickerV2",
|
267
|
+
# "topic": "/contractMarket/tickerV2:XBTUSDM",
|
268
|
+
# "data": {
|
269
|
+
# "symbol": "XBTUSDM", #Market of the symbol
|
270
|
+
# "bestBidSize": 795, # Best bid size
|
271
|
+
# "bestBidPrice": 3200.0, # Best bid
|
272
|
+
# "bestAskPrice": 3600.0, # Best ask
|
273
|
+
# "bestAskSize": 284, # Best ask size
|
274
|
+
# "ts": 1553846081210004941 # Filled time - nanosecond
|
275
|
+
# }
|
276
|
+
# }
|
277
|
+
#
|
278
|
+
parsedTicker = self.parse_ws_bid_ask(message)
|
279
|
+
symbol = parsedTicker['symbol']
|
280
|
+
self.bidsasks[symbol] = parsedTicker
|
281
|
+
client.resolve(parsedTicker, self.get_message_hash('bidask', symbol))
|
282
|
+
|
283
|
+
def parse_ws_bid_ask(self, ticker, market=None):
|
284
|
+
data = self.safe_dict(ticker, 'data', {})
|
285
|
+
marketId = self.safe_string(data, 'symbol')
|
286
|
+
market = self.safe_market(marketId, market)
|
287
|
+
symbol = self.safe_string(market, 'symbol')
|
288
|
+
timestamp = self.safe_integer_product(data, 'ts', 0.000001)
|
289
|
+
return self.safe_ticker({
|
290
|
+
'symbol': symbol,
|
291
|
+
'timestamp': timestamp,
|
292
|
+
'datetime': self.iso8601(timestamp),
|
293
|
+
'ask': self.safe_number(data, 'bestAskPrice'),
|
294
|
+
'askVolume': self.safe_number(data, 'bestAskSize'),
|
295
|
+
'bid': self.safe_number(data, 'bestBidPrice'),
|
296
|
+
'bidVolume': self.safe_number(data, 'bestBidSize'),
|
297
|
+
'info': ticker,
|
298
|
+
}, market)
|
212
299
|
|
213
300
|
async def watch_position(self, symbol: Str = None, params={}) -> Position:
|
214
301
|
"""
|
@@ -412,7 +499,7 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
|
|
412
499
|
marketId = marketIds[i]
|
413
500
|
messageHashes.append('trades:' + symbol)
|
414
501
|
subscriptionHashes.append('/contractMarket/execution:' + marketId)
|
415
|
-
trades = await self.subscribe_multiple(url, messageHashes, topic, subscriptionHashes, params)
|
502
|
+
trades = await self.subscribe_multiple(url, messageHashes, topic, subscriptionHashes, None, params)
|
416
503
|
if self.newUpdates:
|
417
504
|
first = self.safe_value(trades, 0)
|
418
505
|
tradeSymbol = self.safe_string(first, 'symbol')
|
@@ -489,9 +576,7 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
|
|
489
576
|
marketIds = self.market_ids(symbols)
|
490
577
|
url = await self.negotiate(False)
|
491
578
|
topic = '/contractMarket/level2:' + ','.join(marketIds)
|
492
|
-
|
493
|
-
'method': self.handle_order_book_subscription,
|
494
|
-
'symbols': symbols,
|
579
|
+
subscriptionArgs = {
|
495
580
|
'limit': limit,
|
496
581
|
}
|
497
582
|
subscriptionHashes = []
|
@@ -501,7 +586,7 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
|
|
501
586
|
marketId = marketIds[i]
|
502
587
|
messageHashes.append('orderbook:' + symbol)
|
503
588
|
subscriptionHashes.append('/contractMarket/level2:' + marketId)
|
504
|
-
orderbook = await self.subscribe_multiple(url, messageHashes, topic, subscriptionHashes,
|
589
|
+
orderbook = await self.subscribe_multiple(url, messageHashes, topic, subscriptionHashes, subscriptionArgs, params)
|
505
590
|
return orderbook.limit()
|
506
591
|
|
507
592
|
def handle_delta(self, orderbook, delta):
|
@@ -549,10 +634,12 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
|
|
549
634
|
marketId = self.safe_string(topicParts, 1)
|
550
635
|
symbol = self.safe_symbol(marketId, None, '-')
|
551
636
|
messageHash = 'orderbook:' + symbol
|
552
|
-
|
637
|
+
if not (symbol in self.orderbooks):
|
638
|
+
subscriptionArgs = self.safe_dict(client.subscriptions, topic, {})
|
639
|
+
limit = self.safe_integer(subscriptionArgs, 'limit')
|
640
|
+
self.orderbooks[symbol] = self.order_book({}, limit)
|
641
|
+
storedOrderBook = self.orderbooks[symbol]
|
553
642
|
nonce = self.safe_integer(storedOrderBook, 'nonce')
|
554
|
-
if storedOrderBook is None:
|
555
|
-
return # self shouldn't be needed, but for some reason sometimes self runs before handleOrderBookSubscription in c#
|
556
643
|
deltaEnd = self.safe_integer(data, 'sequence')
|
557
644
|
if nonce is None:
|
558
645
|
cacheLength = len(storedOrderBook.cache)
|
@@ -590,35 +677,6 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
|
|
590
677
|
return i
|
591
678
|
return len(cache)
|
592
679
|
|
593
|
-
def handle_order_book_subscription(self, client: Client, message, subscription):
|
594
|
-
limit = self.safe_integer(subscription, 'limit')
|
595
|
-
symbols = self.safe_value(subscription, 'symbols')
|
596
|
-
if symbols is None:
|
597
|
-
symbol = self.safe_string(subscription, 'symbol')
|
598
|
-
self.orderbooks[symbol] = self.order_book({}, limit)
|
599
|
-
else:
|
600
|
-
for i in range(0, len(symbols)):
|
601
|
-
symbol = symbols[i]
|
602
|
-
self.orderbooks[symbol] = self.order_book({}, limit)
|
603
|
-
# moved snapshot initialization to handleOrderBook to fix
|
604
|
-
# https://github.com/ccxt/ccxt/issues/6820
|
605
|
-
# the general idea is to fetch the snapshot after the first delta
|
606
|
-
# but not before, because otherwise we cannot synchronize the feed
|
607
|
-
|
608
|
-
def handle_subscription_status(self, client: Client, message):
|
609
|
-
#
|
610
|
-
# {
|
611
|
-
# "id": "1578090438322",
|
612
|
-
# "type": "ack"
|
613
|
-
# }
|
614
|
-
#
|
615
|
-
id = self.safe_string(message, 'id')
|
616
|
-
subscriptionsById = self.index_by(client.subscriptions, 'id')
|
617
|
-
subscription = self.safe_value(subscriptionsById, id, {})
|
618
|
-
method = self.safe_value(subscription, 'method')
|
619
|
-
if method is not None:
|
620
|
-
method(client, message, subscription)
|
621
|
-
|
622
680
|
def handle_system_status(self, client: Client, message):
|
623
681
|
#
|
624
682
|
# todo: answer the question whether handleSystemStatus should be renamed
|
@@ -864,7 +922,8 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
|
|
864
922
|
subject = self.safe_string(message, 'subject')
|
865
923
|
methods = {
|
866
924
|
'level2': self.handle_order_book,
|
867
|
-
'
|
925
|
+
'ticker': self.handle_ticker,
|
926
|
+
'tickerV2': self.handle_bid_ask,
|
868
927
|
'availableBalance.change': self.handle_balance,
|
869
928
|
'match': self.handle_trade,
|
870
929
|
'orderChange': self.handle_order,
|
@@ -877,6 +936,13 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
|
|
877
936
|
if method is not None:
|
878
937
|
method(client, message)
|
879
938
|
|
939
|
+
def get_message_hash(self, elementName: str, symbol: Str = None):
|
940
|
+
# elementName can be 'ticker', 'bidask', ...
|
941
|
+
if symbol is not None:
|
942
|
+
return elementName + '@' + symbol
|
943
|
+
else:
|
944
|
+
return elementName + 's@all'
|
945
|
+
|
880
946
|
def ping(self, client):
|
881
947
|
# kucoin does not support built-in ws protocol-level ping-pong
|
882
948
|
# instead it requires a custom json-based text ping-pong
|
@@ -914,7 +980,6 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
|
|
914
980
|
methods = {
|
915
981
|
# 'heartbeat': self.handleHeartbeat,
|
916
982
|
'welcome': self.handle_system_status,
|
917
|
-
'ack': self.handle_subscription_status,
|
918
983
|
'message': self.handle_subject,
|
919
984
|
'pong': self.handle_pong,
|
920
985
|
'error': self.handle_error_message,
|
ccxt/test/test_async.py
CHANGED
@@ -1235,7 +1235,7 @@ class testMainClass(baseMainTestClass):
|
|
1235
1235
|
# -----------------------------------------------------------------------------
|
1236
1236
|
# --- Init of brokerId tests functions-----------------------------------------
|
1237
1237
|
# -----------------------------------------------------------------------------
|
1238
|
-
promises = [self.test_binance(), self.test_okx(), self.test_cryptocom(), self.test_bybit(), self.test_kucoin(), self.test_kucoinfutures(), self.test_bitget(), self.test_mexc(), self.test_htx(), self.test_woo(), self.test_bitmart(), self.test_coinex(), self.test_bingx(), self.test_phemex(), self.test_blofin(), self.test_hyperliquid(), self.test_coinbaseinternational()]
|
1238
|
+
promises = [self.test_binance(), self.test_okx(), self.test_cryptocom(), self.test_bybit(), self.test_kucoin(), self.test_kucoinfutures(), self.test_bitget(), self.test_mexc(), self.test_htx(), self.test_woo(), self.test_bitmart(), self.test_coinex(), self.test_bingx(), self.test_phemex(), self.test_blofin(), self.test_hyperliquid(), self.test_coinbaseinternational(), self.test_coinbase_advanced()]
|
1239
1239
|
await asyncio.gather(*promises)
|
1240
1240
|
success_message = '[' + self.lang + '][TEST_SUCCESS] brokerId tests passed.'
|
1241
1241
|
dump('[INFO]' + success_message)
|
@@ -1534,6 +1534,20 @@ class testMainClass(baseMainTestClass):
|
|
1534
1534
|
await close(exchange)
|
1535
1535
|
return True
|
1536
1536
|
|
1537
|
+
async def test_coinbase_advanced(self):
|
1538
|
+
exchange = self.init_offline_exchange('coinbase')
|
1539
|
+
id = 'ccxt'
|
1540
|
+
assert exchange.options['brokerId'] == id, 'id not in options'
|
1541
|
+
request = None
|
1542
|
+
try:
|
1543
|
+
await exchange.create_order('BTC/USDC', 'limit', 'buy', 1, 20000)
|
1544
|
+
except Exception as e:
|
1545
|
+
request = json_parse(exchange.last_request_body)
|
1546
|
+
client_order_id = request['client_order_id']
|
1547
|
+
assert client_order_id.startswith(str(id)), 'clientOrderId does not start with id'
|
1548
|
+
await close(exchange)
|
1549
|
+
return True
|
1550
|
+
|
1537
1551
|
# ***** AUTO-TRANSPILER-END *****
|
1538
1552
|
# *******************************
|
1539
1553
|
|
ccxt/test/test_sync.py
CHANGED
@@ -1234,7 +1234,7 @@ class testMainClass(baseMainTestClass):
|
|
1234
1234
|
# -----------------------------------------------------------------------------
|
1235
1235
|
# --- Init of brokerId tests functions-----------------------------------------
|
1236
1236
|
# -----------------------------------------------------------------------------
|
1237
|
-
promises = [self.test_binance(), self.test_okx(), self.test_cryptocom(), self.test_bybit(), self.test_kucoin(), self.test_kucoinfutures(), self.test_bitget(), self.test_mexc(), self.test_htx(), self.test_woo(), self.test_bitmart(), self.test_coinex(), self.test_bingx(), self.test_phemex(), self.test_blofin(), self.test_hyperliquid(), self.test_coinbaseinternational()]
|
1237
|
+
promises = [self.test_binance(), self.test_okx(), self.test_cryptocom(), self.test_bybit(), self.test_kucoin(), self.test_kucoinfutures(), self.test_bitget(), self.test_mexc(), self.test_htx(), self.test_woo(), self.test_bitmart(), self.test_coinex(), self.test_bingx(), self.test_phemex(), self.test_blofin(), self.test_hyperliquid(), self.test_coinbaseinternational(), self.test_coinbase_advanced()]
|
1238
1238
|
(promises)
|
1239
1239
|
success_message = '[' + self.lang + '][TEST_SUCCESS] brokerId tests passed.'
|
1240
1240
|
dump('[INFO]' + success_message)
|
@@ -1533,6 +1533,20 @@ class testMainClass(baseMainTestClass):
|
|
1533
1533
|
close(exchange)
|
1534
1534
|
return True
|
1535
1535
|
|
1536
|
+
def test_coinbase_advanced(self):
|
1537
|
+
exchange = self.init_offline_exchange('coinbase')
|
1538
|
+
id = 'ccxt'
|
1539
|
+
assert exchange.options['brokerId'] == id, 'id not in options'
|
1540
|
+
request = None
|
1541
|
+
try:
|
1542
|
+
exchange.create_order('BTC/USDC', 'limit', 'buy', 1, 20000)
|
1543
|
+
except Exception as e:
|
1544
|
+
request = json_parse(exchange.last_request_body)
|
1545
|
+
client_order_id = request['client_order_id']
|
1546
|
+
assert client_order_id.startswith(str(id)), 'clientOrderId does not start with id'
|
1547
|
+
close(exchange)
|
1548
|
+
return True
|
1549
|
+
|
1536
1550
|
# ***** AUTO-TRANSPILER-END *****
|
1537
1551
|
# *******************************
|
1538
1552
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: ccxt
|
3
|
-
Version: 4.2.
|
3
|
+
Version: 4.2.91
|
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
|
@@ -261,13 +261,13 @@ console.log(version, Object.keys(exchanges));
|
|
261
261
|
|
262
262
|
All-in-one browser bundle (dependencies included), served from a CDN of your choice:
|
263
263
|
|
264
|
-
* jsDelivr: https://cdn.jsdelivr.net/npm/ccxt@4.2.
|
265
|
-
* unpkg: https://unpkg.com/ccxt@4.2.
|
264
|
+
* jsDelivr: https://cdn.jsdelivr.net/npm/ccxt@4.2.91/dist/ccxt.browser.js
|
265
|
+
* unpkg: https://unpkg.com/ccxt@4.2.91/dist/ccxt.browser.js
|
266
266
|
|
267
267
|
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.
|
268
268
|
|
269
269
|
```HTML
|
270
|
-
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ccxt@4.2.
|
270
|
+
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ccxt@4.2.91/dist/ccxt.browser.js"></script>
|
271
271
|
```
|
272
272
|
|
273
273
|
Creates a global `ccxt` object:
|