Skip to content

Commit 606c626

Browse files
Add basic tests for xstocks feature
1 parent 3f9d21b commit 606c626

File tree

5 files changed

+151
-9
lines changed

5 files changed

+151
-9
lines changed

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ markers = [
9494
"wip: Used to run a specific test by hand.",
9595
"flaky: Flaky tests",
9696
"spot: Spot endpoint.",
97+
"xstocks: Spot xStocks endpoint.",
9798
"spot_auth: Private Spot endpoint.",
9899
"spot_earn: Spot Earn endpoint.",
99100
"spot_trade: Spot Trade endpoint.",

src/kraken/base_api/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,9 @@ class SpotClient:
191191
This class is the base for all Spot clients, handles un-/signed requests and
192192
returns exception handled results.
193193
194+
With this class you can easily interact with the Kraken Spot API, including
195+
trading Spot crypto assets, xStocks, and margin trading.
196+
194197
If you are facing timeout errors on derived clients, you can make use of the
195198
``TIMEOUT`` attribute to deviate from the default ``10`` seconds.
196199

tests/futures/test_futures_trade.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from collections.abc import Generator
1111
from contextlib import suppress
1212
from time import sleep
13-
from typing import Any, Self
13+
from typing import Any, ClassVar, Self
1414

1515
import pytest
1616

@@ -58,13 +58,10 @@ class TestFuturesTrade:
5858
REDUCE_ONLY = True
5959
PROCESS_BEFORE = "3033-11-08T19:56:35.441899Z"
6060
LAST_FILL_TIME = "2020-07-21T12:41:52.790Z"
61-
TEST_ORDER_IDS = None
62-
63-
def __init__(self) -> None:
64-
self.TEST_ORDER_IDS = [
65-
"bcaaefce-27a3-44b4-b13a-19df21e3f087",
66-
"685d5a1a-23eb-450c-bf17-1e4ab5c6fe8a",
67-
]
61+
TEST_ORDER_IDS: ClassVar[list[str]] = [
62+
"bcaaefce-27a3-44b4-b13a-19df21e3f087",
63+
"685d5a1a-23eb-450c-bf17-1e4ab5c6fe8a",
64+
]
6865

6966
def _assert_successful_response(self: Self, result: Any) -> None:
7067
"""Helper method to assert a successful response."""

tests/spot/conftest.py

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,20 @@
1313

1414
import pytest
1515

16-
from kraken.spot import Earn, Funding, Market, Trade, User
16+
from kraken.spot import Earn, Funding, Market, SpotClient, Trade, User
1717

1818
SPOT_API_KEY: str = os.getenv("SPOT_API_KEY")
1919
SPOT_SECRET_KEY: str = os.getenv("SPOT_SECRET_KEY")
20+
XSTOCKS_API_KEY: str = os.getenv("XSTOCKS_API_KEY")
21+
XSTOCKS_SECRET_KEY: str = os.getenv("XSTOCKS_SECRET_KEY")
22+
XSTOCKS_API_URL: str = os.getenv(
23+
"XSTOCKS_API_URL",
24+
"https://api.vip.uat.lobster.kraken.com",
25+
)
2026

2127

28+
# ==============================================================================
29+
# Spot Crypto
2230
@pytest.fixture(scope="session")
2331
def spot_api_key() -> str:
2432
"""Returns the Kraken Spot API Key for testing."""
@@ -93,3 +101,45 @@ def spot_auth_funding() -> Funding:
93101
Fixture providing an authenticated Spot funding client.
94102
"""
95103
return Funding(key=SPOT_API_KEY, secret=SPOT_SECRET_KEY)
104+
105+
106+
# ==============================================================================
107+
# Spot xStocks
108+
@pytest.fixture(scope="session")
109+
def xstocks_api_key() -> str:
110+
"""Returns the Kraken xStocks API Key for testing."""
111+
return XSTOCKS_API_KEY
112+
113+
114+
@pytest.fixture(scope="session")
115+
def xstocks_secret_key() -> str:
116+
"""Returns the Kraken xStocks API secret for testing."""
117+
return XSTOCKS_SECRET_KEY
118+
119+
120+
@pytest.fixture(scope="session")
121+
def xstocks_client() -> SpotClient:
122+
"""
123+
Fixture providing an authenticated Spot client.
124+
"""
125+
return SpotClient(
126+
key=XSTOCKS_API_KEY,
127+
secret=XSTOCKS_SECRET_KEY,
128+
url=XSTOCKS_API_URL,
129+
)
130+
131+
132+
@pytest.fixture(scope="session")
133+
def xstocks_market_client() -> SpotClient:
134+
"""
135+
Fixture providing an authenticated Spot client.
136+
"""
137+
return Market(key=XSTOCKS_API_KEY, secret=XSTOCKS_SECRET_KEY, url=XSTOCKS_API_URL)
138+
139+
140+
@pytest.fixture(scope="session")
141+
def xstocks_trade_client() -> SpotClient:
142+
"""
143+
Fixture providing an authenticated Spot client.
144+
"""
145+
return Trade(key=XSTOCKS_API_KEY, secret=XSTOCKS_SECRET_KEY, url=XSTOCKS_API_URL)

tests/spot/test_xstocks_basic.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# -*- mode: python; coding: utf-8 -*-
2+
#
3+
# Copyright (C) 2025 Benjamin Thomas Schwertfeger
4+
# All rights reserved.
5+
# https://github.com/btschwertfeger
6+
#
7+
8+
"""Module that implements the unit tests for the Spot xStocks features."""
9+
10+
from typing import ClassVar, Self
11+
12+
import pytest
13+
14+
from kraken.spot import Market, SpotClient, Trade
15+
16+
17+
@pytest.mark.spot
18+
@pytest.mark.xstocks
19+
class TestSpotXStocks:
20+
"""Test class for Spot xStocks client functionality."""
21+
22+
SAVE_ORDER: ClassVar[dict[str, str]] = {
23+
"pair": "AAPLxUSD",
24+
"ordertype": "limit",
25+
"volume": "1",
26+
"price": "100.0",
27+
"validate": True,
28+
}
29+
30+
def test_get_asset_pairs_market_client(
31+
self: Self,
32+
xstocks_market_client: Market,
33+
) -> None:
34+
"""
35+
Checks the ``get_asset_pairs`` endpoint by performing a valid request
36+
and validating that the response does not contain the error key.
37+
"""
38+
# internal exception handling would catch any errors
39+
result = xstocks_market_client.get_asset_pairs(
40+
extra_params={"aclass_base": "tokenized_asset"},
41+
)
42+
assert isinstance(result, dict), result
43+
44+
def test_get_asset_pairs_spot_client(
45+
self: Self,
46+
xstocks_client: SpotClient,
47+
) -> None:
48+
"""
49+
Checks the ``get_asset_pairs`` endpoint by performing a valid request
50+
and validating that the response does not contain the error key.
51+
"""
52+
# internal exception handling would catch any errors
53+
result = xstocks_client.request(
54+
"GET",
55+
"/0/public/AssetPairs",
56+
params={"aclass_base": "tokenized_asset"},
57+
auth=False,
58+
)
59+
assert isinstance(result, dict), result
60+
61+
@pytest.mark.spot_auth
62+
def test_create_order_trade_client(
63+
self: Self,
64+
xstocks_trade_client: Trade,
65+
) -> None:
66+
"""
67+
Checks if the response of the ``create_order`` is of type dict which
68+
mean that the request was successful.
69+
"""
70+
result = xstocks_trade_client.create_order(
71+
**self.SAVE_ORDER,
72+
side="buy",
73+
extra_params={"asset_class": "tokenized_asset"},
74+
)
75+
assert "AAPLxUSD" in result.get("descr", {}).get("order", "")
76+
77+
@pytest.mark.spot_auth
78+
def test_create_order_spot_client(
79+
self: Self,
80+
xstocks_client: SpotClient,
81+
) -> None:
82+
"""
83+
Checks if the response of the ``create_order`` is of type dict which
84+
mean that the request was successful.
85+
"""
86+
result = xstocks_client.request(
87+
"POST",
88+
"/0/private/AddOrder",
89+
params={"type": "buy", "asset_class": "tokenized_asset"} | self.SAVE_ORDER,
90+
)
91+
assert "AAPLxUSD" in result.get("descr", {}).get("order", "")

0 commit comments

Comments
 (0)