ccxt 4.3.94__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/__init__.py +1 -5
- ccxt/abstract/okx.py +2 -0
- ccxt/ascendex.py +8 -6
- ccxt/async_support/__init__.py +1 -5
- ccxt/async_support/ascendex.py +9 -6
- ccxt/async_support/base/exchange.py +1 -4
- ccxt/async_support/bingx.py +1 -0
- ccxt/async_support/bitfinex.py +4 -2
- ccxt/async_support/bitfinex2.py +7 -5
- ccxt/async_support/blofin.py +0 -1
- ccxt/async_support/btcturk.py +3 -3
- ccxt/async_support/bybit.py +7 -2
- ccxt/async_support/gate.py +3 -2
- ccxt/async_support/gemini.py +3 -2
- ccxt/async_support/hyperliquid.py +311 -40
- ccxt/async_support/independentreserve.py +5 -3
- ccxt/async_support/indodax.py +2 -0
- ccxt/async_support/kucoin.py +12 -12
- ccxt/async_support/mexc.py +78 -154
- ccxt/async_support/okx.py +2 -1
- ccxt/async_support/p2b.py +0 -1
- ccxt/async_support/tradeogre.py +0 -1
- ccxt/base/exchange.py +4 -8
- ccxt/bingx.py +1 -0
- ccxt/bitfinex.py +3 -2
- ccxt/bitfinex2.py +6 -5
- ccxt/blofin.py +0 -1
- ccxt/btcturk.py +3 -3
- ccxt/bybit.py +7 -2
- ccxt/gate.py +3 -2
- ccxt/gemini.py +3 -2
- ccxt/hyperliquid.py +311 -40
- ccxt/independentreserve.py +4 -3
- ccxt/indodax.py +2 -0
- ccxt/kucoin.py +2 -2
- ccxt/mexc.py +78 -154
- ccxt/okx.py +2 -1
- ccxt/p2b.py +0 -1
- ccxt/pro/__init__.py +1 -1
- ccxt/pro/binance.py +90 -2
- ccxt/pro/bybit.py +58 -4
- ccxt/pro/cryptocom.py +195 -0
- ccxt/pro/okx.py +238 -31
- ccxt/test/tests_async.py +3 -0
- ccxt/test/tests_sync.py +3 -0
- ccxt/tradeogre.py +0 -1
- {ccxt-4.3.94.dist-info → ccxt-4.3.96.dist-info}/METADATA +5 -5
- {ccxt-4.3.94.dist-info → ccxt-4.3.96.dist-info}/RECORD +51 -53
- ccxt/abstract/bitbay.py +0 -53
- ccxt/abstract/hitbtc3.py +0 -115
- {ccxt-4.3.94.dist-info → ccxt-4.3.96.dist-info}/LICENSE.txt +0 -0
- {ccxt-4.3.94.dist-info → ccxt-4.3.96.dist-info}/WHEEL +0 -0
- {ccxt-4.3.94.dist-info → ccxt-4.3.96.dist-info}/top_level.txt +0 -0
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]
|
ccxt/pro/okx.py
CHANGED
@@ -27,6 +27,7 @@ class okx(ccxt.async_support.okx):
|
|
27
27
|
'ws': True,
|
28
28
|
'watchTicker': True,
|
29
29
|
'watchTickers': True,
|
30
|
+
'watchBidsAsks': True,
|
30
31
|
'watchOrderBook': True,
|
31
32
|
'watchTrades': True,
|
32
33
|
'watchTradesForSymbols': True,
|
@@ -135,9 +136,8 @@ class okx(ccxt.async_support.okx):
|
|
135
136
|
symbols = self.symbols
|
136
137
|
symbols = self.market_symbols(symbols)
|
137
138
|
url = self.get_url(channel, access)
|
138
|
-
|
139
|
+
messageHashes = []
|
139
140
|
args = []
|
140
|
-
messageHash += '::' + ','.join(symbols)
|
141
141
|
for i in range(0, len(symbols)):
|
142
142
|
marketId = self.market_id(symbols[i])
|
143
143
|
arg: dict = {
|
@@ -145,11 +145,12 @@ class okx(ccxt.async_support.okx):
|
|
145
145
|
'instId': marketId,
|
146
146
|
}
|
147
147
|
args.append(self.extend(arg, params))
|
148
|
+
messageHashes.append(channel + '::' + symbols[i])
|
148
149
|
request: dict = {
|
149
150
|
'op': 'subscribe',
|
150
151
|
'args': args,
|
151
152
|
}
|
152
|
-
return await self.
|
153
|
+
return await self.watch_multiple(url, messageHashes, request, messageHashes)
|
153
154
|
|
154
155
|
async def subscribe(self, access, messageHash, channel, symbol, params={}):
|
155
156
|
await self.load_markets()
|
@@ -379,6 +380,17 @@ class okx(ccxt.async_support.okx):
|
|
379
380
|
ticker = await self.watch_tickers([symbol], params)
|
380
381
|
return self.safe_value(ticker, symbol)
|
381
382
|
|
383
|
+
async def un_watch_ticker(self, symbol: str, params={}) -> Any:
|
384
|
+
"""
|
385
|
+
:see: https://www.okx.com/docs-v5/en/#order-book-trading-market-data-ws-tickers-channel
|
386
|
+
unWatches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
|
387
|
+
:param str symbol: unified symbol of the market to fetch the ticker for
|
388
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
389
|
+
:param str [params.channel]: the channel to subscribe to, tickers by default. Can be tickers, sprd-tickers, index-tickers, block-tickers
|
390
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
391
|
+
"""
|
392
|
+
return await self.un_watch_tickers([symbol], params)
|
393
|
+
|
382
394
|
async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
|
383
395
|
"""
|
384
396
|
:see: https://www.okx.com/docs-v5/en/#order-book-trading-market-data-ws-tickers-channel
|
@@ -397,6 +409,37 @@ class okx(ccxt.async_support.okx):
|
|
397
409
|
return newTickers
|
398
410
|
return self.filter_by_array(self.tickers, 'symbol', symbols)
|
399
411
|
|
412
|
+
async def un_watch_tickers(self, symbols: Strings = None, params={}) -> Any:
|
413
|
+
"""
|
414
|
+
:see: https://www.okx.com/docs-v5/en/#order-book-trading-market-data-ws-tickers-channel
|
415
|
+
unWatches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
|
416
|
+
:param str[] [symbols]: unified symbol of the market to fetch the ticker for
|
417
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
418
|
+
:param str [params.channel]: the channel to subscribe to, tickers by default. Can be tickers, sprd-tickers, index-tickers, block-tickers
|
419
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
420
|
+
"""
|
421
|
+
await self.load_markets()
|
422
|
+
symbols = self.market_symbols(symbols, None, False)
|
423
|
+
channel = None
|
424
|
+
channel, params = self.handle_option_and_params(params, 'watchTickers', 'channel', 'tickers')
|
425
|
+
topics = []
|
426
|
+
messageHashes = []
|
427
|
+
for i in range(0, len(symbols)):
|
428
|
+
symbol = symbols[i]
|
429
|
+
messageHashes.append('unsubscribe:ticker:' + symbol)
|
430
|
+
marketId = self.market_id(symbol)
|
431
|
+
topic: dict = {
|
432
|
+
'channel': channel,
|
433
|
+
'instId': marketId,
|
434
|
+
}
|
435
|
+
topics.append(topic)
|
436
|
+
request: dict = {
|
437
|
+
'op': 'unsubscribe',
|
438
|
+
'args': topics,
|
439
|
+
}
|
440
|
+
url = self.get_url(channel, 'public')
|
441
|
+
return await self.watch_multiple(url, messageHashes, request, messageHashes)
|
442
|
+
|
400
443
|
def handle_ticker(self, client: Client, message):
|
401
444
|
#
|
402
445
|
# {
|
@@ -423,27 +466,104 @@ class okx(ccxt.async_support.okx):
|
|
423
466
|
# ]
|
424
467
|
# }
|
425
468
|
#
|
469
|
+
self.handle_bid_ask(client, message)
|
426
470
|
arg = self.safe_value(message, 'arg', {})
|
471
|
+
marketId = self.safe_string(arg, 'instId')
|
472
|
+
market = self.safe_market(marketId, None, '-')
|
473
|
+
symbol = market['symbol']
|
427
474
|
channel = self.safe_string(arg, 'channel')
|
428
475
|
data = self.safe_value(message, 'data', [])
|
429
|
-
newTickers =
|
476
|
+
newTickers: dict = {}
|
430
477
|
for i in range(0, len(data)):
|
431
478
|
ticker = self.parse_ticker(data[i])
|
432
|
-
symbol = ticker['symbol']
|
433
479
|
self.tickers[symbol] = ticker
|
434
|
-
newTickers
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
480
|
+
newTickers[symbol] = ticker
|
481
|
+
messageHash = channel + '::' + symbol
|
482
|
+
client.resolve(newTickers, messageHash)
|
483
|
+
|
484
|
+
async def watch_bids_asks(self, symbols: Strings = None, params={}) -> Tickers:
|
485
|
+
"""
|
486
|
+
:see: https://www.okx.com/docs-v5/en/#order-book-trading-market-data-ws-tickers-channel
|
487
|
+
watches best bid & ask for symbols
|
488
|
+
:param str[] symbols: unified symbol of the market to fetch the ticker for
|
489
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
490
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
491
|
+
"""
|
492
|
+
await self.load_markets()
|
493
|
+
symbols = self.market_symbols(symbols, None, False)
|
494
|
+
channel = None
|
495
|
+
channel, params = self.handle_option_and_params(params, 'watchBidsAsks', 'channel', 'tickers')
|
496
|
+
url = self.get_url(channel, 'public')
|
497
|
+
messageHashes = []
|
498
|
+
args = []
|
499
|
+
for i in range(0, len(symbols)):
|
500
|
+
marketId = self.market_id(symbols[i])
|
501
|
+
arg: dict = {
|
502
|
+
'channel': channel,
|
503
|
+
'instId': marketId,
|
504
|
+
}
|
505
|
+
args.append(self.extend(arg, params))
|
506
|
+
messageHashes.append('bidask::' + symbols[i])
|
507
|
+
request: dict = {
|
508
|
+
'op': 'subscribe',
|
509
|
+
'args': args,
|
510
|
+
}
|
511
|
+
newTickers = await self.watch_multiple(url, messageHashes, request, messageHashes)
|
512
|
+
if self.newUpdates:
|
513
|
+
tickers: dict = {}
|
514
|
+
tickers[newTickers['symbol']] = newTickers
|
515
|
+
return tickers
|
516
|
+
return self.filter_by_array(self.bidsasks, 'symbol', symbols)
|
517
|
+
|
518
|
+
def handle_bid_ask(self, client: Client, message):
|
519
|
+
#
|
520
|
+
# {
|
521
|
+
# "arg": {channel: "tickers", instId: "BTC-USDT"},
|
522
|
+
# "data": [
|
523
|
+
# {
|
524
|
+
# "instType": "SPOT",
|
525
|
+
# "instId": "BTC-USDT",
|
526
|
+
# "last": "31500.1",
|
527
|
+
# "lastSz": "0.00001754",
|
528
|
+
# "askPx": "31500.1",
|
529
|
+
# "askSz": "0.00998144",
|
530
|
+
# "bidPx": "31500",
|
531
|
+
# "bidSz": "3.05652439",
|
532
|
+
# "open24h": "31697",
|
533
|
+
# "high24h": "32248",
|
534
|
+
# "low24h": "31165.6",
|
535
|
+
# "sodUtc0": "31385.5",
|
536
|
+
# "sodUtc8": "32134.9",
|
537
|
+
# "volCcy24h": "503403597.38138519",
|
538
|
+
# "vol24h": "15937.10781721",
|
539
|
+
# "ts": "1626526618762"
|
540
|
+
# }
|
541
|
+
# ]
|
542
|
+
# }
|
543
|
+
#
|
544
|
+
data = self.safe_list(message, 'data', [])
|
545
|
+
ticker = self.safe_dict(data, 0, {})
|
546
|
+
parsedTicker = self.parse_ws_bid_ask(ticker)
|
547
|
+
symbol = parsedTicker['symbol']
|
548
|
+
self.bidsasks[symbol] = parsedTicker
|
549
|
+
messageHash = 'bidask::' + symbol
|
550
|
+
client.resolve(parsedTicker, messageHash)
|
551
|
+
|
552
|
+
def parse_ws_bid_ask(self, ticker, market=None):
|
553
|
+
marketId = self.safe_string(ticker, 'instId')
|
554
|
+
market = self.safe_market(marketId, market)
|
555
|
+
symbol = self.safe_string(market, 'symbol')
|
556
|
+
timestamp = self.safe_integer(ticker, 'ts')
|
557
|
+
return self.safe_ticker({
|
558
|
+
'symbol': symbol,
|
559
|
+
'timestamp': timestamp,
|
560
|
+
'datetime': self.iso8601(timestamp),
|
561
|
+
'ask': self.safe_string(ticker, 'askPx'),
|
562
|
+
'askVolume': self.safe_string(ticker, 'askSz'),
|
563
|
+
'bid': self.safe_string(ticker, 'bidPx'),
|
564
|
+
'bidVolume': self.safe_string(ticker, 'bidSz'),
|
565
|
+
'info': ticker,
|
566
|
+
}, market)
|
447
567
|
|
448
568
|
async def watch_liquidations_for_symbols(self, symbols: List[str] = None, since: Int = None, limit: Int = None, params={}) -> List[Liquidation]:
|
449
569
|
"""
|
@@ -547,10 +667,24 @@ class okx(ccxt.async_support.okx):
|
|
547
667
|
await self.authenticate({'access': 'business' if isStop else 'private'})
|
548
668
|
symbols = self.market_symbols(symbols, None, True, True)
|
549
669
|
messageHash = 'myLiquidations'
|
670
|
+
messageHashes = []
|
550
671
|
if symbols is not None:
|
551
|
-
|
672
|
+
for i in range(0, len(symbols)):
|
673
|
+
symbol = symbols[i]
|
674
|
+
messageHashes.append(messageHash + '::' + symbol)
|
675
|
+
else:
|
676
|
+
messageHashes.append(messageHash)
|
552
677
|
channel = 'balance_and_position'
|
553
|
-
|
678
|
+
request: dict = {
|
679
|
+
'op': 'subscribe',
|
680
|
+
'args': [
|
681
|
+
{
|
682
|
+
'channel': channel,
|
683
|
+
},
|
684
|
+
],
|
685
|
+
}
|
686
|
+
url = self.get_url(channel, 'private')
|
687
|
+
newLiquidations = await self.watch_multiple(url, messageHashes, self.deep_extend(request, params), messageHashes)
|
554
688
|
if self.newUpdates:
|
555
689
|
return newLiquidations
|
556
690
|
return self.filter_by_symbols_since_limit(self.liquidations, symbols, since, limit, True)
|
@@ -710,6 +844,17 @@ class okx(ccxt.async_support.okx):
|
|
710
844
|
limit = ohlcv.getLimit(symbol, limit)
|
711
845
|
return self.filter_by_since_limit(ohlcv, since, limit, 0, True)
|
712
846
|
|
847
|
+
async def un_watch_ohlcv(self, symbol: str, timeframe='1m', params={}) -> Any:
|
848
|
+
"""
|
849
|
+
watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
850
|
+
:param str symbol: unified symbol of the market to fetch OHLCV data for
|
851
|
+
:param str timeframe: the length of time each candle represents
|
852
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
853
|
+
:returns int[][]: A list of candles ordered, open, high, low, close, volume
|
854
|
+
"""
|
855
|
+
await self.load_markets()
|
856
|
+
return await self.un_watch_ohlcv_for_symbols([[symbol, timeframe]], params)
|
857
|
+
|
713
858
|
async def watch_ohlcv_for_symbols(self, symbolsAndTimeframes: List[List[str]], since: Int = None, limit: Int = None, params={}):
|
714
859
|
"""
|
715
860
|
watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
@@ -749,6 +894,39 @@ class okx(ccxt.async_support.okx):
|
|
749
894
|
filtered = self.filter_by_since_limit(candles, since, limit, 0, True)
|
750
895
|
return self.create_ohlcv_object(symbol, timeframe, filtered)
|
751
896
|
|
897
|
+
async def un_watch_ohlcv_for_symbols(self, symbolsAndTimeframes: List[List[str]], params={}):
|
898
|
+
"""
|
899
|
+
unWatches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
900
|
+
:param str[][] symbolsAndTimeframes: array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
|
901
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
902
|
+
:returns int[][]: A list of candles ordered, open, high, low, close, volume
|
903
|
+
"""
|
904
|
+
symbolsLength = len(symbolsAndTimeframes)
|
905
|
+
if symbolsLength == 0 or not isinstance(symbolsAndTimeframes[0], list):
|
906
|
+
raise ArgumentsRequired(self.id + " watchOHLCVForSymbols() requires a an array of symbols and timeframes, like [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]")
|
907
|
+
await self.load_markets()
|
908
|
+
topics = []
|
909
|
+
messageHashes = []
|
910
|
+
for i in range(0, len(symbolsAndTimeframes)):
|
911
|
+
symbolAndTimeframe = symbolsAndTimeframes[i]
|
912
|
+
sym = symbolAndTimeframe[0]
|
913
|
+
tf = symbolAndTimeframe[1]
|
914
|
+
marketId = self.market_id(sym)
|
915
|
+
interval = self.safe_string(self.timeframes, tf, tf)
|
916
|
+
channel = 'candle' + interval
|
917
|
+
topic: dict = {
|
918
|
+
'channel': channel,
|
919
|
+
'instId': marketId,
|
920
|
+
}
|
921
|
+
topics.append(topic)
|
922
|
+
messageHashes.append('unsubscribe:multi:' + channel + ':' + sym)
|
923
|
+
request: dict = {
|
924
|
+
'op': 'unsubscribe',
|
925
|
+
'args': topics,
|
926
|
+
}
|
927
|
+
url = self.get_url('candle', 'public')
|
928
|
+
return await self.watch_multiple(url, messageHashes, request, messageHashes)
|
929
|
+
|
752
930
|
def handle_ohlcv(self, client: Client, message):
|
753
931
|
#
|
754
932
|
# {
|
@@ -1403,6 +1581,9 @@ class okx(ccxt.async_support.okx):
|
|
1403
1581
|
# }
|
1404
1582
|
#
|
1405
1583
|
arg = self.safe_value(message, 'arg', {})
|
1584
|
+
marketId = self.safe_string(arg, 'instId')
|
1585
|
+
market = self.safe_market(marketId, None, '-')
|
1586
|
+
symbol = market['symbol']
|
1406
1587
|
channel = self.safe_string(arg, 'channel', '')
|
1407
1588
|
data = self.safe_value(message, 'data', [])
|
1408
1589
|
if self.positions is None:
|
@@ -1420,16 +1601,10 @@ class okx(ccxt.async_support.okx):
|
|
1420
1601
|
newPositions.append(shortPosition)
|
1421
1602
|
newPositions.append(position)
|
1422
1603
|
cache.append(position)
|
1423
|
-
|
1424
|
-
|
1425
|
-
messageHash =
|
1426
|
-
|
1427
|
-
symbolsString = parts[1]
|
1428
|
-
symbols = symbolsString.split(',')
|
1429
|
-
positions = self.filter_by_array(newPositions, 'symbol', symbols, False)
|
1430
|
-
if not self.is_empty(positions):
|
1431
|
-
client.resolve(positions, messageHash)
|
1432
|
-
client.resolve(newPositions, channel)
|
1604
|
+
messageHash = channel
|
1605
|
+
if symbol is not None:
|
1606
|
+
messageHash = channel + '::' + symbol
|
1607
|
+
client.resolve(newPositions, messageHash)
|
1433
1608
|
|
1434
1609
|
async def watch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
1435
1610
|
"""
|
@@ -2008,6 +2183,34 @@ class okx(ccxt.async_support.okx):
|
|
2008
2183
|
client.reject(error, subMessageHash)
|
2009
2184
|
client.resolve(True, messageHash)
|
2010
2185
|
|
2186
|
+
def handle_unsubscription_ohlcv(self, client: Client, symbol: str, channel: str):
|
2187
|
+
tf = channel.replace('candle', '')
|
2188
|
+
timeframe = self.find_timeframe(tf)
|
2189
|
+
subMessageHash = 'multi:' + channel + ':' + symbol
|
2190
|
+
messageHash = 'unsubscribe:' + subMessageHash
|
2191
|
+
if subMessageHash in client.subscriptions:
|
2192
|
+
del client.subscriptions[subMessageHash]
|
2193
|
+
if messageHash in client.subscriptions:
|
2194
|
+
del client.subscriptions[messageHash]
|
2195
|
+
if timeframe in self.ohlcvs[symbol]:
|
2196
|
+
del self.ohlcvs[symbol][timeframe]
|
2197
|
+
error = UnsubscribeError(self.id + ' ' + subMessageHash)
|
2198
|
+
client.reject(error, subMessageHash)
|
2199
|
+
client.resolve(True, messageHash)
|
2200
|
+
|
2201
|
+
def handle_unsubscription_ticker(self, client: Client, symbol: str, channel):
|
2202
|
+
subMessageHash = channel + '::' + symbol
|
2203
|
+
messageHash = 'unsubscribe:ticker:' + symbol
|
2204
|
+
if subMessageHash in client.subscriptions:
|
2205
|
+
del client.subscriptions[subMessageHash]
|
2206
|
+
if messageHash in client.subscriptions:
|
2207
|
+
del client.subscriptions[messageHash]
|
2208
|
+
if symbol in self.tickers:
|
2209
|
+
del self.tickers[symbol]
|
2210
|
+
error = UnsubscribeError(self.id + ' ' + subMessageHash)
|
2211
|
+
client.reject(error, subMessageHash)
|
2212
|
+
client.resolve(True, messageHash)
|
2213
|
+
|
2011
2214
|
def handle_unsubscription(self, client: Client, message):
|
2012
2215
|
#
|
2013
2216
|
# {
|
@@ -2020,10 +2223,14 @@ class okx(ccxt.async_support.okx):
|
|
2020
2223
|
# }
|
2021
2224
|
# arg might be an array or list
|
2022
2225
|
arg = self.safe_dict(message, 'arg', {})
|
2023
|
-
channel = self.safe_string(arg, 'channel')
|
2226
|
+
channel = self.safe_string(arg, 'channel', '')
|
2024
2227
|
marketId = self.safe_string(arg, 'instId')
|
2025
2228
|
symbol = self.safe_symbol(marketId)
|
2026
2229
|
if channel == 'trades':
|
2027
2230
|
self.handle_un_subscription_trades(client, symbol)
|
2028
2231
|
elif channel.startswith('bbo') or channel.startswith('book'):
|
2029
2232
|
self.handle_unsubscription_order_book(client, symbol, channel)
|
2233
|
+
elif channel.find('tickers') > -1:
|
2234
|
+
self.handle_unsubscription_ticker(client, symbol, channel)
|
2235
|
+
elif channel.startswith('candle'):
|
2236
|
+
self.handle_unsubscription_ohlcv(client, symbol, channel)
|
ccxt/test/tests_async.py
CHANGED
@@ -920,6 +920,9 @@ class testMainClass(baseMainTestClass):
|
|
920
920
|
is_disabled = exchange.safe_bool(result, 'disabled', False)
|
921
921
|
if is_disabled:
|
922
922
|
continue
|
923
|
+
disabled_string = exchange.safe_string(result, 'disabled', '')
|
924
|
+
if disabled_string != '':
|
925
|
+
continue
|
923
926
|
is_disabled_c_sharp = exchange.safe_bool(result, 'disabledCS', False)
|
924
927
|
if is_disabled_c_sharp and (self.lang == 'C#'):
|
925
928
|
continue
|
ccxt/test/tests_sync.py
CHANGED
@@ -917,6 +917,9 @@ class testMainClass(baseMainTestClass):
|
|
917
917
|
is_disabled = exchange.safe_bool(result, 'disabled', False)
|
918
918
|
if is_disabled:
|
919
919
|
continue
|
920
|
+
disabled_string = exchange.safe_string(result, 'disabled', '')
|
921
|
+
if disabled_string != '':
|
922
|
+
continue
|
920
923
|
is_disabled_c_sharp = exchange.safe_bool(result, 'disabledCS', False)
|
921
924
|
if is_disabled_c_sharp and (self.lang == 'C#'):
|
922
925
|
continue
|