54 lines
1.8 KiB
Python
54 lines
1.8 KiB
Python
"""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")
|