Spot Websocket

The examples presented below serve to demonstrate the usage of the Spot websocket clients provided by python-kraken-sdk to access Kraken’s Websocket API v2.

For questions, feedback, additions, suggestions for improvement or problems python-kraken-sdk/discussions or python-kraken-sdk/issues may be helpful.

Example access and usage for Kraken Spot Websocket API
  1# !/usr/bin/env python3
  2# -*- mode: python; coding: utf-8 -*-
  3#
  4# Copyright (C) 2023 Benjamin Thomas Schwertfeger
  5# All rights reserved.
  6# https://github.com/btschwertfeger
  7#
  8# SPDX-License-Identifier: Apache-2.0
  9#
 10
 11"""
 12Module that provides an example usage for the KrakenSpotWebsocketClient.
 13It uses the Kraken Websocket API v2.
 14"""
 15
 16from __future__ import annotations
 17
 18import asyncio
 19import logging
 20import os
 21
 22from kraken.spot import SpotWSClient
 23
 24logging.basicConfig(
 25    format="%(asctime)s %(module)s,line: %(lineno)d %(levelname)8s | %(message)s",
 26    datefmt="%Y/%m/%d %H:%M:%S",
 27    level=logging.INFO,
 28)
 29logging.getLogger("requests").setLevel(logging.WARNING)
 30logging.getLogger("urllib3").setLevel(logging.WARNING)
 31
 32clients = []
 33
 34
 35class Client(SpotWSClient):
 36    """Can be used to create a custom trading strategy"""
 37
 38    async def on_message(self: Client, message: dict) -> None:
 39        """Receives the websocket messages"""
 40        if message.get("method") == "pong" or message.get("channel") == "heartbeat":
 41            return
 42
 43        print(message)
 44        # now you can access lots of methods, for example to create an order:
 45        # if self._is_auth:  # only if the client is authenticated …
 46        #     await self.send_message(
 47        #         message={
 48        #             "method": "add_order",
 49        #             "params": {
 50        #                 "limit_price": 1234.56,
 51        #                 "order_type": "limit",
 52        #                 "order_userref": 123456789,
 53        #                 "order_qty": 1.0,
 54        #                 "side": "buy",
 55        #                 "symbol": "BTC/USD",
 56        #                 "validate": True,
 57        #             },
 58        #         }
 59        #     )
 60        # ... it is also possible to call regular REST endpoints
 61        # but using the websocket messages is more efficient.
 62        # You can also un-/subscribe here using self.subscribe/self.unsubscribe.
 63
 64
 65async def main() -> None:
 66    key: str = os.getenv("SPOT_API_KEY")
 67    secret: str = os.getenv("SPOT_SECRET_KEY")
 68
 69    try:
 70        # Public/unauthenticated websocket client
 71        client: Client = Client()  # only use this one if you don't need private feeds
 72        clients.append(client)
 73        await client.start()
 74        # print(client.public_channel_names)  # list public subscription names
 75
 76        await client.subscribe(
 77            params={"channel": "ticker", "symbol": ["BTC/USD", "DOT/USD"]},
 78        )
 79        await client.subscribe(
 80            params={"channel": "book", "depth": 25, "symbol": ["BTC/USD"]},
 81        )
 82        # await client.subscribe(params={"channel": "ohlc", "symbol": ["BTC/USD"]})
 83        await client.subscribe(
 84            params={
 85                "channel": "ohlc",
 86                "interval": 15,
 87                "snapshot": False,
 88                "symbol": ["BTC/USD", "DOT/USD"],
 89            },
 90        )
 91        await client.subscribe(params={"channel": "trade", "symbol": ["BTC/USD"]})
 92
 93        # wait because unsubscribing is faster than unsubscribing ... (just for that example)
 94        await asyncio.sleep(3)
 95        # print(client.active_public_subscriptions) # … to list active subscriptions
 96        await client.unsubscribe(
 97            params={"channel": "ticker", "symbol": ["BTC/USD", "DOT/USD"]},
 98        )
 99        # ...
100
101        if key and secret:
102            # Per default, the authenticated client starts two websocket connections,
103            # one for authenticated and one for public messages. If there is no need
104            # for a public connection, it can be disabled using the ``no_public``
105            # parameter.
106            client_auth = Client(key=key, secret=secret, no_public=True)
107            clients.append(client_auth)
108            await client_auth.start()
109            # print(client_auth.private_channel_names)  # … list private channel names
110            # when using the authenticated client, you can also subscribe to public feeds
111            await client_auth.subscribe(params={"channel": "executions"})
112
113            await asyncio.sleep(5)
114            await client_auth.unsubscribe(params={"channel": "executions"})
115
116        while not client.exception_occur:  # and not client_auth.exception_occur:
117            await asyncio.sleep(6)
118    finally:
119        # Stop the sessions properly.
120        for open_client in clients:
121            await open_client.close()
122
123
124if __name__ == "__main__":
125    asyncio.run(main())
126
127# ============================================================
128# Alternative - as ContextManager:
129
130# from kraken.spot import SpotWSClient
131# import asyncio
132
133
134# async def on_message(message: dict) -> None:
135#     print(message)
136
137
138# async def main() -> None:
139#     async with SpotWSClient(callback=on_message) as session:
140#         await session.subscribe(params={"channel": "ticker", "symbol": ["BTC/USD"]})
141
142#     while True:
143#         await asyncio.sleep(6)
144
145
146# if __name__ == "__main__":
147#     try:
148#         asyncio.run(main())
149#     except KeyboardInterrupt:
150#         pass