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