"""Redis-backed per-symbol blocklist with TTL. Set on AVOID mentions. Subsequent BUY mention on the same symbol clears the entry (handled by the strategy callsite, not here). """ from __future__ import annotations from typing import Any class KevinBlocklist: _KEY_PREFIX = "kevin:blocked:" def __init__(self, redis: Any) -> None: self.redis = redis async def add(self, symbol: str, ttl_days: int) -> None: await self.redis.set( f"{self._KEY_PREFIX}{symbol}", "1", ex=ttl_days * 86400, ) async def remove(self, symbol: str) -> None: await self.redis.delete(f"{self._KEY_PREFIX}{symbol}") async def is_blocked(self, symbol: str) -> bool: return bool(await self.redis.exists(f"{self._KEY_PREFIX}{symbol}")) async def active_set(self) -> set[str]: keys = await self.redis.keys(f"{self._KEY_PREFIX}*") out: set[str] = set() for k in keys: key_str = k.decode() if isinstance(k, bytes) else k out.add(key_str.replace(self._KEY_PREFIX, "")) return out