"""Daily Redis counters for trade-cap + alloc-cap + pause flag.""" from __future__ import annotations from datetime import datetime, timezone from decimal import Decimal from typing import Any class KevinRiskCounters: _PAUSE_KEY = "trading:paused" _TRADES_KEY = "kevin:daily_trades:{date}" _ALLOC_KEY = "kevin:daily_alloc:{date}" def __init__(self, redis: Any) -> None: self.redis = redis @staticmethod def _today_utc() -> str: return datetime.now(timezone.utc).strftime("%Y%m%d") async def get_daily_trades(self) -> int: v = await self.redis.get(self._TRADES_KEY.format(date=self._today_utc())) if v is None: return 0 return int(v) async def increment_daily_trades(self) -> int: key = self._TRADES_KEY.format(date=self._today_utc()) n = await self.redis.incr(key) await self.redis.expire(key, 172800) # 48h return int(n) async def get_daily_alloc(self) -> Decimal: v = await self.redis.get(self._ALLOC_KEY.format(date=self._today_utc())) if v is None: return Decimal("0") s = v.decode() if isinstance(v, bytes) else str(v) return Decimal(s) async def add_daily_alloc(self, usd: Decimal) -> Decimal: key = self._ALLOC_KEY.format(date=self._today_utc()) new = await self.redis.incrbyfloat(key, float(usd)) await self.redis.expire(key, 172800) return Decimal(str(new)) async def is_trading_paused(self) -> bool: return bool(await self.redis.get(self._PAUSE_KEY)) async def set_trading_paused(self, ttl_seconds: int | None = None) -> None: if ttl_seconds: await self.redis.set(self._PAUSE_KEY, "1", ex=ttl_seconds) else: await self.redis.set(self._PAUSE_KEY, "PERMANENT")