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.SpotOrderBookClient uses the websocket API v2.

Sample on how to maintain a valid orderbook w/ websocket API
  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 SpotOrderBookClient
 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(SpotOrderBookClient):
 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.SpotOrderBookClient` is derived from
 59    :class:`kraken.spot.SpotWSClient` 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
108    async with Orderbook(depth=10) as orderbook:
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!")

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