Maintain a valid Spot order book

The following example demonstrate how to use the python-kraken-sdk to retrieve a valid realtime order book. Please see the following example snippet for more information.

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

  1#!/usr/bin/env python
  2# -*- coding: utf-8 -*-
  3# Copyright (C) 2023 Benjamin Thomas Schwertfeger
  4# GitHub: https://github.com/btschwertfeger
  5#
  6
  7"""
  8This module provides an example on how to use the Spot Orderbook
  9client of the python-kraken-sdk (https://github.com/btschwertfeger/python-kraken-sdk)
 10to retrieve and maintain a valid Spot order book for (a) specific
 11asset pair(s). It can be run directly without any credentials if the
 12python-kraken-sdk is installed.
 13
 14    python3 -m pip install python-kraken-sdk
 15
 16The output when running this snippet looks like the following table and
 17updates the book as soon as Kraken sent any order book update.
 18
 19Bid         Volume               Ask         Volume
 2027076.00000 (8.28552127)         27076.10000 (2.85897056)
 2127075.90000 (3.75748052)         27077.30000 (0.57243521)
 2227074.40000 (0.57249652)         27080.80000 (0.00100000)
 2327072.90000 (0.01200917)         27081.00000 (0.00012345)
 2427072.80000 (0.25000000)         27081.70000 (0.30000000)
 2527072.30000 (4.89735970)         27082.70000 (0.05539777)
 2627072.20000 (2.65896716)         27082.80000 (0.00400000)
 2727072.10000 (2.77037635)         27082.90000 (0.57231684)
 2827072.00000 (0.81770000)         27083.00000 (0.38934000)
 2927071.50000 (0.07194657)         27083.80000 (2.76918992)
 30
 31This can be the basis of an order book based trading strategy where
 32realtime data and fast price movements are considered.
 33"""
 34
 35from __future__ import annotations
 36
 37import asyncio
 38from typing import Any, Dict, List, Tuple
 39
 40from kraken.spot import OrderbookClient
 41
 42
 43class Orderbook(OrderbookClient):
 44    """
 45    This is a wrapper class that is used to overload the :func:`on_book_update`
 46    function. It can also be used as a base for trading strategy. Since the
 47    :class:`OrderbookClient` is derived from :class:`KrakenSpotWSClient`
 48    it can also be used to access the :func:`subscribe` function and any
 49    other provided utility.
 50    """
 51
 52    async def on_book_update(self: "Orderbook", pair: str, message: list) -> None:
 53        """
 54        This function is called every time the order book of ``pair`` gets
 55        updated.
 56
 57        The ``pair`` parameter can be used to access the updated order book
 58        as shown in the function body below.
 59
 60        :param pair: The currency pair of the updated order book
 61        :type pair: str
 62        :param message: The message sent by Kraken (not needed in most cases)
 63        :type message: list
 64        """
 65        book: Dict[str, Any] = self.get(pair=pair)
 66        bid: List[Tuple[str, str]] = list(book["bid"].items())
 67        ask: List[Tuple[str, str]] = list(book["ask"].items())
 68
 69        print("Bid         Volume\t\t Ask         Volume")
 70        for level in range(self.depth):
 71            print(
 72                f"{bid[level][0]} ({bid[level][1][0]}) \t {ask[level][0]} ({ask[level][1][0]})"
 73            )
 74
 75        assert book["valid"]  # ensure that the checksum is valid
 76
 77
 78async def main() -> None:
 79    """
 80    Here we depth of the order book and also a pair. We could
 81    subscribe to multiple pairs, but for simplicity only XBT/USD is chosen.
 82
 83    The Orderbook class can be instantiated, which receives the order
 84    book-related messages, after we subscribed to the book feed.
 85
 86    Finally we need some "game loop" - so we create a while loop
 87    that runs as long as there is no error.
 88    """
 89    orderbook: Orderbook = Orderbook()
 90
 91    await orderbook.add_book(
 92        pairs=["XBT/USD"]  # we can also subscribe to more currency pairs
 93    )
 94
 95    while not orderbook.exception_occur:
 96        await asyncio.sleep(10)
 97
 98
 99if __name__ == "__main__":
100    try:
101        asyncio.run(main())
102    except KeyboardInterrupt:
103        pass