ccxt 4.4.90__py2.py3-none-any.whl → 4.4.92__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.
Files changed (71) hide show
  1. ccxt/__init__.py +1 -3
  2. ccxt/abstract/lbank.py +1 -0
  3. ccxt/async_support/__init__.py +1 -3
  4. ccxt/async_support/base/exchange.py +6 -3
  5. ccxt/async_support/base/ws/client.py +173 -64
  6. ccxt/async_support/base/ws/future.py +23 -50
  7. ccxt/async_support/binance.py +1 -1
  8. ccxt/async_support/bitmart.py +7 -0
  9. ccxt/async_support/bitmex.py +2 -1
  10. ccxt/async_support/bitvavo.py +7 -1
  11. ccxt/async_support/cex.py +61 -0
  12. ccxt/async_support/cryptocom.py +17 -2
  13. ccxt/async_support/cryptomus.py +1 -1
  14. ccxt/async_support/exmo.py +25 -10
  15. ccxt/async_support/gate.py +2 -2
  16. ccxt/async_support/htx.py +1 -1
  17. ccxt/async_support/hyperliquid.py +104 -53
  18. ccxt/async_support/kraken.py +26 -1
  19. ccxt/async_support/krakenfutures.py +1 -1
  20. ccxt/async_support/lbank.py +113 -33
  21. ccxt/async_support/mexc.py +1 -0
  22. ccxt/async_support/modetrade.py +2 -2
  23. ccxt/async_support/okx.py +2 -2
  24. ccxt/async_support/paradex.py +1 -1
  25. ccxt/base/exchange.py +22 -23
  26. ccxt/base/types.py +1 -0
  27. ccxt/binance.py +1 -1
  28. ccxt/bitmart.py +7 -0
  29. ccxt/bitmex.py +2 -1
  30. ccxt/bitvavo.py +7 -1
  31. ccxt/cex.py +61 -0
  32. ccxt/cryptocom.py +17 -2
  33. ccxt/cryptomus.py +1 -1
  34. ccxt/exmo.py +24 -10
  35. ccxt/gate.py +2 -2
  36. ccxt/htx.py +1 -1
  37. ccxt/hyperliquid.py +104 -53
  38. ccxt/kraken.py +26 -1
  39. ccxt/krakenfutures.py +1 -1
  40. ccxt/lbank.py +113 -33
  41. ccxt/mexc.py +1 -0
  42. ccxt/modetrade.py +2 -2
  43. ccxt/okx.py +2 -2
  44. ccxt/paradex.py +1 -1
  45. ccxt/pro/__init__.py +1 -1
  46. ccxt/pro/bitstamp.py +1 -1
  47. ccxt/pro/bybit.py +9 -140
  48. ccxt/pro/kraken.py +246 -258
  49. ccxt/pro/mexc.py +0 -1
  50. {ccxt-4.4.90.dist-info → ccxt-4.4.92.dist-info}/METADATA +6 -7
  51. {ccxt-4.4.90.dist-info → ccxt-4.4.92.dist-info}/RECORD +54 -71
  52. ccxt/abstract/coinlist.py +0 -57
  53. ccxt/async_support/base/ws/aiohttp_client.py +0 -147
  54. ccxt/async_support/bitcoincom.py +0 -18
  55. ccxt/async_support/bitfinex1.py +0 -1711
  56. ccxt/async_support/bitpanda.py +0 -17
  57. ccxt/async_support/coinlist.py +0 -2542
  58. ccxt/async_support/poloniexfutures.py +0 -1875
  59. ccxt/bitcoincom.py +0 -18
  60. ccxt/bitfinex1.py +0 -1710
  61. ccxt/bitpanda.py +0 -17
  62. ccxt/coinlist.py +0 -2542
  63. ccxt/poloniexfutures.py +0 -1875
  64. ccxt/pro/bitcoincom.py +0 -35
  65. ccxt/pro/bitfinex1.py +0 -635
  66. ccxt/pro/bitpanda.py +0 -16
  67. ccxt/pro/poloniexfutures.py +0 -1004
  68. ccxt/pro/wazirx.py +0 -766
  69. {ccxt-4.4.90.dist-info → ccxt-4.4.92.dist-info}/LICENSE.txt +0 -0
  70. {ccxt-4.4.90.dist-info → ccxt-4.4.92.dist-info}/WHEEL +0 -0
  71. {ccxt-4.4.90.dist-info → ccxt-4.4.92.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': True,
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-v1/cancelorder
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-v1/cancelorder
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-v1/cancelall
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, subscription):
470
+ def handle_ticker(self, client, message):
465
471
  #
466
- # [
467
- # 0, # channelID
468
- # {
469
- # "a": ["5525.40000", 1, "1.000"], # ask, wholeAskVolume, askVolume
470
- # "b": ["5525.10000", 1, "1.000"], # bid, wholeBidVolume, bidVolume
471
- # "c": ["5525.10000", "0.00398963"], # closing price, volume
472
- # "h": ["5783.00000", "5783.00000"], # high price today, high price 24h ago
473
- # "l": ["5505.00000", "5505.00000"], # low price today, low price 24h ago
474
- # "o": ["5760.70000", "5763.40000"], # open price today, open price 24h ago
475
- # "p": ["5631.44067", "5653.78939"], # vwap today, vwap 24h ago
476
- # "t": [11493, 16267], # number of trades today, 24 hours ago
477
- # "v": ["2634.11501494", "3591.17907851"], # volume today, volume 24 hours ago
478
- # },
479
- # "ticker",
480
- # "XBT/USD"
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
- wsName = message[3]
484
- market = self.safe_value(self.options['marketsByWsName'], wsName)
485
- symbol = market['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
- ticker = message[1]
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['v'], 0)
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['c'], 0)
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['h'], 0),
499
- 'low': self.safe_string(ticker['l'], 0),
500
- 'bid': self.safe_string(ticker['b'], 0),
501
- 'bidVolume': self.safe_string(ticker['b'], 2),
502
- 'ask': self.safe_string(ticker['a'], 0),
503
- 'askVolume': self.safe_string(ticker['a'], 2),
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': self.safe_string(ticker['o'], 0),
514
+ 'open': None,
506
515
  'close': last,
507
516
  'last': last,
508
517
  'previousClose': None,
509
- 'change': None,
510
- 'percentage': None,
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, subscription):
528
+ def handle_trades(self, client: Client, message):
520
529
  #
521
- # [
522
- # 0, # channelID
523
- # [ # price volume time side type misc
524
- # ["5541.20000", "0.15850568", "1534614057.321596", "s", "l", ""],
525
- # ["6060.00000", "0.02455000", "1534614057.324998", "b", "l", ""],
526
- # ],
527
- # "trade",
528
- # "XBT/USD"
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
- wsName = self.safe_string(message, 3)
532
- name = self.safe_string(message, 2)
533
- market = self.safe_value(self.options['marketsByWsName'], wsName)
534
- symbol = market['symbol']
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
- trades = self.safe_value(message, 1, [])
542
- parsed = self.parse_trades(trades, market)
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-v1/ticker
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-v1/ticker
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-v1/spread
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
- ticker = await self.watch_multi_helper('bidask', 'spread', symbols, None, params)
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-v1/trade
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-v1/trade
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-v1/book
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-v1/book
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['subscription'] = {
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, subscription):
839
+ def handle_order_book(self, client: Client, message):
850
840
  #
851
841
  # first message(snapshot)
852
842
  #
853
- # [
854
- # 1234, # channelID
855
- # {
856
- # "as": [
857
- # ["5541.30000", "2.50700000", "1534614248.123678"],
858
- # ["5541.80000", "0.33000000", "1534614098.345543"],
859
- # ["5542.70000", "0.64700000", "1534614244.654432"]
860
- # ],
861
- # "bs": [
862
- # ["5541.20000", "1.52900000", "1534614248.765567"],
863
- # ["5539.90000", "0.30000000", "1534614241.769870"],
864
- # ["5539.50000", "5.00000000", "1534613831.243486"]
865
- # ]
866
- # },
867
- # "book-10",
868
- # "XBT/USD"
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
- # 1234,
875
- # { # optional
876
- # "a": [
877
- # ["5541.30000", "2.50700000", "1534614248.456738"],
878
- # ["5542.50000", "0.40100000", "1534614248.456738"]
879
- # ]
880
- # },
881
- # { # optional
882
- # "b": [
883
- # ["5541.30000", "0.00000000", "1534614335.345903"]
884
- # ]
885
- # },
886
- # "book-10",
887
- # "XBT/USD"
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
- messageLength = len(message)
891
- wsName = message[messageLength - 1]
892
- bookDepthString = message[messageLength - 2]
893
- parts = bookDepthString.split('-')
894
- depth = self.safe_integer(parts, 1, 10)
895
- market = self.safe_value(self.options['marketsByWsName'], wsName)
896
- symbol = market['symbol']
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
- # if self is a snapshot
900
- if 'as' in message[1]:
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
- timestamp = self.custom_handle_deltas(storedAsks, a, timestamp)
941
- example = self.safe_value(a, 0)
909
+ self.custom_handle_deltas(storedAsks, a)
942
910
  if b is not None:
943
- timestamp = self.custom_handle_deltas(storedBids, b, timestamp)
944
- example = self.safe_value(b, 0)
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'] = timestamp
973
- orderbook['datetime'] = self.iso8601(timestamp)
974
- client.resolve(orderbook, messageHash)
975
-
976
- def format_number(self, n, length):
977
- stringNumber = self.number_to_string(n)
978
- parts = stringNumber.split('.')
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
- paddedDecimals = decimals.ljust(length, '0')
982
- joined = integer + paddedDecimals
977
+ joinedResult = integer + decimals
983
978
  i = 0
984
- while(joined[i] == '0'):
979
+ while(joinedResult[i] == '0'):
985
980
  i += 1
986
981
  if i > 0:
987
- return joined[i:]
988
- else:
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
- if subscription is None:
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.safe_value(response, 'result')
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
- messageHashes.append(self.get_message_hash(unifiedName, None, self.symbol(symbols[i])))
1481
- # for WS subscriptions, we can't use .marketIds(symbols), instead a custom is field needed
1482
- markets = self.markets_for_symbols(symbols)
1483
- wsMarketIds = []
1484
- for i in range(0, len(markets)):
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
- 'event': 'subscribe',
1489
- 'reqid': self.request_id(),
1490
- 'pair': wsMarketIds,
1491
- 'subscription': {
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
- url = self.urls['api']['ws']['public']
1496
- return await self.watch_multiple(url, messageHashes, self.deep_extend(request, params), messageHashes, subscriptionArgs)
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: