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

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