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