__init__.py 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. """TTL-based in-memory cache."""
  2. import threading
  3. import time
  4. from typing import Any, Optional
  5. from config import PRICE_TTL, OHLCV_TTL
  6. class TTLCache:
  7. def __init__(self):
  8. self._store: dict[str, tuple[Any, float]] = {}
  9. self._lock = threading.Lock()
  10. def get(self, key: str) -> Optional[Any]:
  11. with self._lock:
  12. entry = self._store.get(key)
  13. if entry is None:
  14. return None
  15. value, expires_at = entry
  16. if time.time() > expires_at:
  17. del self._store[key]
  18. return None
  19. return value
  20. def set(self, key: str, value: Any, ttl: int) -> None:
  21. with self._lock:
  22. self._store[key] = (value, time.time() + ttl)
  23. def delete(self, key: str) -> None:
  24. with self._lock:
  25. self._store.pop(key, None)
  26. def stats(self) -> dict:
  27. with self._lock:
  28. now = time.time()
  29. alive = sum(1 for _, (_, exp) in self._store.items() if exp > now)
  30. return {"total_keys": len(self._store), "alive_keys": alive}
  31. _cache = TTLCache()
  32. def cache_key_price(symbol: str) -> str:
  33. return f"price:{symbol.upper()}"
  34. def cache_key_ohlcv(symbol: str, timeframe: str) -> str:
  35. return f"ohlcv:{symbol.upper()}:{timeframe}"
  36. def get_cached_price(symbol: str) -> Optional[dict]:
  37. return _cache.get(cache_key_price(symbol))
  38. def set_cached_price(symbol: str, data: dict) -> None:
  39. _cache.set(cache_key_price(symbol), data, ttl=PRICE_TTL)
  40. def get_cached_ohlcv(symbol: str, timeframe: str) -> Optional[dict]:
  41. return _cache.get(cache_key_ohlcv(symbol, timeframe))
  42. def set_cached_ohlcv(symbol: str, timeframe: str, data: dict) -> None:
  43. _cache.set(cache_key_ohlcv(symbol, timeframe), data, ttl=OHLCV_TTL.get(timeframe, 60))
  44. def get_cache_stats() -> dict:
  45. return _cache.stats()