ccxt 4.2.92__py2.py3-none-any.whl → 4.2.94__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/binance.py +1 -0
- ccxt/abstract/binancecoinm.py +1 -0
- ccxt/abstract/binanceus.py +1 -0
- ccxt/abstract/binanceusdm.py +1 -0
- ccxt/async_support/__init__.py +1 -1
- ccxt/async_support/base/exchange.py +7 -1
- ccxt/async_support/binance.py +60 -2
- ccxt/async_support/bitget.py +135 -1
- ccxt/async_support/coinex.py +0 -27
- ccxt/async_support/digifinex.py +1 -45
- ccxt/async_support/okx.py +149 -1
- ccxt/async_support/probit.py +2 -3
- ccxt/async_support/woo.py +135 -1
- ccxt/base/exchange.py +42 -10
- ccxt/base/types.py +13 -0
- ccxt/binance.py +60 -2
- ccxt/bitget.py +135 -1
- ccxt/coinex.py +0 -27
- ccxt/digifinex.py +1 -45
- ccxt/okx.py +149 -1
- ccxt/pro/__init__.py +1 -1
- ccxt/pro/kraken.py +96 -18
- ccxt/pro/krakenfutures.py +104 -39
- ccxt/pro/kucoin.py +25 -16
- ccxt/probit.py +2 -3
- ccxt/woo.py +135 -1
- {ccxt-4.2.92.dist-info → ccxt-4.2.94.dist-info}/METADATA +4 -4
- {ccxt-4.2.92.dist-info → ccxt-4.2.94.dist-info}/RECORD +31 -31
- {ccxt-4.2.92.dist-info → ccxt-4.2.94.dist-info}/WHEEL +0 -0
- {ccxt-4.2.92.dist-info → ccxt-4.2.94.dist-info}/top_level.txt +0 -0
ccxt/okx.py
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
from ccxt.base.exchange import Exchange
|
7
7
|
from ccxt.abstract.okx import ImplicitAPI
|
8
8
|
import hashlib
|
9
|
-
from ccxt.base.types import Account, Balances, Currencies, Currency, Greeks, Int, Leverage, MarginModification, Market, MarketInterface, Num, Option, OptionChain, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFeeInterface, Transaction, TransferEntry
|
9
|
+
from ccxt.base.types import Account, Balances, Conversion, Currencies, Currency, Greeks, Int, Leverage, MarginModification, Market, MarketInterface, Num, Option, OptionChain, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFeeInterface, Transaction, TransferEntry
|
10
10
|
from typing import List
|
11
11
|
from ccxt.base.errors import ExchangeError
|
12
12
|
from ccxt.base.errors import PermissionDenied
|
@@ -82,6 +82,8 @@ class okx(Exchange, ImplicitAPI):
|
|
82
82
|
'fetchCanceledOrders': True,
|
83
83
|
'fetchClosedOrder': None,
|
84
84
|
'fetchClosedOrders': True,
|
85
|
+
'fetchConvertCurrencies': True,
|
86
|
+
'fetchConvertQuote': True,
|
85
87
|
'fetchCrossBorrowRate': True,
|
86
88
|
'fetchCrossBorrowRates': True,
|
87
89
|
'fetchCurrencies': True,
|
@@ -7097,6 +7099,152 @@ class okx(Exchange, ImplicitAPI):
|
|
7097
7099
|
'quoteVolume': None,
|
7098
7100
|
}
|
7099
7101
|
|
7102
|
+
def fetch_convert_quote(self, fromCode: str, toCode: str, amount: Num = None, params={}) -> Conversion:
|
7103
|
+
"""
|
7104
|
+
fetch a quote for converting from one currency to another
|
7105
|
+
:see: https://www.okx.com/docs-v5/en/#funding-account-rest-api-estimate-quote
|
7106
|
+
:param str fromCode: the currency that you want to sell and convert from
|
7107
|
+
:param str toCode: the currency that you want to buy and convert into
|
7108
|
+
:param float [amount]: how much you want to trade in units of the from currency
|
7109
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
7110
|
+
:returns dict: a `conversion structure <https://docs.ccxt.com/#/?id=conversion-structure>`
|
7111
|
+
"""
|
7112
|
+
self.load_markets()
|
7113
|
+
request = {
|
7114
|
+
'baseCcy': fromCode.upper(),
|
7115
|
+
'quoteCcy': toCode.upper(),
|
7116
|
+
'rfqSzCcy': fromCode.upper(),
|
7117
|
+
'rfqSz': self.number_to_string(amount),
|
7118
|
+
'side': 'sell',
|
7119
|
+
}
|
7120
|
+
response = self.privatePostAssetConvertEstimateQuote(self.extend(request, params))
|
7121
|
+
#
|
7122
|
+
# {
|
7123
|
+
# "code": "0",
|
7124
|
+
# "data": [
|
7125
|
+
# {
|
7126
|
+
# "baseCcy": "ETH",
|
7127
|
+
# "baseSz": "0.01023052",
|
7128
|
+
# "clQReqId": "",
|
7129
|
+
# "cnvtPx": "2932.40104429",
|
7130
|
+
# "origRfqSz": "30",
|
7131
|
+
# "quoteCcy": "USDT",
|
7132
|
+
# "quoteId": "quoterETH-USDT16461885104612381",
|
7133
|
+
# "quoteSz": "30",
|
7134
|
+
# "quoteTime": "1646188510461",
|
7135
|
+
# "rfqSz": "30",
|
7136
|
+
# "rfqSzCcy": "USDT",
|
7137
|
+
# "side": "buy",
|
7138
|
+
# "ttlMs": "10000"
|
7139
|
+
# }
|
7140
|
+
# ],
|
7141
|
+
# "msg": ""
|
7142
|
+
# }
|
7143
|
+
#
|
7144
|
+
data = self.safe_list(response, 'data', [])
|
7145
|
+
result = self.safe_dict(data, 0, {})
|
7146
|
+
fromCurrencyId = self.safe_string(result, 'baseCcy', fromCode)
|
7147
|
+
fromCurrency = self.currency(fromCurrencyId)
|
7148
|
+
toCurrencyId = self.safe_string(result, 'quoteCcy', toCode)
|
7149
|
+
toCurrency = self.currency(toCurrencyId)
|
7150
|
+
return self.parse_conversion(result, fromCurrency, toCurrency)
|
7151
|
+
|
7152
|
+
def parse_conversion(self, conversion, fromCurrency: Currency = None, toCurrency: Currency = None) -> Conversion:
|
7153
|
+
#
|
7154
|
+
# fetchConvertQuote
|
7155
|
+
#
|
7156
|
+
# {
|
7157
|
+
# "baseCcy": "ETH",
|
7158
|
+
# "baseSz": "0.01023052",
|
7159
|
+
# "clQReqId": "",
|
7160
|
+
# "cnvtPx": "2932.40104429",
|
7161
|
+
# "origRfqSz": "30",
|
7162
|
+
# "quoteCcy": "USDT",
|
7163
|
+
# "quoteId": "quoterETH-USDT16461885104612381",
|
7164
|
+
# "quoteSz": "30",
|
7165
|
+
# "quoteTime": "1646188510461",
|
7166
|
+
# "rfqSz": "30",
|
7167
|
+
# "rfqSzCcy": "USDT",
|
7168
|
+
# "side": "buy",
|
7169
|
+
# "ttlMs": "10000"
|
7170
|
+
# }
|
7171
|
+
#
|
7172
|
+
timestamp = self.safe_integer(conversion, 'quoteTime')
|
7173
|
+
fromCoin = self.safe_string(conversion, 'baseCcy')
|
7174
|
+
fromCode = self.safe_currency_code(fromCoin, fromCurrency)
|
7175
|
+
to = self.safe_string(conversion, 'quoteCcy')
|
7176
|
+
toCode = self.safe_currency_code(to, toCurrency)
|
7177
|
+
return {
|
7178
|
+
'info': conversion,
|
7179
|
+
'timestamp': timestamp,
|
7180
|
+
'datetime': self.iso8601(timestamp),
|
7181
|
+
'id': self.safe_string(conversion, 'clQReqId'),
|
7182
|
+
'fromCurrency': fromCode,
|
7183
|
+
'fromAmount': self.safe_number(conversion, 'baseSz'),
|
7184
|
+
'toCurrency': toCode,
|
7185
|
+
'toAmount': self.safe_number(conversion, 'quoteSz'),
|
7186
|
+
'price': self.safe_number(conversion, 'cnvtPx'),
|
7187
|
+
'fee': None,
|
7188
|
+
}
|
7189
|
+
|
7190
|
+
def fetch_convert_currencies(self, params={}) -> Currencies:
|
7191
|
+
"""
|
7192
|
+
fetches all available currencies that can be converted
|
7193
|
+
:see: https://www.okx.com/docs-v5/en/#funding-account-rest-api-get-convert-currencies
|
7194
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
7195
|
+
:returns dict: an associative dictionary of currencies
|
7196
|
+
"""
|
7197
|
+
self.load_markets()
|
7198
|
+
response = self.privateGetAssetConvertCurrencies(params)
|
7199
|
+
#
|
7200
|
+
# {
|
7201
|
+
# "code": "0",
|
7202
|
+
# "data": [
|
7203
|
+
# {
|
7204
|
+
# "ccy": "BTC",
|
7205
|
+
# "max": "",
|
7206
|
+
# "min": ""
|
7207
|
+
# },
|
7208
|
+
# ],
|
7209
|
+
# "msg": ""
|
7210
|
+
# }
|
7211
|
+
#
|
7212
|
+
result = {}
|
7213
|
+
data = self.safe_list(response, 'data', [])
|
7214
|
+
for i in range(0, len(data)):
|
7215
|
+
entry = data[i]
|
7216
|
+
id = self.safe_string(entry, 'ccy')
|
7217
|
+
code = self.safe_currency_code(id)
|
7218
|
+
result[code] = {
|
7219
|
+
'info': entry,
|
7220
|
+
'id': id,
|
7221
|
+
'code': code,
|
7222
|
+
'networks': None,
|
7223
|
+
'type': None,
|
7224
|
+
'name': None,
|
7225
|
+
'active': None,
|
7226
|
+
'deposit': None,
|
7227
|
+
'withdraw': None,
|
7228
|
+
'fee': None,
|
7229
|
+
'precision': None,
|
7230
|
+
'limits': {
|
7231
|
+
'amount': {
|
7232
|
+
'min': self.safe_number(entry, 'min'),
|
7233
|
+
'max': self.safe_number(entry, 'max'),
|
7234
|
+
},
|
7235
|
+
'withdraw': {
|
7236
|
+
'min': None,
|
7237
|
+
'max': None,
|
7238
|
+
},
|
7239
|
+
'deposit': {
|
7240
|
+
'min': None,
|
7241
|
+
'max': None,
|
7242
|
+
},
|
7243
|
+
},
|
7244
|
+
'created': None,
|
7245
|
+
}
|
7246
|
+
return result
|
7247
|
+
|
7100
7248
|
def handle_errors(self, httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody):
|
7101
7249
|
if not response:
|
7102
7250
|
return None # fallback to default error handler
|
ccxt/pro/__init__.py
CHANGED
ccxt/pro/kraken.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, ArrayCacheByTimestamp
|
8
|
-
from ccxt.base.types import Int, Num, Order, OrderBook, OrderSide, OrderType, Str, Ticker, Trade
|
8
|
+
from ccxt.base.types import Int, Num, Order, OrderBook, OrderSide, OrderType, 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
|
@@ -34,10 +34,12 @@ class kraken(ccxt.async_support.kraken):
|
|
34
34
|
'watchMyTrades': True,
|
35
35
|
'watchOHLCV': True,
|
36
36
|
'watchOrderBook': True,
|
37
|
+
'watchOrderBookForSymbols': True,
|
37
38
|
'watchOrders': True,
|
38
39
|
'watchTicker': True,
|
39
|
-
'watchTickers':
|
40
|
+
'watchTickers': True,
|
40
41
|
'watchTrades': True,
|
42
|
+
'watchTradesForSymbols': True,
|
41
43
|
'createOrderWs': True,
|
42
44
|
'editOrderWs': True,
|
43
45
|
'cancelOrderWs': True,
|
@@ -317,10 +319,9 @@ class kraken(ccxt.async_support.kraken):
|
|
317
319
|
# ]
|
318
320
|
#
|
319
321
|
wsName = message[3]
|
320
|
-
name = 'ticker'
|
321
|
-
messageHash = name + ':' + wsName
|
322
322
|
market = self.safe_value(self.options['marketsByWsName'], wsName)
|
323
323
|
symbol = market['symbol']
|
324
|
+
messageHash = self.get_message_hash('ticker', None, symbol)
|
324
325
|
ticker = message[1]
|
325
326
|
vwap = self.safe_string(ticker['p'], 0)
|
326
327
|
quoteVolume = None
|
@@ -350,9 +351,6 @@ class kraken(ccxt.async_support.kraken):
|
|
350
351
|
'quoteVolume': quoteVolume,
|
351
352
|
'info': ticker,
|
352
353
|
})
|
353
|
-
# todo add support for multiple tickers(may be tricky)
|
354
|
-
# kraken confirms multi-pair subscriptions separately one by one
|
355
|
-
# trigger correct watchTickers calls upon receiving any of symbols
|
356
354
|
self.tickers[symbol] = result
|
357
355
|
client.resolve(result, messageHash)
|
358
356
|
|
@@ -370,9 +368,9 @@ class kraken(ccxt.async_support.kraken):
|
|
370
368
|
#
|
371
369
|
wsName = self.safe_string(message, 3)
|
372
370
|
name = self.safe_string(message, 2)
|
373
|
-
messageHash = name + ':' + wsName
|
374
371
|
market = self.safe_value(self.options['marketsByWsName'], wsName)
|
375
372
|
symbol = market['symbol']
|
373
|
+
messageHash = self.get_message_hash(name, None, symbol)
|
376
374
|
stored = self.safe_value(self.trades, symbol)
|
377
375
|
if stored is None:
|
378
376
|
limit = self.safe_integer(self.options, 'tradesLimit', 1000)
|
@@ -467,43 +465,85 @@ class kraken(ccxt.async_support.kraken):
|
|
467
465
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
468
466
|
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
469
467
|
"""
|
470
|
-
|
468
|
+
await self.load_markets()
|
469
|
+
symbol = self.symbol(symbol)
|
470
|
+
tickers = await self.watch_tickers([symbol], params)
|
471
|
+
return tickers[symbol]
|
472
|
+
|
473
|
+
async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
|
474
|
+
"""
|
475
|
+
watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
|
476
|
+
:param str symbol: unified symbol of the market to fetch the ticker for
|
477
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
478
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
479
|
+
"""
|
480
|
+
await self.load_markets()
|
481
|
+
symbols = self.market_symbols(symbols, None, False)
|
482
|
+
ticker = await self.watch_multi_helper('ticker', 'ticker', symbols, None, params)
|
483
|
+
if self.newUpdates:
|
484
|
+
result = {}
|
485
|
+
result[ticker['symbol']] = ticker
|
486
|
+
return result
|
487
|
+
return self.filter_by_array(self.tickers, 'symbol', symbols)
|
471
488
|
|
472
489
|
async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
473
490
|
"""
|
474
491
|
get the list of most recent trades for a particular symbol
|
492
|
+
:see: https://docs.kraken.com/websockets/#message-trade
|
475
493
|
:param str symbol: unified symbol of the market to fetch trades for
|
476
494
|
:param int [since]: timestamp in ms of the earliest trade to fetch
|
477
495
|
:param int [limit]: the maximum amount of trades to fetch
|
478
496
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
479
497
|
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
|
480
498
|
"""
|
481
|
-
await self.
|
482
|
-
|
483
|
-
|
484
|
-
|
499
|
+
return await self.watch_trades_for_symbols([symbol], since, limit, params)
|
500
|
+
|
501
|
+
async def watch_trades_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
502
|
+
"""
|
503
|
+
:see: https://docs.kraken.com/websockets/#message-trade
|
504
|
+
get the list of most recent trades for a list of symbols
|
505
|
+
:param str[] symbols: unified symbol of the market to fetch trades for
|
506
|
+
:param int [since]: timestamp in ms of the earliest trade to fetch
|
507
|
+
:param int [limit]: the maximum amount of trades to fetch
|
508
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
509
|
+
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
|
510
|
+
"""
|
511
|
+
trades = await self.watch_multi_helper('trade', 'trade', symbols, None, params)
|
485
512
|
if self.newUpdates:
|
486
|
-
|
513
|
+
first = self.safe_list(trades, 0)
|
514
|
+
tradeSymbol = self.safe_string(first, 'symbol')
|
515
|
+
limit = trades.getLimit(tradeSymbol, limit)
|
487
516
|
return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
|
488
517
|
|
489
518
|
async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
|
490
519
|
"""
|
491
520
|
watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
|
521
|
+
:see: https://docs.kraken.com/websockets/#message-book
|
492
522
|
:param str symbol: unified symbol of the market to fetch the order book for
|
493
523
|
:param int [limit]: the maximum amount of order book entries to return
|
494
524
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
495
525
|
:returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
|
496
526
|
"""
|
497
|
-
|
527
|
+
return await self.watch_order_book_for_symbols([symbol], limit, params)
|
528
|
+
|
529
|
+
async def watch_order_book_for_symbols(self, symbols: List[str], limit: Int = None, params={}) -> OrderBook:
|
530
|
+
"""
|
531
|
+
watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
|
532
|
+
:see: https://docs.kraken.com/websockets/#message-book
|
533
|
+
:param str[] symbols: unified array of symbols
|
534
|
+
:param int [limit]: the maximum amount of order book entries to return
|
535
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
536
|
+
:returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
|
537
|
+
"""
|
498
538
|
request = {}
|
499
539
|
if limit is not None:
|
500
|
-
if (limit
|
540
|
+
if self.in_array(limit, [10, 25, 100, 500, 1000]):
|
501
541
|
request['subscription'] = {
|
502
542
|
'depth': limit, # default 10, valid options 10, 25, 100, 500, 1000
|
503
543
|
}
|
504
544
|
else:
|
505
545
|
raise NotSupported(self.id + ' watchOrderBook accepts limit values of 10, 25, 100, 500 and 1000 only')
|
506
|
-
orderbook = await self.
|
546
|
+
orderbook = await self.watch_multi_helper('orderbook', 'book', symbols, {'limit': limit}, self.extend(request, params))
|
507
547
|
return orderbook.limit()
|
508
548
|
|
509
549
|
async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
|
@@ -625,7 +665,7 @@ class kraken(ccxt.async_support.kraken):
|
|
625
665
|
market = self.safe_value(self.options['marketsByWsName'], wsName)
|
626
666
|
symbol = market['symbol']
|
627
667
|
timestamp = None
|
628
|
-
messageHash = '
|
668
|
+
messageHash = self.get_message_hash('orderbook', None, symbol)
|
629
669
|
# if self is a snapshot
|
630
670
|
if 'as' in message[1]:
|
631
671
|
# todo get depth from marketsByWsName
|
@@ -695,6 +735,7 @@ class kraken(ccxt.async_support.kraken):
|
|
695
735
|
if localChecksum != c:
|
696
736
|
error = InvalidNonce(self.id + ' invalid checksum')
|
697
737
|
client.reject(error, messageHash)
|
738
|
+
return
|
698
739
|
orderbook['symbol'] = symbol
|
699
740
|
orderbook['timestamp'] = timestamp
|
700
741
|
orderbook['datetime'] = self.iso8601(timestamp)
|
@@ -1179,6 +1220,43 @@ class kraken(ccxt.async_support.kraken):
|
|
1179
1220
|
'trades': trades,
|
1180
1221
|
})
|
1181
1222
|
|
1223
|
+
async def watch_multi_helper(self, unifiedName: str, channelName: str, symbols: Strings = None, subscriptionArgs=None, params={}):
|
1224
|
+
await self.load_markets()
|
1225
|
+
# symbols are required
|
1226
|
+
symbols = self.market_symbols(symbols, None, False, True, False)
|
1227
|
+
messageHashes = []
|
1228
|
+
for i in range(0, len(symbols)):
|
1229
|
+
messageHashes.append(self.get_message_hash(unifiedName, None, self.symbol(symbols[i])))
|
1230
|
+
# for WS subscriptions, we can't use .market_ids(symbols), instead a custom is field needed
|
1231
|
+
markets = self.markets_for_symbols(symbols)
|
1232
|
+
wsMarketIds = []
|
1233
|
+
for i in range(0, len(markets)):
|
1234
|
+
wsMarketId = self.safe_string(markets[i]['info'], 'wsname')
|
1235
|
+
wsMarketIds.append(wsMarketId)
|
1236
|
+
request = {
|
1237
|
+
'event': 'subscribe',
|
1238
|
+
'reqid': self.request_id(),
|
1239
|
+
'pair': wsMarketIds,
|
1240
|
+
'subscription': {
|
1241
|
+
'name': channelName,
|
1242
|
+
},
|
1243
|
+
}
|
1244
|
+
url = self.urls['api']['ws']['public']
|
1245
|
+
return await self.watch_multiple(url, messageHashes, self.extend(request, params), messageHashes, subscriptionArgs)
|
1246
|
+
|
1247
|
+
def get_message_hash(self, unifiedElementName: str, subChannelName: Str = None, symbol: Str = None):
|
1248
|
+
# unifiedElementName can be : orderbook, trade, ticker, bidask ...
|
1249
|
+
# subChannelName only applies to channel that needs specific variation(i.e. depth_50, depth_100..) to be selected
|
1250
|
+
withSymbol = symbol is not None
|
1251
|
+
messageHash = unifiedElementName
|
1252
|
+
if not withSymbol:
|
1253
|
+
messageHash += 's'
|
1254
|
+
else:
|
1255
|
+
messageHash += '@' + symbol
|
1256
|
+
if subChannelName is not None:
|
1257
|
+
messageHash += '#' + subChannelName
|
1258
|
+
return messageHash
|
1259
|
+
|
1182
1260
|
def handle_subscription_status(self, client: Client, message):
|
1183
1261
|
#
|
1184
1262
|
# public
|
ccxt/pro/krakenfutures.py
CHANGED
@@ -32,9 +32,12 @@ class krakenfutures(ccxt.async_support.krakenfutures):
|
|
32
32
|
'fetchTradesWs': False,
|
33
33
|
'watchOHLCV': False,
|
34
34
|
'watchOrderBook': True,
|
35
|
+
'watchOrderBookForSymbols': True,
|
35
36
|
'watchTicker': True,
|
36
37
|
'watchTickers': True,
|
38
|
+
'watchBidsAsks': True,
|
37
39
|
'watchTrades': True,
|
40
|
+
'watchTradesForSymbols': True,
|
38
41
|
'watchBalance': True,
|
39
42
|
# 'watchStatus': True, # https://docs.futures.kraken.com/#websocket-api-public-feeds-heartbeat
|
40
43
|
'watchOrders': True,
|
@@ -55,12 +58,6 @@ class krakenfutures(ccxt.async_support.krakenfutures):
|
|
55
58
|
'OHLCVLimit': 1000,
|
56
59
|
'connectionLimit': 100, # https://docs.futures.kraken.com/#websocket-api-websocket-api-introduction-subscriptions-limits
|
57
60
|
'requestLimit': 100, # per second
|
58
|
-
'watchTicker': {
|
59
|
-
'method': 'ticker', # or ticker_lite
|
60
|
-
},
|
61
|
-
'watchTickers': {
|
62
|
-
'method': 'ticker', # or ticker_lite
|
63
|
-
},
|
64
61
|
'fetchBalance': {
|
65
62
|
'type': None,
|
66
63
|
},
|
@@ -96,6 +93,18 @@ class krakenfutures(ccxt.async_support.krakenfutures):
|
|
96
93
|
client.subscriptions[messageHash] = future
|
97
94
|
return future
|
98
95
|
|
96
|
+
async def watch_order_book_for_symbols(self, symbols: List[str], limit: Int = None, params={}) -> OrderBook:
|
97
|
+
"""
|
98
|
+
watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
|
99
|
+
:see: https://docs.futures.kraken.com/#websocket-api-public-feeds-challenge
|
100
|
+
:param str[] symbols: unified array of symbols
|
101
|
+
:param int [limit]: the maximum amount of order book entries to return
|
102
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
103
|
+
:returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
|
104
|
+
"""
|
105
|
+
orderbook = await self.watch_multi_helper('orderbook', 'book', symbols, {'limit': limit}, params)
|
106
|
+
return orderbook.limit()
|
107
|
+
|
99
108
|
async def subscribe_public(self, name: str, symbols: List[str], params={}):
|
100
109
|
"""
|
101
110
|
* @ignore
|
@@ -156,31 +165,43 @@ class krakenfutures(ccxt.async_support.krakenfutures):
|
|
156
165
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
157
166
|
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
158
167
|
"""
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
return await self.subscribe_public(name, [symbol], params)
|
168
|
+
await self.load_markets()
|
169
|
+
symbol = self.symbol(symbol)
|
170
|
+
tickers = await self.watch_tickers([symbol], params)
|
171
|
+
return tickers[symbol]
|
164
172
|
|
165
173
|
async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
|
166
174
|
"""
|
167
175
|
watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
|
168
|
-
:see: https://docs.futures.kraken.com/#websocket-api-public-feeds-ticker
|
176
|
+
:see: https://docs.futures.kraken.com/#websocket-api-public-feeds-ticker
|
169
177
|
:param str symbol: unified symbol of the market to fetch the ticker for
|
170
178
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
171
179
|
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
172
180
|
"""
|
173
|
-
|
174
|
-
name = self.safe_string_2(params, 'method', 'watchTickerMethod', method)
|
175
|
-
params = self.omit(params, ['watchTickerMethod', 'method'])
|
181
|
+
await self.load_markets()
|
176
182
|
symbols = self.market_symbols(symbols, None, False)
|
177
|
-
ticker = await self.
|
183
|
+
ticker = await self.watch_multi_helper('ticker', 'ticker', symbols, None, params)
|
178
184
|
if self.newUpdates:
|
179
|
-
|
180
|
-
|
181
|
-
return
|
185
|
+
result = {}
|
186
|
+
result[ticker['symbol']] = ticker
|
187
|
+
return result
|
182
188
|
return self.filter_by_array(self.tickers, 'symbol', symbols)
|
183
189
|
|
190
|
+
async def watch_bids_asks(self, symbols: Strings = None, params={}) -> Tickers:
|
191
|
+
"""
|
192
|
+
:see: https://docs.futures.kraken.com/#websocket-api-public-feeds-ticker-lite
|
193
|
+
watches best bid & ask for symbols
|
194
|
+
:param str[] symbols: unified symbol of the market to fetch the ticker for
|
195
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
196
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
197
|
+
"""
|
198
|
+
ticker = await self.watch_multi_helper('bidask', 'ticker_lite', symbols, None, params)
|
199
|
+
if self.newUpdates:
|
200
|
+
result = {}
|
201
|
+
result[ticker['symbol']] = ticker
|
202
|
+
return result
|
203
|
+
return self.filter_by_array(self.bidsasks, 'symbol', symbols)
|
204
|
+
|
184
205
|
async def watch_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
185
206
|
"""
|
186
207
|
get the list of most recent trades for a particular symbol
|
@@ -191,11 +212,23 @@ class krakenfutures(ccxt.async_support.krakenfutures):
|
|
191
212
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
192
213
|
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
|
193
214
|
"""
|
194
|
-
await self.
|
195
|
-
|
196
|
-
|
215
|
+
return await self.watch_trades_for_symbols([symbol], since, limit, params)
|
216
|
+
|
217
|
+
async def watch_trades_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
218
|
+
"""
|
219
|
+
:see: https://docs.futures.kraken.com/#websocket-api-public-feeds-trade
|
220
|
+
get the list of most recent trades for a list of symbols
|
221
|
+
:param str[] symbols: unified symbol of the market to fetch trades for
|
222
|
+
:param int [since]: timestamp in ms of the earliest trade to fetch
|
223
|
+
:param int [limit]: the maximum amount of trades to fetch
|
224
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
225
|
+
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
|
226
|
+
"""
|
227
|
+
trades = await self.watch_multi_helper('trade', 'trade', symbols, None, params)
|
197
228
|
if self.newUpdates:
|
198
|
-
|
229
|
+
first = self.safe_list(trades, 0)
|
230
|
+
tradeSymbol = self.safe_string(first, 'symbol')
|
231
|
+
limit = trades.getLimit(tradeSymbol, limit)
|
199
232
|
return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
|
200
233
|
|
201
234
|
async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
|
@@ -207,8 +240,7 @@ class krakenfutures(ccxt.async_support.krakenfutures):
|
|
207
240
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
208
241
|
:returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
|
209
242
|
"""
|
210
|
-
|
211
|
-
return orderbook.limit()
|
243
|
+
return await self.watch_order_book_for_symbols([symbol], limit, params)
|
212
244
|
|
213
245
|
async def watch_positions(self, symbols: Strings = None, since: Int = None, limit: Int = None, params={}) -> List[Position]:
|
214
246
|
"""
|
@@ -436,7 +468,7 @@ class krakenfutures(ccxt.async_support.krakenfutures):
|
|
436
468
|
if marketId is not None:
|
437
469
|
market = self.market(marketId)
|
438
470
|
symbol = market['symbol']
|
439
|
-
messageHash = 'trade
|
471
|
+
messageHash = self.get_message_hash('trade', None, symbol)
|
440
472
|
if self.safe_list(self.trades, symbol) is None:
|
441
473
|
tradesLimit = self.safe_integer(self.options, 'tradesLimit', 1000)
|
442
474
|
self.trades[symbol] = ArrayCache(tradesLimit)
|
@@ -453,7 +485,6 @@ class krakenfutures(ccxt.async_support.krakenfutures):
|
|
453
485
|
trade = self.parse_ws_trade(message)
|
454
486
|
tradesArray.append(trade)
|
455
487
|
client.resolve(tradesArray, messageHash)
|
456
|
-
return message
|
457
488
|
|
458
489
|
def parse_ws_trade(self, trade, market=None):
|
459
490
|
#
|
@@ -859,7 +890,15 @@ class krakenfutures(ccxt.async_support.krakenfutures):
|
|
859
890
|
# "volumeQuote": 19628180
|
860
891
|
# }
|
861
892
|
#
|
862
|
-
|
893
|
+
marketId = self.safe_string(message, 'product_id')
|
894
|
+
if marketId is not None:
|
895
|
+
ticker = self.parse_ws_ticker(message)
|
896
|
+
symbol = ticker['symbol']
|
897
|
+
self.tickers[symbol] = ticker
|
898
|
+
messageHash = self.get_message_hash('ticker', None, symbol)
|
899
|
+
client.resolve(ticker, messageHash)
|
900
|
+
|
901
|
+
def handle_bid_ask(self, client: Client, message):
|
863
902
|
#
|
864
903
|
# {
|
865
904
|
# "feed": "ticker_lite",
|
@@ -877,15 +916,12 @@ class krakenfutures(ccxt.async_support.krakenfutures):
|
|
877
916
|
# }
|
878
917
|
#
|
879
918
|
marketId = self.safe_string(message, 'product_id')
|
880
|
-
feed = self.safe_string(message, 'feed')
|
881
919
|
if marketId is not None:
|
882
920
|
ticker = self.parse_ws_ticker(message)
|
883
921
|
symbol = ticker['symbol']
|
884
|
-
self.
|
885
|
-
messageHash =
|
922
|
+
self.bidsasks[symbol] = ticker
|
923
|
+
messageHash = self.get_message_hash('bidask', None, symbol)
|
886
924
|
client.resolve(ticker, messageHash)
|
887
|
-
client.resolve(self.tickers, feed)
|
888
|
-
return message
|
889
925
|
|
890
926
|
def parse_ws_ticker(self, ticker, market=None):
|
891
927
|
#
|
@@ -997,14 +1033,14 @@ class krakenfutures(ccxt.async_support.krakenfutures):
|
|
997
1033
|
marketId = self.safe_string(message, 'product_id')
|
998
1034
|
market = self.safe_market(marketId)
|
999
1035
|
symbol = market['symbol']
|
1000
|
-
messageHash = '
|
1001
|
-
subscription = self.
|
1036
|
+
messageHash = self.get_message_hash('orderbook', None, symbol)
|
1037
|
+
subscription = self.safe_dict(client.subscriptions, messageHash, {})
|
1002
1038
|
limit = self.safe_integer(subscription, 'limit')
|
1003
1039
|
timestamp = self.safe_integer(message, 'timestamp')
|
1004
1040
|
self.orderbooks[symbol] = self.order_book({}, limit)
|
1005
1041
|
orderbook = self.orderbooks[symbol]
|
1006
|
-
bids = self.
|
1007
|
-
asks = self.
|
1042
|
+
bids = self.safe_list(message, 'bids')
|
1043
|
+
asks = self.safe_list(message, 'asks')
|
1008
1044
|
for i in range(0, len(bids)):
|
1009
1045
|
bid = bids[i]
|
1010
1046
|
price = self.safe_number(bid, 'price')
|
@@ -1037,7 +1073,7 @@ class krakenfutures(ccxt.async_support.krakenfutures):
|
|
1037
1073
|
marketId = self.safe_string(message, 'product_id')
|
1038
1074
|
market = self.safe_market(marketId)
|
1039
1075
|
symbol = market['symbol']
|
1040
|
-
messageHash = '
|
1076
|
+
messageHash = self.get_message_hash('orderbook', None, symbol)
|
1041
1077
|
orderbook = self.orderbooks[symbol]
|
1042
1078
|
side = self.safe_string(message, 'side')
|
1043
1079
|
price = self.safe_number(message, 'price')
|
@@ -1353,6 +1389,35 @@ class krakenfutures(ccxt.async_support.krakenfutures):
|
|
1353
1389
|
},
|
1354
1390
|
})
|
1355
1391
|
|
1392
|
+
async def watch_multi_helper(self, unifiedName: str, channelName: str, symbols: Strings = None, subscriptionArgs=None, params={}):
|
1393
|
+
await self.load_markets()
|
1394
|
+
# symbols are required
|
1395
|
+
symbols = self.market_symbols(symbols, None, False, True, False)
|
1396
|
+
messageHashes = []
|
1397
|
+
for i in range(0, len(symbols)):
|
1398
|
+
messageHashes.append(self.get_message_hash(unifiedName, None, self.symbol(symbols[i])))
|
1399
|
+
marketIds = self.market_ids(symbols)
|
1400
|
+
request = {
|
1401
|
+
'event': 'subscribe',
|
1402
|
+
'feed': channelName,
|
1403
|
+
'product_ids': marketIds,
|
1404
|
+
}
|
1405
|
+
url = self.urls['api']['ws']
|
1406
|
+
return await self.watch_multiple(url, messageHashes, self.extend(request, params), messageHashes, subscriptionArgs)
|
1407
|
+
|
1408
|
+
def get_message_hash(self, unifiedElementName: str, subChannelName: Str = None, symbol: Str = None):
|
1409
|
+
# unifiedElementName can be : orderbook, trade, ticker, bidask ...
|
1410
|
+
# subChannelName only applies to channel that needs specific variation(i.e. depth_50, depth_100..) to be selected
|
1411
|
+
withSymbol = symbol is not None
|
1412
|
+
messageHash = unifiedElementName
|
1413
|
+
if not withSymbol:
|
1414
|
+
messageHash += 's'
|
1415
|
+
else:
|
1416
|
+
messageHash += ':' + symbol
|
1417
|
+
if subChannelName is not None:
|
1418
|
+
messageHash += '#' + subChannelName
|
1419
|
+
return messageHash
|
1420
|
+
|
1356
1421
|
def handle_error_message(self, client: Client, message):
|
1357
1422
|
#
|
1358
1423
|
# {
|
@@ -1378,10 +1443,10 @@ class krakenfutures(ccxt.async_support.krakenfutures):
|
|
1378
1443
|
feed = self.safe_string(message, 'feed')
|
1379
1444
|
methods = {
|
1380
1445
|
'ticker': self.handle_ticker,
|
1446
|
+
'ticker_lite': self.handle_bid_ask,
|
1381
1447
|
'trade': self.handle_trade,
|
1382
1448
|
'trade_snapshot': self.handle_trade,
|
1383
1449
|
# 'heartbeat': self.handleStatus,
|
1384
|
-
'ticker_lite': self.handle_ticker,
|
1385
1450
|
'book': self.handle_order_book,
|
1386
1451
|
'book_snapshot': self.handle_order_book_snapshot,
|
1387
1452
|
'open_orders_verbose': self.handle_order,
|