ccxt 4.4.90__py2.py3-none-any.whl → 4.4.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 -3
- ccxt/async_support/__init__.py +1 -3
- ccxt/async_support/base/exchange.py +6 -3
- ccxt/async_support/base/ws/client.py +173 -64
- ccxt/async_support/base/ws/future.py +23 -50
- ccxt/async_support/binance.py +1 -1
- ccxt/async_support/bitmex.py +2 -1
- ccxt/async_support/cex.py +61 -0
- ccxt/async_support/cryptocom.py +17 -2
- ccxt/async_support/cryptomus.py +1 -1
- ccxt/async_support/exmo.py +14 -7
- ccxt/async_support/gate.py +2 -2
- ccxt/async_support/hyperliquid.py +104 -53
- ccxt/async_support/kraken.py +26 -1
- ccxt/async_support/mexc.py +1 -0
- ccxt/async_support/modetrade.py +2 -2
- ccxt/async_support/paradex.py +1 -1
- ccxt/base/exchange.py +8 -5
- ccxt/binance.py +1 -1
- ccxt/bitmex.py +2 -1
- ccxt/cex.py +61 -0
- ccxt/cryptocom.py +17 -2
- ccxt/cryptomus.py +1 -1
- ccxt/exmo.py +13 -7
- ccxt/gate.py +2 -2
- ccxt/hyperliquid.py +104 -53
- ccxt/kraken.py +26 -1
- ccxt/mexc.py +1 -0
- ccxt/modetrade.py +2 -2
- ccxt/paradex.py +1 -1
- ccxt/pro/__init__.py +1 -1
- ccxt/pro/bitstamp.py +1 -1
- ccxt/pro/bybit.py +6 -136
- ccxt/pro/kraken.py +246 -258
- ccxt/pro/mexc.py +0 -1
- {ccxt-4.4.90.dist-info → ccxt-4.4.91.dist-info}/METADATA +6 -7
- {ccxt-4.4.90.dist-info → ccxt-4.4.91.dist-info}/RECORD +40 -57
- ccxt/abstract/coinlist.py +0 -57
- ccxt/async_support/base/ws/aiohttp_client.py +0 -147
- ccxt/async_support/bitcoincom.py +0 -18
- ccxt/async_support/bitfinex1.py +0 -1711
- ccxt/async_support/bitpanda.py +0 -17
- ccxt/async_support/coinlist.py +0 -2542
- ccxt/async_support/poloniexfutures.py +0 -1875
- ccxt/bitcoincom.py +0 -18
- ccxt/bitfinex1.py +0 -1710
- ccxt/bitpanda.py +0 -17
- ccxt/coinlist.py +0 -2542
- ccxt/poloniexfutures.py +0 -1875
- ccxt/pro/bitcoincom.py +0 -35
- ccxt/pro/bitfinex1.py +0 -635
- ccxt/pro/bitpanda.py +0 -16
- ccxt/pro/poloniexfutures.py +0 -1004
- ccxt/pro/wazirx.py +0 -766
- {ccxt-4.4.90.dist-info → ccxt-4.4.91.dist-info}/LICENSE.txt +0 -0
- {ccxt-4.4.90.dist-info → ccxt-4.4.91.dist-info}/WHEEL +0 -0
- {ccxt-4.4.90.dist-info → ccxt-4.4.91.dist-info}/top_level.txt +0 -0
ccxt/pro/kraken.py
CHANGED
@@ -56,6 +56,7 @@ class kraken(ccxt.async_support.kraken):
|
|
56
56
|
'public': 'wss://ws.kraken.com',
|
57
57
|
'private': 'wss://ws-auth.kraken.com',
|
58
58
|
'privateV2': 'wss://ws-auth.kraken.com/v2',
|
59
|
+
'publicV2': 'wss://ws.kraken.com/v2',
|
59
60
|
'beta': 'wss://beta-ws.kraken.com',
|
60
61
|
'beta-private': 'wss://beta-ws-auth.kraken.com',
|
61
62
|
},
|
@@ -70,9 +71,13 @@ class kraken(ccxt.async_support.kraken):
|
|
70
71
|
'ordersLimit': 1000,
|
71
72
|
'symbolsByOrderId': {},
|
72
73
|
'watchOrderBook': {
|
73
|
-
'checksum':
|
74
|
+
'checksum': False,
|
74
75
|
},
|
75
76
|
},
|
77
|
+
'streaming': {
|
78
|
+
'ping': self.ping,
|
79
|
+
'keepAlive': 6000,
|
80
|
+
},
|
76
81
|
'exceptions': {
|
77
82
|
'ws': {
|
78
83
|
'exact': {
|
@@ -123,6 +128,7 @@ class kraken(ccxt.async_support.kraken):
|
|
123
128
|
'EService:Market in post_only mode': NotSupported,
|
124
129
|
'EService:Unavailable': ExchangeNotAvailable,
|
125
130
|
'ETrade:Invalid request': BadRequest,
|
131
|
+
'ESession:Invalid session': AuthenticationError,
|
126
132
|
},
|
127
133
|
},
|
128
134
|
},
|
@@ -349,10 +355,10 @@ class kraken(ccxt.async_support.kraken):
|
|
349
355
|
|
350
356
|
async def cancel_orders_ws(self, ids: List[str], symbol: Str = None, params={}):
|
351
357
|
"""
|
358
|
+
cancel multiple orders
|
352
359
|
|
353
|
-
https://docs.kraken.com/api/docs/websocket-
|
360
|
+
https://docs.kraken.com/api/docs/websocket-v2/cancel_order
|
354
361
|
|
355
|
-
cancel multiple orders
|
356
362
|
:param str[] ids: order ids
|
357
363
|
:param str [symbol]: unified market symbol, default is None
|
358
364
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
@@ -377,10 +383,10 @@ class kraken(ccxt.async_support.kraken):
|
|
377
383
|
|
378
384
|
async def cancel_order_ws(self, id: str, symbol: Str = None, params={}) -> Order:
|
379
385
|
"""
|
386
|
+
cancels an open order
|
380
387
|
|
381
|
-
https://docs.kraken.com/api/docs/websocket-
|
388
|
+
https://docs.kraken.com/api/docs/websocket-v2/cancel_order
|
382
389
|
|
383
|
-
cancels an open order
|
384
390
|
:param str id: order id
|
385
391
|
:param str [symbol]: unified symbol of the market the order was made in
|
386
392
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
@@ -421,10 +427,10 @@ class kraken(ccxt.async_support.kraken):
|
|
421
427
|
|
422
428
|
async def cancel_all_orders_ws(self, symbol: Str = None, params={}):
|
423
429
|
"""
|
430
|
+
cancel all open orders
|
424
431
|
|
425
|
-
https://docs.kraken.com/api/docs/websocket-
|
432
|
+
https://docs.kraken.com/api/docs/websocket-v2/cancel_all
|
426
433
|
|
427
|
-
cancel all open orders
|
428
434
|
:param str [symbol]: unified market symbol, only orders in the market of self symbol are cancelled when symbol is not None
|
429
435
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
430
436
|
:returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
@@ -461,53 +467,56 @@ class kraken(ccxt.async_support.kraken):
|
|
461
467
|
reqId = self.safe_value(message, 'req_id')
|
462
468
|
client.resolve(message, reqId)
|
463
469
|
|
464
|
-
def handle_ticker(self, client, message
|
470
|
+
def handle_ticker(self, client, message):
|
465
471
|
#
|
466
|
-
#
|
467
|
-
#
|
468
|
-
#
|
469
|
-
#
|
470
|
-
#
|
471
|
-
#
|
472
|
-
#
|
473
|
-
#
|
474
|
-
#
|
475
|
-
#
|
476
|
-
#
|
477
|
-
#
|
478
|
-
#
|
479
|
-
#
|
480
|
-
#
|
481
|
-
#
|
472
|
+
# {
|
473
|
+
# "channel": "ticker",
|
474
|
+
# "type": "snapshot",
|
475
|
+
# "data": [
|
476
|
+
# {
|
477
|
+
# "symbol": "BTC/USD",
|
478
|
+
# "bid": 108359.8,
|
479
|
+
# "bid_qty": 0.01362603,
|
480
|
+
# "ask": 108359.9,
|
481
|
+
# "ask_qty": 17.17988863,
|
482
|
+
# "last": 108359.8,
|
483
|
+
# "volume": 2158.32346723,
|
484
|
+
# "vwap": 108894.5,
|
485
|
+
# "low": 106824,
|
486
|
+
# "high": 111300,
|
487
|
+
# "change": -2679.9,
|
488
|
+
# "change_pct": -2.41
|
489
|
+
# }
|
490
|
+
# ]
|
491
|
+
# }
|
482
492
|
#
|
483
|
-
|
484
|
-
|
485
|
-
symbol =
|
493
|
+
data = self.safe_list(message, 'data', [])
|
494
|
+
ticker = data[0]
|
495
|
+
symbol = self.safe_string(ticker, 'symbol')
|
486
496
|
messageHash = self.get_message_hash('ticker', None, symbol)
|
487
|
-
|
488
|
-
vwap = self.safe_string(ticker['p'], 0)
|
497
|
+
vwap = self.safe_string(ticker, 'vwap')
|
489
498
|
quoteVolume = None
|
490
|
-
baseVolume = self.safe_string(ticker
|
499
|
+
baseVolume = self.safe_string(ticker, 'volume')
|
491
500
|
if baseVolume is not None and vwap is not None:
|
492
501
|
quoteVolume = Precise.string_mul(baseVolume, vwap)
|
493
|
-
last = self.safe_string(ticker
|
502
|
+
last = self.safe_string(ticker, 'last')
|
494
503
|
result = self.safe_ticker({
|
495
504
|
'symbol': symbol,
|
496
505
|
'timestamp': None,
|
497
506
|
'datetime': None,
|
498
|
-
'high': self.safe_string(ticker
|
499
|
-
'low': self.safe_string(ticker
|
500
|
-
'bid': self.safe_string(ticker
|
501
|
-
'bidVolume': self.safe_string(ticker
|
502
|
-
'ask': self.safe_string(ticker
|
503
|
-
'askVolume': self.safe_string(ticker
|
507
|
+
'high': self.safe_string(ticker, 'high'),
|
508
|
+
'low': self.safe_string(ticker, 'low'),
|
509
|
+
'bid': self.safe_string(ticker, 'bid'),
|
510
|
+
'bidVolume': self.safe_string(ticker, 'bid_qty'),
|
511
|
+
'ask': self.safe_string(ticker, 'ask'),
|
512
|
+
'askVolume': self.safe_string(ticker, 'ask_qty'),
|
504
513
|
'vwap': vwap,
|
505
|
-
'open':
|
514
|
+
'open': None,
|
506
515
|
'close': last,
|
507
516
|
'last': last,
|
508
517
|
'previousClose': None,
|
509
|
-
'change':
|
510
|
-
'percentage':
|
518
|
+
'change': self.safe_string(ticker, 'change'),
|
519
|
+
'percentage': self.safe_string(ticker, 'change_pct'),
|
511
520
|
'average': None,
|
512
521
|
'baseVolume': baseVolume,
|
513
522
|
'quoteVolume': quoteVolume,
|
@@ -516,30 +525,35 @@ class kraken(ccxt.async_support.kraken):
|
|
516
525
|
self.tickers[symbol] = result
|
517
526
|
client.resolve(result, messageHash)
|
518
527
|
|
519
|
-
def handle_trades(self, client: Client, message
|
528
|
+
def handle_trades(self, client: Client, message):
|
520
529
|
#
|
521
|
-
#
|
522
|
-
#
|
523
|
-
#
|
524
|
-
#
|
525
|
-
#
|
526
|
-
#
|
527
|
-
#
|
528
|
-
#
|
529
|
-
#
|
530
|
+
# {
|
531
|
+
# "channel": "trade",
|
532
|
+
# "type": "update",
|
533
|
+
# "data": [
|
534
|
+
# {
|
535
|
+
# "symbol": "MATIC/USD",
|
536
|
+
# "side": "sell",
|
537
|
+
# "price": 0.5117,
|
538
|
+
# "qty": 40.0,
|
539
|
+
# "ord_type": "market",
|
540
|
+
# "trade_id": 4665906,
|
541
|
+
# "timestamp": "2023-09-25T07:49:37.708706Z"
|
542
|
+
# }
|
543
|
+
# ]
|
544
|
+
# }
|
530
545
|
#
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
messageHash = self.get_message_hash(name, None, symbol)
|
546
|
+
data = self.safe_list(message, 'data', [])
|
547
|
+
trade = data[0]
|
548
|
+
symbol = self.safe_string(trade, 'symbol')
|
549
|
+
messageHash = self.get_message_hash('trade', None, symbol)
|
536
550
|
stored = self.safe_value(self.trades, symbol)
|
537
551
|
if stored is None:
|
538
552
|
limit = self.safe_integer(self.options, 'tradesLimit', 1000)
|
539
553
|
stored = ArrayCache(limit)
|
540
554
|
self.trades[symbol] = stored
|
541
|
-
|
542
|
-
parsed = self.parse_trades(
|
555
|
+
market = self.market(symbol)
|
556
|
+
parsed = self.parse_trades(data, market)
|
543
557
|
for i in range(0, len(parsed)):
|
544
558
|
stored.append(parsed[i])
|
545
559
|
client.resolve(stored, messageHash)
|
@@ -624,7 +638,7 @@ class kraken(ccxt.async_support.kraken):
|
|
624
638
|
"""
|
625
639
|
watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
|
626
640
|
|
627
|
-
https://docs.kraken.com/api/docs/websocket-
|
641
|
+
https://docs.kraken.com/api/docs/websocket-v2/ticker
|
628
642
|
|
629
643
|
:param str symbol: unified symbol of the market to fetch the ticker for
|
630
644
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
@@ -639,7 +653,7 @@ class kraken(ccxt.async_support.kraken):
|
|
639
653
|
"""
|
640
654
|
watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
|
641
655
|
|
642
|
-
https://docs.kraken.com/api/docs/websocket-
|
656
|
+
https://docs.kraken.com/api/docs/websocket-v2/ticker
|
643
657
|
|
644
658
|
:param str[] symbols:
|
645
659
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
@@ -656,66 +670,29 @@ class kraken(ccxt.async_support.kraken):
|
|
656
670
|
|
657
671
|
async def watch_bids_asks(self, symbols: Strings = None, params={}) -> Tickers:
|
658
672
|
"""
|
673
|
+
watches best bid & ask for symbols
|
659
674
|
|
660
|
-
https://docs.kraken.com/api/docs/websocket-
|
675
|
+
https://docs.kraken.com/api/docs/websocket-v2/ticker
|
661
676
|
|
662
|
-
watches best bid & ask for symbols
|
663
677
|
:param str[] symbols: unified symbol of the market to fetch the ticker for
|
664
678
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
665
679
|
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
666
680
|
"""
|
667
681
|
await self.load_markets()
|
668
682
|
symbols = self.market_symbols(symbols, None, False)
|
669
|
-
|
683
|
+
params['event_trigger'] = 'bbo'
|
684
|
+
ticker = await self.watch_multi_helper('bidask', 'ticker', symbols, None, params)
|
670
685
|
if self.newUpdates:
|
671
686
|
result: dict = {}
|
672
687
|
result[ticker['symbol']] = ticker
|
673
688
|
return result
|
674
689
|
return self.filter_by_array(self.bidsasks, 'symbol', symbols)
|
675
690
|
|
676
|
-
def handle_bid_ask(self, client: Client, message, subscription):
|
677
|
-
#
|
678
|
-
# [
|
679
|
-
# 7208974, # channelID
|
680
|
-
# [
|
681
|
-
# "63758.60000", # bid
|
682
|
-
# "63759.10000", # ask
|
683
|
-
# "1726814731.089778", # timestamp
|
684
|
-
# "0.00057917", # bid_volume
|
685
|
-
# "0.15681688" # ask_volume
|
686
|
-
# ],
|
687
|
-
# "spread",
|
688
|
-
# "XBT/USDT"
|
689
|
-
# ]
|
690
|
-
#
|
691
|
-
parsedTicker = self.parse_ws_bid_ask(message)
|
692
|
-
symbol = parsedTicker['symbol']
|
693
|
-
self.bidsasks[symbol] = parsedTicker
|
694
|
-
messageHash = self.get_message_hash('bidask', None, symbol)
|
695
|
-
client.resolve(parsedTicker, messageHash)
|
696
|
-
|
697
|
-
def parse_ws_bid_ask(self, ticker, market=None):
|
698
|
-
data = self.safe_list(ticker, 1, [])
|
699
|
-
marketId = self.safe_string(ticker, 3)
|
700
|
-
market = self.safe_value(self.options['marketsByWsName'], marketId)
|
701
|
-
symbol = self.safe_string(market, 'symbol')
|
702
|
-
timestamp = self.parse_to_int(self.safe_integer(data, 2)) * 1000
|
703
|
-
return self.safe_ticker({
|
704
|
-
'symbol': symbol,
|
705
|
-
'timestamp': timestamp,
|
706
|
-
'datetime': self.iso8601(timestamp),
|
707
|
-
'ask': self.safe_string(data, 1),
|
708
|
-
'askVolume': self.safe_string(data, 4),
|
709
|
-
'bid': self.safe_string(data, 0),
|
710
|
-
'bidVolume': self.safe_string(data, 3),
|
711
|
-
'info': ticker,
|
712
|
-
}, market)
|
713
|
-
|
714
691
|
async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
715
692
|
"""
|
716
693
|
get the list of most recent trades for a particular symbol
|
717
694
|
|
718
|
-
https://docs.kraken.com/api/docs/websocket-
|
695
|
+
https://docs.kraken.com/api/docs/websocket-v2/trade
|
719
696
|
|
720
697
|
:param str symbol: unified symbol of the market to fetch trades for
|
721
698
|
:param int [since]: timestamp in ms of the earliest trade to fetch
|
@@ -727,10 +704,10 @@ class kraken(ccxt.async_support.kraken):
|
|
727
704
|
|
728
705
|
async def watch_trades_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
729
706
|
"""
|
707
|
+
get the list of most recent trades for a list of symbols
|
730
708
|
|
731
|
-
https://docs.kraken.com/api/docs/websocket-
|
709
|
+
https://docs.kraken.com/api/docs/websocket-v2/trade
|
732
710
|
|
733
|
-
get the list of most recent trades for a list of symbols
|
734
711
|
:param str[] symbols: unified symbol of the market to fetch trades for
|
735
712
|
:param int [since]: timestamp in ms of the earliest trade to fetch
|
736
713
|
:param int [limit]: the maximum amount of trades to fetch
|
@@ -748,7 +725,7 @@ class kraken(ccxt.async_support.kraken):
|
|
748
725
|
"""
|
749
726
|
watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
|
750
727
|
|
751
|
-
https://docs.kraken.com/api/docs/websocket-
|
728
|
+
https://docs.kraken.com/api/docs/websocket-v2/book
|
752
729
|
|
753
730
|
:param str symbol: unified symbol of the market to fetch the order book for
|
754
731
|
:param int [limit]: the maximum amount of order book entries to return
|
@@ -761,7 +738,7 @@ class kraken(ccxt.async_support.kraken):
|
|
761
738
|
"""
|
762
739
|
watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
|
763
740
|
|
764
|
-
https://docs.kraken.com/api/docs/websocket-
|
741
|
+
https://docs.kraken.com/api/docs/websocket-v2/book
|
765
742
|
|
766
743
|
:param str[] symbols: unified array of symbols
|
767
744
|
:param int [limit]: the maximum amount of order book entries to return
|
@@ -771,7 +748,7 @@ class kraken(ccxt.async_support.kraken):
|
|
771
748
|
request: dict = {}
|
772
749
|
if limit is not None:
|
773
750
|
if self.in_array(limit, [10, 25, 100, 500, 1000]):
|
774
|
-
request['
|
751
|
+
request['params'] = {
|
775
752
|
'depth': limit, # default 10, valid options 10, 25, 100, 500, 1000
|
776
753
|
}
|
777
754
|
else:
|
@@ -831,6 +808,19 @@ class kraken(ccxt.async_support.kraken):
|
|
831
808
|
self.options['marketsByWsName'] = marketsByWsName
|
832
809
|
return markets
|
833
810
|
|
811
|
+
def ping(self, client: Client):
|
812
|
+
url = client.url
|
813
|
+
request = {}
|
814
|
+
if url.find('v2') >= 0:
|
815
|
+
request['method'] = 'ping'
|
816
|
+
else:
|
817
|
+
request['event'] = 'ping'
|
818
|
+
return request
|
819
|
+
|
820
|
+
def handle_pong(self, client: Client, message):
|
821
|
+
client.lastPong = self.milliseconds()
|
822
|
+
return message
|
823
|
+
|
834
824
|
async def watch_heartbeat(self, params={}):
|
835
825
|
await self.load_markets()
|
836
826
|
event = 'heartbeat'
|
@@ -846,157 +836,151 @@ class kraken(ccxt.async_support.kraken):
|
|
846
836
|
event = self.safe_string(message, 'event')
|
847
837
|
client.resolve(message, event)
|
848
838
|
|
849
|
-
def handle_order_book(self, client: Client, message
|
839
|
+
def handle_order_book(self, client: Client, message):
|
850
840
|
#
|
851
841
|
# first message(snapshot)
|
852
842
|
#
|
853
|
-
#
|
854
|
-
#
|
855
|
-
#
|
856
|
-
#
|
857
|
-
#
|
858
|
-
#
|
859
|
-
#
|
860
|
-
#
|
861
|
-
#
|
862
|
-
#
|
863
|
-
#
|
864
|
-
#
|
865
|
-
#
|
866
|
-
#
|
867
|
-
#
|
868
|
-
#
|
869
|
-
#
|
843
|
+
# {
|
844
|
+
# "channel": "book",
|
845
|
+
# "type": "snapshot",
|
846
|
+
# "data": [
|
847
|
+
# {
|
848
|
+
# "symbol": "MATIC/USD",
|
849
|
+
# "bids": [
|
850
|
+
# {
|
851
|
+
# "price": 0.5666,
|
852
|
+
# "qty": 4831.75496356
|
853
|
+
# },
|
854
|
+
# {
|
855
|
+
# "price": 0.5665,
|
856
|
+
# "qty": 6658.22734739
|
857
|
+
# }
|
858
|
+
# ],
|
859
|
+
# "asks": [
|
860
|
+
# {
|
861
|
+
# "price": 0.5668,
|
862
|
+
# "qty": 4410.79769741
|
863
|
+
# },
|
864
|
+
# {
|
865
|
+
# "price": 0.5669,
|
866
|
+
# "qty": 4655.40412487
|
867
|
+
# }
|
868
|
+
# ],
|
869
|
+
# "checksum": 2439117997
|
870
|
+
# }
|
871
|
+
# ]
|
872
|
+
# }
|
870
873
|
#
|
871
874
|
# subsequent updates
|
872
875
|
#
|
873
|
-
#
|
874
|
-
#
|
875
|
-
#
|
876
|
-
#
|
877
|
-
#
|
878
|
-
#
|
879
|
-
#
|
880
|
-
#
|
881
|
-
#
|
882
|
-
#
|
883
|
-
#
|
884
|
-
#
|
885
|
-
#
|
886
|
-
#
|
887
|
-
#
|
888
|
-
#
|
876
|
+
# {
|
877
|
+
# "channel": "book",
|
878
|
+
# "type": "update",
|
879
|
+
# "data": [
|
880
|
+
# {
|
881
|
+
# "symbol": "MATIC/USD",
|
882
|
+
# "bids": [
|
883
|
+
# {
|
884
|
+
# "price": 0.5657,
|
885
|
+
# "qty": 1098.3947558
|
886
|
+
# }
|
887
|
+
# ],
|
888
|
+
# "asks": [],
|
889
|
+
# "checksum": 2114181697,
|
890
|
+
# "timestamp": "2023-10-06T17:35:55.440295Z"
|
891
|
+
# }
|
892
|
+
# ]
|
893
|
+
# }
|
889
894
|
#
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
timestamp = None
|
895
|
+
type = self.safe_string(message, 'type')
|
896
|
+
data = self.safe_list(message, 'data', [])
|
897
|
+
first = self.safe_dict(data, 0, {})
|
898
|
+
symbol = self.safe_string(first, 'symbol')
|
899
|
+
a = self.safe_value(first, 'asks', [])
|
900
|
+
b = self.safe_value(first, 'bids', [])
|
901
|
+
c = self.safe_integer(first, 'checksum')
|
898
902
|
messageHash = self.get_message_hash('orderbook', None, symbol)
|
899
|
-
|
900
|
-
if '
|
901
|
-
# todo get depth from marketsByWsName
|
902
|
-
self.orderbooks[symbol] = self.order_book({}, depth)
|
903
|
+
orderbook = None
|
904
|
+
if type == 'update':
|
903
905
|
orderbook = self.orderbooks[symbol]
|
904
|
-
sides: dict = {
|
905
|
-
'as': 'asks',
|
906
|
-
'bs': 'bids',
|
907
|
-
}
|
908
|
-
keys = list(sides.keys())
|
909
|
-
for i in range(0, len(keys)):
|
910
|
-
key = keys[i]
|
911
|
-
side = sides[key]
|
912
|
-
bookside = orderbook[side]
|
913
|
-
deltas = self.safe_value(message[1], key, [])
|
914
|
-
timestamp = self.custom_handle_deltas(bookside, deltas, timestamp)
|
915
|
-
orderbook['symbol'] = symbol
|
916
|
-
orderbook['timestamp'] = timestamp
|
917
|
-
orderbook['datetime'] = self.iso8601(timestamp)
|
918
|
-
client.resolve(orderbook, messageHash)
|
919
|
-
else:
|
920
|
-
orderbook = self.orderbooks[symbol]
|
921
|
-
# else, if self is an orderbook update
|
922
|
-
a = None
|
923
|
-
b = None
|
924
|
-
c = None
|
925
|
-
if messageLength == 5:
|
926
|
-
a = self.safe_value(message[1], 'a', [])
|
927
|
-
b = self.safe_value(message[2], 'b', [])
|
928
|
-
c = self.safe_integer(message[1], 'c')
|
929
|
-
c = self.safe_integer(message[2], 'c', c)
|
930
|
-
else:
|
931
|
-
c = self.safe_integer(message[1], 'c')
|
932
|
-
if 'a' in message[1]:
|
933
|
-
a = self.safe_value(message[1], 'a', [])
|
934
|
-
else:
|
935
|
-
b = self.safe_value(message[1], 'b', [])
|
936
906
|
storedAsks = orderbook['asks']
|
937
907
|
storedBids = orderbook['bids']
|
938
|
-
example = None
|
939
908
|
if a is not None:
|
940
|
-
|
941
|
-
example = self.safe_value(a, 0)
|
909
|
+
self.custom_handle_deltas(storedAsks, a)
|
942
910
|
if b is not None:
|
943
|
-
|
944
|
-
|
945
|
-
# don't remove self line or I will poop on your face
|
946
|
-
orderbook.limit()
|
947
|
-
checksum = self.handle_option('watchOrderBook', 'checksum', True)
|
948
|
-
if checksum:
|
949
|
-
priceString = self.safe_string(example, 0)
|
950
|
-
amountString = self.safe_string(example, 1)
|
951
|
-
priceParts = priceString.split('.')
|
952
|
-
amountParts = amountString.split('.')
|
953
|
-
priceLength = len(priceParts[1]) - 0
|
954
|
-
amountLength = len(amountParts[1]) - 0
|
955
|
-
payloadArray = []
|
956
|
-
if c is not None:
|
957
|
-
for i in range(0, 10):
|
958
|
-
formatted = self.format_number(storedAsks[i][0], priceLength) + self.format_number(storedAsks[i][1], amountLength)
|
959
|
-
payloadArray.append(formatted)
|
960
|
-
for i in range(0, 10):
|
961
|
-
formatted = self.format_number(storedBids[i][0], priceLength) + self.format_number(storedBids[i][1], amountLength)
|
962
|
-
payloadArray.append(formatted)
|
963
|
-
payload = ''.join(payloadArray)
|
964
|
-
localChecksum = self.crc32(payload, False)
|
965
|
-
if localChecksum != c:
|
966
|
-
error = ChecksumError(self.id + ' ' + self.orderbook_checksum_message(symbol))
|
967
|
-
del client.subscriptions[messageHash]
|
968
|
-
del self.orderbooks[symbol]
|
969
|
-
client.reject(error, messageHash)
|
970
|
-
return
|
911
|
+
self.custom_handle_deltas(storedBids, b)
|
912
|
+
datetime = self.safe_string(first, 'timestamp')
|
971
913
|
orderbook['symbol'] = symbol
|
972
|
-
orderbook['timestamp'] =
|
973
|
-
orderbook['datetime'] =
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
914
|
+
orderbook['timestamp'] = self.parse8601(datetime)
|
915
|
+
orderbook['datetime'] = datetime
|
916
|
+
else:
|
917
|
+
# snapshot
|
918
|
+
depth = len(a)
|
919
|
+
self.orderbooks[symbol] = self.order_book({}, depth)
|
920
|
+
orderbook = self.orderbooks[symbol]
|
921
|
+
keys = ['asks', 'bids']
|
922
|
+
for i in range(0, len(keys)):
|
923
|
+
key = keys[i]
|
924
|
+
bookside = orderbook[key]
|
925
|
+
deltas = self.safe_value(first, key, [])
|
926
|
+
if len(deltas) > 0:
|
927
|
+
self.custom_handle_deltas(bookside, deltas)
|
928
|
+
orderbook['symbol'] = symbol
|
929
|
+
orderbook.limit()
|
930
|
+
# checksum temporarily disabled because the exchange checksum was not reliable
|
931
|
+
checksum = self.handle_option('watchOrderBook', 'checksum', False)
|
932
|
+
if checksum:
|
933
|
+
payloadArray = []
|
934
|
+
if c is not None:
|
935
|
+
checkAsks = orderbook['asks']
|
936
|
+
checkBids = orderbook['bids']
|
937
|
+
# checkAsks = asks.map((elem) => [elem['price'], elem['qty']])
|
938
|
+
# checkBids = bids.map((elem) => [elem['price'], elem['qty']])
|
939
|
+
for i in range(0, 10):
|
940
|
+
currentAsk = self.safe_value(checkAsks, i, {})
|
941
|
+
formattedAsk = self.format_number(currentAsk[0]) + self.format_number(currentAsk[1])
|
942
|
+
payloadArray.append(formattedAsk)
|
943
|
+
for i in range(0, 10):
|
944
|
+
currentBid = self.safe_value(checkBids, i, {})
|
945
|
+
formattedBid = self.format_number(currentBid[0]) + self.format_number(currentBid[1])
|
946
|
+
payloadArray.append(formattedBid)
|
947
|
+
payload = ''.join(payloadArray)
|
948
|
+
localChecksum = self.crc32(payload, False)
|
949
|
+
if localChecksum != c:
|
950
|
+
error = ChecksumError(self.id + ' ' + self.orderbook_checksum_message(symbol))
|
951
|
+
del client.subscriptions[messageHash]
|
952
|
+
del self.orderbooks[symbol]
|
953
|
+
client.reject(error, messageHash)
|
954
|
+
return
|
955
|
+
client.resolve(orderbook, messageHash)
|
956
|
+
|
957
|
+
def custom_handle_deltas(self, bookside, deltas):
|
958
|
+
# sortOrder = True if (key == 'bids') else False
|
959
|
+
for j in range(0, len(deltas)):
|
960
|
+
delta = deltas[j]
|
961
|
+
price = self.safe_number(delta, 'price')
|
962
|
+
amount = self.safe_number(delta, 'qty')
|
963
|
+
bookside.store(price, amount)
|
964
|
+
# if amount == 0:
|
965
|
+
# index = bookside.findIndex((x: Int) => x[0] == price)
|
966
|
+
# bookside.splice(index, 1)
|
967
|
+
# else:
|
968
|
+
# bookside.store(price, amount)
|
969
|
+
# }
|
970
|
+
# bookside = self.sort_by(bookside, 0, sortOrder)
|
971
|
+
# bookside[0:9]
|
972
|
+
|
973
|
+
def format_number(self, data):
|
974
|
+
parts = data.split('.')
|
979
975
|
integer = self.safe_string(parts, 0)
|
980
976
|
decimals = self.safe_string(parts, 1, '')
|
981
|
-
|
982
|
-
joined = integer + paddedDecimals
|
977
|
+
joinedResult = integer + decimals
|
983
978
|
i = 0
|
984
|
-
while(
|
979
|
+
while(joinedResult[i] == '0'):
|
985
980
|
i += 1
|
986
981
|
if i > 0:
|
987
|
-
|
988
|
-
|
989
|
-
return joined
|
990
|
-
|
991
|
-
def custom_handle_deltas(self, bookside, deltas, timestamp=None):
|
992
|
-
for j in range(0, len(deltas)):
|
993
|
-
delta = deltas[j]
|
994
|
-
price = self.parse_number(delta[0])
|
995
|
-
amount = self.parse_number(delta[1])
|
996
|
-
oldTimestamp = timestamp if timestamp else 0
|
997
|
-
timestamp = max(oldTimestamp, self.parse_to_int(float(delta[2]) * 1000))
|
998
|
-
bookside.store(price, amount)
|
999
|
-
return timestamp
|
982
|
+
joinedResult = joinedResult[i:]
|
983
|
+
return joinedResult
|
1000
984
|
|
1001
985
|
def handle_system_status(self, client: Client, message):
|
1002
986
|
#
|
@@ -1032,7 +1016,11 @@ class kraken(ccxt.async_support.kraken):
|
|
1032
1016
|
client = self.client(url)
|
1033
1017
|
authenticated = 'authenticated'
|
1034
1018
|
subscription = self.safe_value(client.subscriptions, authenticated)
|
1035
|
-
|
1019
|
+
now = self.seconds()
|
1020
|
+
start = self.safe_integer(subscription, 'start')
|
1021
|
+
expires = self.safe_integer(subscription, 'expires')
|
1022
|
+
if (subscription is None) or ((subscription is not None) and (start + expires) <= now):
|
1023
|
+
# https://docs.kraken.com/api/docs/rest-api/get-websockets-token
|
1036
1024
|
response = await self.privatePostGetWebSocketsToken(params)
|
1037
1025
|
#
|
1038
1026
|
# {
|
@@ -1043,7 +1031,8 @@ class kraken(ccxt.async_support.kraken):
|
|
1043
1031
|
# }
|
1044
1032
|
# }
|
1045
1033
|
#
|
1046
|
-
subscription = self.
|
1034
|
+
subscription = self.safe_dict(response, 'result')
|
1035
|
+
subscription['start'] = now
|
1047
1036
|
client.subscriptions[authenticated] = subscription
|
1048
1037
|
return self.safe_string(subscription, 'token')
|
1049
1038
|
|
@@ -1477,23 +1466,22 @@ class kraken(ccxt.async_support.kraken):
|
|
1477
1466
|
symbols = self.market_symbols(symbols, None, False, True, False)
|
1478
1467
|
messageHashes = []
|
1479
1468
|
for i in range(0, len(symbols)):
|
1480
|
-
|
1481
|
-
|
1482
|
-
|
1483
|
-
|
1484
|
-
|
1485
|
-
wsMarketId = self.safe_string(markets[i]['info'], 'wsname')
|
1486
|
-
wsMarketIds.append(wsMarketId)
|
1469
|
+
eventTrigger = self.safe_string(params, 'event_trigger')
|
1470
|
+
if eventTrigger is not None:
|
1471
|
+
messageHashes.append(self.get_message_hash(channelName, None, self.symbol(symbols[i])))
|
1472
|
+
else:
|
1473
|
+
messageHashes.append(self.get_message_hash(unifiedName, None, self.symbol(symbols[i])))
|
1487
1474
|
request: dict = {
|
1488
|
-
'
|
1489
|
-
'
|
1490
|
-
|
1491
|
-
|
1492
|
-
'name': channelName,
|
1475
|
+
'method': 'subscribe',
|
1476
|
+
'params': {
|
1477
|
+
'channel': channelName,
|
1478
|
+
'symbol': symbols,
|
1493
1479
|
},
|
1480
|
+
'req_id': self.request_id(),
|
1494
1481
|
}
|
1495
|
-
|
1496
|
-
|
1482
|
+
request['params'] = self.deep_extend(request['params'], params)
|
1483
|
+
url = self.urls['api']['ws']['publicV2']
|
1484
|
+
return await self.watch_multiple(url, messageHashes, request, messageHashes, subscriptionArgs)
|
1497
1485
|
|
1498
1486
|
async def watch_balance(self, params={}) -> Balances:
|
1499
1487
|
"""
|
@@ -1649,11 +1637,7 @@ class kraken(ccxt.async_support.kraken):
|
|
1649
1637
|
name = self.safe_string(info, 'name')
|
1650
1638
|
methods: dict = {
|
1651
1639
|
# public
|
1652
|
-
'book': self.handle_order_book,
|
1653
1640
|
'ohlc': self.handle_ohlcv,
|
1654
|
-
'ticker': self.handle_ticker,
|
1655
|
-
'spread': self.handle_bid_ask,
|
1656
|
-
'trade': self.handle_trades,
|
1657
1641
|
# private
|
1658
1642
|
'openOrders': self.handle_orders,
|
1659
1643
|
'ownTrades': self.handle_my_trades,
|
@@ -1666,6 +1650,9 @@ class kraken(ccxt.async_support.kraken):
|
|
1666
1650
|
if channel is not None:
|
1667
1651
|
methods: dict = {
|
1668
1652
|
'balances': self.handle_balance,
|
1653
|
+
'book': self.handle_order_book,
|
1654
|
+
'ticker': self.handle_ticker,
|
1655
|
+
'trade': self.handle_trades,
|
1669
1656
|
}
|
1670
1657
|
method = self.safe_value(methods, channel)
|
1671
1658
|
if method is not None:
|
@@ -1680,6 +1667,7 @@ class kraken(ccxt.async_support.kraken):
|
|
1680
1667
|
'amend_order': self.handle_create_edit_order,
|
1681
1668
|
'cancel_order': self.handle_cancel_order,
|
1682
1669
|
'cancel_all': self.handle_cancel_all_orders,
|
1670
|
+
'pong': self.handle_pong,
|
1683
1671
|
}
|
1684
1672
|
method = self.safe_value(methods, event)
|
1685
1673
|
if method is not None:
|