Maintain a valid Spot Orderbook

The following examples demonstrate how to use the python-kraken-sdk to retrieve valid realtime orderbooks. The current implementation of the kraken.spot.OrderbookClientV2 uses the websocket API v2 and kraken.spot.OrderbookClientV1 provides the legacy support for websocket API v2.

Sample on how to maintain a valid orderbook w/ websocket API v2
  1#!/usr/bin/env python
  2# Copyright (C) 2023 Benjamin Thomas Schwertfeger
  3# GitHub: https://github.com/btschwertfeger
  4#
  5
  6"""
  7
  8**For websocket API v2**
  9
 10This module provides an example on how to use the Spot Orderbook client of the
 11python-kraken-sdk (https://github.com/btschwertfeger/python-kraken-sdk) to
 12retrieve and maintain a valid Spot order book for (a) specific asset pair(s).
 13It can be run directly without any credentials if the python-kraken-sdk is
 14installed.
 15
 16    python3 -m pip install python-kraken-sdk
 17
 18The output when running this snippet looks like the following table and updates
 19the book as soon as Kraken sent any order book update.
 20
 21Bid         Volume               Ask         Volume
 2227076.00000 (8.28552127)         27076.10000 (2.85897056)
 2327075.90000 (3.75748052)         27077.30000 (0.57243521)
 2427074.40000 (0.57249652)         27080.80000 (0.00100000)
 2527072.90000 (0.01200917)         27081.00000 (0.00012345)
 2627072.80000 (0.25000000)         27081.70000 (0.30000000)
 2727072.30000 (4.89735970)         27082.70000 (0.05539777)
 2827072.20000 (2.65896716)         27082.80000 (0.00400000)
 2927072.10000 (2.77037635)         27082.90000 (0.57231684)
 3027072.00000 (0.81770000)         27083.00000 (0.38934000)
 3127071.50000 (0.07194657)         27083.80000 (2.76918992)
 32
 33This can be the basis of an order book based trading strategy where realtime
 34data and fast price movements are considered.
 35"""
 36
 37from __future__ import annotations
 38
 39import asyncio
 40import logging
 41from typing import Any
 42
 43from kraken.spot import OrderbookClientV2
 44
 45logging.basicConfig(
 46    format="%(asctime)s %(module)s,line: %(lineno)d %(levelname)8s | %(message)s",
 47    datefmt="%Y/%m/%d %H:%M:%S",
 48    level=logging.INFO,
 49)
 50logging.getLogger().setLevel(logging.INFO)
 51logging.getLogger("requests").setLevel(logging.WARNING)
 52
 53
 54class Orderbook(OrderbookClientV2):
 55    """
 56    This is a wrapper class that is used to overload the :func:`on_book_update`
 57    function. It can also be used as a base for trading strategy. Since the
 58    :class:`kraken.spot.OrderbookClientV2` is derived from
 59    :class:`kraken.spot.KrakenSpotWSClientV2` it can also be used to access the
 60    :func:`subscribe` function and any other provided utility.
 61    """
 62
 63    async def on_book_update(
 64        self: Orderbook,
 65        pair: str,
 66        message: list,  # noqa: ARG002
 67    ) -> None:
 68        """
 69        This function is called every time the order book of ``pair`` gets
 70        updated.
 71
 72        The ``pair`` parameter can be used to access the updated order book as
 73        shown in the function body below.
 74
 75        :param pair: The currency pair of the updated order book
 76        :type pair: str
 77        :param message: The message sent by Kraken (not needed in most cases)
 78        :type message: list
 79        """
 80        book: dict[str, Any] = self.get(pair=pair)
 81        bid: list[tuple[str, str]] = list(book["bid"].items())
 82        ask: list[tuple[str, str]] = list(book["ask"].items())
 83
 84        print("Bid     Volume\t\t  Ask     Volume")
 85        for level in range(self.depth):
 86            print(
 87                f"{bid[level][0]} ({bid[level][1][0]}) \t {ask[level][0]} ({ask[level][1][0]})",
 88            )
 89
 90        assert book["valid"]  # ensure that the checksum is valid
 91        # … the client will automatically resubscribe to a book feed if the
 92        #   checksum is not valid. The user must not do anything for that, but
 93        #   will get informed.
 94
 95
 96async def main() -> None:
 97    """
 98    Here we depth of the order book and also a pair. We could
 99    subscribe to multiple pairs, but for simplicity only XBT/USD is chosen.
100
101    The Orderbook class can be instantiated, which receives the order
102    book-related messages, after we subscribed to the book feed.
103
104    Finally we need some "game loop" - so we create a while loop
105    that runs as long as there is no error.
106    """
107    orderbook: Orderbook = Orderbook(depth=10)
108
109    await orderbook.add_book(
110        pairs=["BTC/USD"],  # we can also subscribe to more currency pairs
111    )
112
113    while not orderbook.exception_occur:
114        await asyncio.sleep(10)
115
116
117if __name__ == "__main__":
118    try:
119        asyncio.run(main())
120    except KeyboardInterrupt:
121        print("KeyboardInterrupt!")
Sample on how to maintain a valid orderbook w/ websocket API v1
  1#!/usr/bin/env python
  2# Copyright (C) 2023 Benjamin Thomas Schwertfeger
  3# GitHub: https://github.com/btschwertfeger
  4#
  5
  6"""
  7
  8**For websocket API v1**
  9
 10This module provides an example on how to use the Spot Orderbook client of the
 11python-kraken-sdk (https://github.com/btschwertfeger/python-kraken-sdk) to
 12retrieve and maintain a valid Spot order book for (a) specific asset pair(s).
 13It can be run directly without any credentials if the python-kraken-sdk is
 14installed.
 15
 16    python3 -m pip install python-kraken-sdk
 17
 18The output when running this snippet looks like the following table and updates
 19the book as soon as Kraken sent any order book update.
 20
 21Bid         Volume               Ask         Volume
 2227076.00000 (8.28552127)         27076.10000 (2.85897056)
 2327075.90000 (3.75748052)         27077.30000 (0.57243521)
 2427074.40000 (0.57249652)         27080.80000 (0.00100000)
 2527072.90000 (0.01200917)         27081.00000 (0.00012345)
 2627072.80000 (0.25000000)         27081.70000 (0.30000000)
 2727072.30000 (4.89735970)         27082.70000 (0.05539777)
 2827072.20000 (2.65896716)         27082.80000 (0.00400000)
 2927072.10000 (2.77037635)         27082.90000 (0.57231684)
 3027072.00000 (0.81770000)         27083.00000 (0.38934000)
 3127071.50000 (0.07194657)         27083.80000 (2.76918992)
 32
 33This can be the basis of an order book based trading strategy where realtime
 34data and fast price movements are considered.
 35"""
 36
 37from __future__ import annotations
 38
 39import asyncio
 40from typing import Any
 41
 42from kraken.spot import OrderbookClientV1
 43
 44
 45class Orderbook(OrderbookClientV1):
 46    """
 47    This is a wrapper class that is used to overload the :func:`on_book_update`
 48    function. It can also be used as a base for trading strategy. Since the
 49    :class:`kraken.spot.OrderbookClientV1` is derived from
 50    :class:`kraken.spot.KrakenSpotWSClientV1` it can also be used to access the
 51    :func:`subscribe` function and any other provided utility.
 52    """
 53
 54    async def on_book_update(
 55        self: Orderbook,
 56        pair: str,
 57        message: list,  # noqa: ARG002
 58    ) -> None:
 59        """
 60        This function is called every time the order book of ``pair`` gets
 61        updated.
 62
 63        The ``pair`` parameter can be used to access the updated order book as
 64        shown in the function body below.
 65
 66        :param pair: The currency pair of the updated order book
 67        :type pair: str
 68        :param message: The message sent by Kraken (not needed in most cases)
 69        :type message: list
 70        """
 71
 72        book: dict[str, Any] = self.get(pair=pair)
 73        bid: list[tuple[str, str]] = list(book["bid"].items())
 74        ask: list[tuple[str, str]] = list(book["ask"].items())
 75
 76        print("Bid         Volume\t\t Ask         Volume")
 77        for level in range(self.depth):
 78            print(
 79                f"{bid[level][0]} ({bid[level][1][0]}) \t {ask[level][0]} ({ask[level][1][0]})",
 80            )
 81        # assert book["valid"]  # ensure that the checksum is valid (will be
 82        # false after reconnect -- but the client handles the removal and
 83        # resubscription of the book)
 84
 85
 86async def main() -> None:
 87    """
 88    Here we depth of the order book and also a pair. We could
 89    subscribe to multiple pairs, but for simplicity only XBT/USD is chosen.
 90
 91    The Orderbook class can be instantiated, which receives the order
 92    book-related messages, after we subscribed to the book feed.
 93
 94    Finally we need some "game loop" - so we create a while loop
 95    that runs as long as there is no error.
 96    """
 97    orderbook: Orderbook = Orderbook()
 98
 99    await orderbook.add_book(
100        pairs=["XBT/USD"],  # we can also subscribe to more currency pairs
101    )
102
103    while not orderbook.exception_occur:
104        await asyncio.sleep(10)
105
106
107if __name__ == "__main__":
108    try:
109        asyncio.run(main())
110    except KeyboardInterrupt:
111        print("KeyboardInterrupt!")

References: - https://gist.github.com/btschwertfeger/6eea0eeff193f7cd1b262cfce4f0eb51