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