""" Cache key management for Redis operations. """ from typing import Optional from ..utils.logging import get_logger logger = get_logger(__name__) class CacheKeys: """ Centralized cache key management for consistent Redis operations. Provides standardized key patterns for different data types. """ # Key prefixes ORDERBOOK_PREFIX = "ob" HEATMAP_PREFIX = "hm" TRADE_PREFIX = "tr" METRICS_PREFIX = "mt" STATUS_PREFIX = "st" STATS_PREFIX = "stats" # TTL values (seconds) ORDERBOOK_TTL = 60 # 1 minute HEATMAP_TTL = 30 # 30 seconds TRADE_TTL = 300 # 5 minutes METRICS_TTL = 120 # 2 minutes STATUS_TTL = 60 # 1 minute STATS_TTL = 300 # 5 minutes @classmethod def orderbook_key(cls, symbol: str, exchange: str) -> str: """ Generate cache key for order book data. Args: symbol: Trading symbol exchange: Exchange name Returns: str: Cache key """ return f"{cls.ORDERBOOK_PREFIX}:{exchange}:{symbol}" @classmethod def heatmap_key(cls, symbol: str, bucket_size: float = 1.0, exchange: Optional[str] = None) -> str: """ Generate cache key for heatmap data. Args: symbol: Trading symbol bucket_size: Price bucket size exchange: Exchange name (None for consolidated) Returns: str: Cache key """ if exchange: return f"{cls.HEATMAP_PREFIX}:{exchange}:{symbol}:{bucket_size}" else: return f"{cls.HEATMAP_PREFIX}:consolidated:{symbol}:{bucket_size}" @classmethod def trade_key(cls, symbol: str, exchange: str, trade_id: str) -> str: """ Generate cache key for trade data. Args: symbol: Trading symbol exchange: Exchange name trade_id: Trade identifier Returns: str: Cache key """ return f"{cls.TRADE_PREFIX}:{exchange}:{symbol}:{trade_id}" @classmethod def metrics_key(cls, symbol: str, exchange: str) -> str: """ Generate cache key for metrics data. Args: symbol: Trading symbol exchange: Exchange name Returns: str: Cache key """ return f"{cls.METRICS_PREFIX}:{exchange}:{symbol}" @classmethod def status_key(cls, exchange: str) -> str: """ Generate cache key for exchange status. Args: exchange: Exchange name Returns: str: Cache key """ return f"{cls.STATUS_PREFIX}:{exchange}" @classmethod def stats_key(cls, component: str) -> str: """ Generate cache key for component statistics. Args: component: Component name Returns: str: Cache key """ return f"{cls.STATS_PREFIX}:{component}" @classmethod def latest_heatmaps_key(cls, symbol: str) -> str: """ Generate cache key for latest heatmaps list. Args: symbol: Trading symbol Returns: str: Cache key """ return f"{cls.HEATMAP_PREFIX}:latest:{symbol}" @classmethod def symbol_list_key(cls, exchange: str) -> str: """ Generate cache key for symbol list. Args: exchange: Exchange name Returns: str: Cache key """ return f"symbols:{exchange}" @classmethod def price_bucket_key(cls, symbol: str, exchange: str) -> str: """ Generate cache key for price buckets. Args: symbol: Trading symbol exchange: Exchange name Returns: str: Cache key """ return f"buckets:{exchange}:{symbol}" @classmethod def arbitrage_key(cls, symbol: str) -> str: """ Generate cache key for arbitrage opportunities. Args: symbol: Trading symbol Returns: str: Cache key """ return f"arbitrage:{symbol}" @classmethod def get_ttl(cls, key: str) -> int: """ Get appropriate TTL for a cache key. Args: key: Cache key Returns: int: TTL in seconds """ if key.startswith(cls.ORDERBOOK_PREFIX): return cls.ORDERBOOK_TTL elif key.startswith(cls.HEATMAP_PREFIX): return cls.HEATMAP_TTL elif key.startswith(cls.TRADE_PREFIX): return cls.TRADE_TTL elif key.startswith(cls.METRICS_PREFIX): return cls.METRICS_TTL elif key.startswith(cls.STATUS_PREFIX): return cls.STATUS_TTL elif key.startswith(cls.STATS_PREFIX): return cls.STATS_TTL else: return 300 # Default 5 minutes @classmethod def parse_key(cls, key: str) -> dict: """ Parse cache key to extract components. Args: key: Cache key to parse Returns: dict: Parsed key components """ parts = key.split(':') if len(parts) < 2: return {'type': 'unknown', 'key': key} key_type = parts[0] if key_type == cls.ORDERBOOK_PREFIX and len(parts) >= 3: return { 'type': 'orderbook', 'exchange': parts[1], 'symbol': parts[2] } elif key_type == cls.HEATMAP_PREFIX and len(parts) >= 4: return { 'type': 'heatmap', 'exchange': parts[1] if parts[1] != 'consolidated' else None, 'symbol': parts[2], 'bucket_size': float(parts[3]) if len(parts) > 3 else 1.0 } elif key_type == cls.TRADE_PREFIX and len(parts) >= 4: return { 'type': 'trade', 'exchange': parts[1], 'symbol': parts[2], 'trade_id': parts[3] } elif key_type == cls.METRICS_PREFIX and len(parts) >= 3: return { 'type': 'metrics', 'exchange': parts[1], 'symbol': parts[2] } elif key_type == cls.STATUS_PREFIX and len(parts) >= 2: return { 'type': 'status', 'exchange': parts[1] } elif key_type == cls.STATS_PREFIX and len(parts) >= 2: return { 'type': 'stats', 'component': parts[1] } else: return {'type': 'unknown', 'key': key} @classmethod def get_pattern(cls, key_type: str) -> str: """ Get Redis pattern for key type. Args: key_type: Type of key Returns: str: Redis pattern """ patterns = { 'orderbook': f"{cls.ORDERBOOK_PREFIX}:*", 'heatmap': f"{cls.HEATMAP_PREFIX}:*", 'trade': f"{cls.TRADE_PREFIX}:*", 'metrics': f"{cls.METRICS_PREFIX}:*", 'status': f"{cls.STATUS_PREFIX}:*", 'stats': f"{cls.STATS_PREFIX}:*" } return patterns.get(key_type, "*")