← Back
"""
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

📜 Git History

c2258e0feat(of-trader): maker chase + bracket + time-stop lifecycle (chunk 2b)4 weeks ago
Show last diff
Loading...