"""
RiskGate — lean pre-trade gate for OF-Trader.
=============================================
Three checks (kept deliberately small vs grid's session RiskManager):
1. kill-switch file present → block everything
2. concurrent positions cap
3. per-trade notional cap
4. daily realized-loss limit (USD)
Daily loss is in-memory and resets on restart (acceptable while DRY_RUN).
"""
import logging
import os
from src.config import (
MAX_CONCURRENT_POSITIONS, MAX_NOTIONAL_USD, DAILY_LOSS_LIMIT_USD,
KILL_SWITCH_FILE,
)
logger = logging.getLogger("risk")
class RiskGate:
def __init__(self):
self.daily_loss_usd = 0.0 # accumulated realized loss today (positive number)
def can_open(self, open_count, notional):
if os.path.exists(KILL_SWITCH_FILE):
return False, "kill_switch"
if open_count >= MAX_CONCURRENT_POSITIONS:
return False, "max_positions"
if notional > MAX_NOTIONAL_USD:
return False, "notional_cap"
if self.daily_loss_usd >= DAILY_LOSS_LIMIT_USD:
return False, "daily_loss_limit"
return True, "ok"
def record_close(self, pnl_usd):
"""Track realized loss for the daily limit."""
if pnl_usd < 0:
self.daily_loss_usd += abs(pnl_usd)
logger.info(
f"Daily loss: ${self.daily_loss_usd:.2f}/${DAILY_LOSS_LIMIT_USD:.0f}"
)
def reset_daily(self):
self.daily_loss_usd = 0.0