Skip to content

Commit 54f79c6

Browse files
Improve caching (#102)
1 parent f4862b1 commit 54f79c6

18 files changed

Lines changed: 480 additions & 412 deletions

File tree

kraken/base_api/__init__.py

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import json
1212
import time
1313
import urllib.parse
14-
from typing import Any, Dict, List, Optional, Type, Union
14+
from typing import Any, Callable, Dict, List, Optional, Type, Union
1515
from urllib.parse import urljoin
1616
from uuid import uuid1
1717

@@ -20,6 +20,59 @@
2020
from kraken.exceptions import KrakenException
2121

2222

23+
def defined(value: Any) -> bool:
24+
"""Returns ``True`` if ``value`` is not ``None``"""
25+
return value is not None
26+
27+
28+
def ensure_string(parameter_name: str) -> Callable:
29+
"""
30+
This function is intended to be used as decorator
31+
to ensure that a specific parameter is of type string.
32+
33+
.. code-block:: python
34+
:linenos:
35+
:caption: Example
36+
37+
@ensure_string("assets")
38+
@lru_cache()
39+
def get_assets(
40+
self: "Market",
41+
assets: Optional[Union[str, List[str]]] = None,
42+
aclass: Optional[str] = None,
43+
) -> dict:
44+
# If the function was called using
45+
# get_assets(assets=["BTC","USD","ETH"])
46+
# there will be no error because of the non-hashable
47+
# parameters, because the decorator transforms the
48+
# list into: "BTC,USD,ETH"
49+
50+
:param parameter_name: The parameter name to transform into string
51+
:type parameter_name: str
52+
:return: The called function
53+
:rtype: Callable
54+
"""
55+
56+
def decorator(func: Callable) -> Callable:
57+
def wrapper(*args: Any, **kwargs: Any) -> Any:
58+
if parameter_name in kwargs:
59+
value: Any = kwargs[parameter_name]
60+
if isinstance(value, str) or value is None:
61+
pass
62+
elif isinstance(value, list):
63+
kwargs[parameter_name] = ",".join(value)
64+
else:
65+
raise ValueError(
66+
f"{parameter_name} cannot be {type(kwargs[parameter_name])}!"
67+
)
68+
69+
return func(*args, **kwargs)
70+
71+
return wrapper
72+
73+
return decorator
74+
75+
2376
class KrakenErrorHandler:
2477
"""
2578
Class that checks if the response of a request contains error messages and
@@ -313,21 +366,6 @@ def return_unique_id(self: "KrakenBaseSpotAPI") -> str:
313366
"""
314367
return "".join(str(uuid1()).split("-"))
315368

316-
def _to_str_list(self: "KrakenBaseSpotAPI", value: Union[str, list]) -> str:
317-
"""
318-
Converts a list to a comme separated string
319-
320-
:param value: The value to convert to e.g., ["XBT", "USD"] => "XBT,USD"
321-
:type value: Union[str,dict]
322-
:return: The content ov `value` as comma-separated string
323-
:rtype: str
324-
"""
325-
if isinstance(value, str):
326-
return value
327-
if isinstance(value, list):
328-
return ",".join(value)
329-
raise ValueError("a must be type of str or list of strings")
330-
331369
def __enter__(self: "KrakenBaseSpotAPI") -> "KrakenBaseSpotAPI":
332370
return self
333371

kraken/futures/funding/__init__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ class Funding(KrakenBaseFuturesAPI):
4545

4646
def __init__(
4747
self,
48-
key: Optional[str] = "",
49-
secret: Optional[str] = "",
50-
url: Optional[str] = "",
51-
sandbox: Optional[bool] = False,
48+
key: str = "",
49+
secret: str = "",
50+
url: str = "",
51+
sandbox: bool = False,
5252
) -> None:
5353
super().__init__(key=key, secret=secret, url=url, sandbox=sandbox)
5454

kraken/futures/market/__init__.py

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from functools import lru_cache
99
from typing import List, Optional, Union
1010

11-
from ...base_api import KrakenBaseFuturesAPI
11+
from ...base_api import KrakenBaseFuturesAPI, defined
1212

1313

1414
class Market(KrakenBaseFuturesAPI):
@@ -47,10 +47,10 @@ class Market(KrakenBaseFuturesAPI):
4747

4848
def __init__(
4949
self: "Market",
50-
key: Optional[str] = "",
51-
secret: Optional[str] = "",
52-
url: Optional[str] = "",
53-
sandbox: Optional[bool] = False,
50+
key: str = "",
51+
secret: str = "",
52+
url: str = "",
53+
sandbox: bool = False,
5454
) -> None:
5555
super().__init__(key=key, secret=secret, url=url, sandbox=sandbox)
5656

@@ -115,9 +115,9 @@ def get_ohlc(
115115
raise ValueError(f"resolution must be in {resolutions}")
116116

117117
params: dict = {}
118-
if from_ is not None:
118+
if defined(from_):
119119
params["from"] = from_
120-
if to is not None:
120+
if defined(to):
121121
params["to"] = to
122122
return self._request( # type: ignore[return-value]
123123
method="GET",
@@ -134,6 +134,8 @@ def get_tick_types(self: "Market") -> List[str]:
134134
135135
- https://docs.futures.kraken.com/#http-api-charts-ohlc-get-tick-types
136136
137+
This function uses caching. Run ``get_tick_types.cache_clear()`` to clear.
138+
137139
:return: List of available tick types
138140
:rtype: List[str]
139141
@@ -154,6 +156,8 @@ def get_tradeable_products(self: "Market", tick_type: str) -> List[str]:
154156
155157
- https://docs.futures.kraken.com/#http-api-charts-ohlc-get-tradeable-products
156158
159+
This function uses caching. Run ``get_tradeable_products.cache_clear()`` to clear.
160+
157161
:param tick_type: The kind of data, based on ``mark``, ``spot``, or ``trade``
158162
:type tick_type: str
159163
:return: List of tradeable assets
@@ -178,6 +182,8 @@ def get_resolutions(self: "Market", tick_type: str, tradeable: str) -> List[str]
178182
179183
- https://docs.futures.kraken.com/#http-api-charts-ohlc-get-resolutions
180184
185+
This function uses caching. Run ``get_resolutions.cache_clear()`` to clear.
186+
181187
:param tick_type: The kind of data, based on ``mark``, ``spot``, or ``trade``
182188
:type tick_type: str
183189
:param tick_type: The asset of interest
@@ -203,8 +209,11 @@ def get_fee_schedules(self: "Market") -> dict:
203209
Retrieve information about the current fees
204210
205211
- https://docs.futures.kraken.com/#http-api-trading-v3-api-fee-schedules-get-fee-schedules
212+
206213
- https://support.kraken.com/hc/en-us/articles/360049269572-Fee-Schedules
207214
215+
This function uses caching. Run ``get_fee_schedules.cache_clear()`` to clear.
216+
208217
:return: Dictionary containing information about the fees for wide range of tradeable assets
209218
:rtype: dict
210219
@@ -304,7 +313,7 @@ def get_orderbook(self: "Market", symbol: Optional[str] = None) -> dict:
304313
}
305314
"""
306315
params: dict = {}
307-
if symbol is not None:
316+
if defined(symbol):
308317
params["symbol"] = symbol
309318

310319
return self._request( # type: ignore[return-value]
@@ -526,9 +535,9 @@ def get_trade_history(
526535
]
527536
"""
528537
params: dict = {}
529-
if symbol is not None:
538+
if defined(symbol):
530539
params["symbol"] = symbol
531-
if lastTime is not None:
540+
if defined(lastTime):
532541
params["lastTime"] = lastTime
533542
params.update(kwargs)
534543
return self._request( # type: ignore[return-value]
@@ -637,7 +646,7 @@ def set_leverage_preference(
637646
{'result': 'success', 'serverTime': '2023-04-04T05:59:49.576Z'}
638647
"""
639648
params: dict = {"symbol": symbol}
640-
if maxLeverage is not None:
649+
if defined(maxLeverage):
641650
params["maxLeverage"] = maxLeverage
642651

643652
return self._request( # type: ignore[return-value]
@@ -736,15 +745,15 @@ def _get_historical_events(
736745
:type auth: bool
737746
"""
738747
params: dict = {}
739-
if before is not None:
748+
if defined(before):
740749
params["before"] = before
741-
if continuation_token is not None:
750+
if defined(continuation_token):
742751
params["continuation_token"] = continuation_token
743-
if since is not None:
752+
if defined(since):
744753
params["since"] = since
745-
if sort is not None:
754+
if defined(sort):
746755
params["sort"] = sort
747-
if tradeable is not None:
756+
if defined(tradeable):
748757
params["tradeable"] = tradeable
749758
params.update(kwargs)
750759
return self._request( # type: ignore[return-value]

kraken/futures/trade/__init__.py

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from typing import List, Optional, Tuple, Union
1010

11-
from ...base_api import KrakenBaseFuturesAPI
11+
from ...base_api import KrakenBaseFuturesAPI, defined
1212

1313

1414
class Trade(KrakenBaseFuturesAPI):
@@ -46,10 +46,10 @@ class Trade(KrakenBaseFuturesAPI):
4646

4747
def __init__(
4848
self: "Trade",
49-
key: Optional[str] = "",
50-
secret: Optional[str] = "",
51-
url: Optional[str] = "",
52-
sandbox: Optional[bool] = False,
49+
key: str = "",
50+
secret: str = "",
51+
url: str = "",
52+
sandbox: bool = False,
5353
) -> None:
5454
super().__init__(key=key, secret=secret, url=url, sandbox=sandbox)
5555

@@ -93,7 +93,7 @@ def get_fills(self: "Trade", lastFillTime: Optional[str] = None) -> dict:
9393
}
9494
"""
9595
query_params: dict = {}
96-
if lastFillTime:
96+
if defined(lastFillTime):
9797
query_params["lastFillTime"] = lastFillTime
9898
return self._request( # type: ignore[return-value]
9999
method="GET",
@@ -248,7 +248,7 @@ def cancel_all_orders(self: "Trade", symbol: Optional[str] = None) -> dict:
248248
}
249249
"""
250250
params: dict = {}
251-
if symbol is not None:
251+
if defined(symbol):
252252
params["symbol"] = symbol
253253
return self._request( # type: ignore[return-value]
254254
method="POST",
@@ -331,9 +331,9 @@ def cancel_order(
331331
"""
332332

333333
params: dict = {}
334-
if order_id is not None:
334+
if defined(order_id):
335335
params["order_id"] = order_id
336-
elif cliOrdId is not None:
336+
elif defined(cliOrdId):
337337
params["cliOrdId"] = cliOrdId
338338
else:
339339
raise ValueError("Either order_id or cliOrdId must be set!")
@@ -394,18 +394,18 @@ def edit_order(
394394
}
395395
"""
396396
params: dict = {}
397-
if orderId is not None:
397+
if defined(orderId):
398398
params["orderId"] = orderId
399-
elif cliOrdId is not None:
399+
elif defined(cliOrdId):
400400
params["cliOrdId"] = cliOrdId
401401
else:
402402
raise ValueError("Either orderId or cliOrdId must be set!")
403403

404-
if limitPrice is not None:
404+
if defined(limitPrice):
405405
params["limitPrice"] = limitPrice
406-
if size is not None:
406+
if defined(size):
407407
params["size"] = size
408-
if stopPrice is not None:
408+
if defined(stopPrice):
409409
params["stopPrice"] = stopPrice
410410

411411
return self._request( # type: ignore[return-value]
@@ -448,9 +448,9 @@ def get_orders_status(
448448
{'result': 'success', 'serverTime': '2023-04-04T17:27:29.667Z', 'orders': []}
449449
"""
450450
params = {}
451-
if orderIds is not None:
451+
if defined(orderIds):
452452
params["orderIds"] = orderIds
453-
elif cliOrdIds is not None:
453+
elif defined(cliOrdIds):
454454
params["cliOrdIds"] = cliOrdIds
455455

456456
return self._request( # type: ignore[return-value]
@@ -647,22 +647,22 @@ def create_order(
647647
"size": size,
648648
"symbol": symbol,
649649
}
650-
if cliOrdId is not None:
650+
if defined(cliOrdId):
651651
params["cliOrdId"] = cliOrdId
652-
if limitPrice is not None:
652+
if defined(limitPrice):
653653
params["limitPrice"] = limitPrice
654-
if reduceOnly is not None:
654+
if defined(reduceOnly):
655655
params["reduceOnly"] = reduceOnly
656-
if stopPrice is not None:
656+
if defined(stopPrice):
657657
params["stopPrice"] = stopPrice
658-
if triggerSignal is not None:
659-
trigger_signals = ("mark", "spot", "last")
658+
if defined(triggerSignal):
659+
trigger_signals: tuple = ("mark", "spot", "last")
660660
if triggerSignal not in trigger_signals:
661661
raise ValueError(f"Trigger signal must be in [{trigger_signals}]!")
662662
params["triggerSignal"] = triggerSignal
663-
if trailingStopDeviationUnit is not None:
663+
if defined(trailingStopDeviationUnit):
664664
params["trailingStopDeviationUnit"] = trailingStopDeviationUnit
665-
if trailingStopMaxDeviation is not None:
665+
if defined(trailingStopMaxDeviation):
666666
params["trailingStopMaxDeviation"] = trailingStopMaxDeviation
667667

668668
return self._request( # type: ignore[return-value]

0 commit comments

Comments
 (0)