"""Risk guardrails. Generous-but-present defaults for a paper account. These are enforced programmatically in ``execution/guardrails.py`` — the LLM's requested sizing and stop/take levels are inputs that get clamped here, never trusted. """ from __future__ import annotations from pydantic import BaseModel class RiskConfig(BaseModel): max_position_pct: float = 0.10 # cap per single position, % of equity max_symbol_exposure_pct: float = 0.15 # aggregate cap per ticker across all agents max_trades_per_agent: int = 4 # 4 trades/day mandate (one of them an option) # NOTE: plan_orders runs once per persona against its own account, so this "day" cap # acts PER ACCOUNT. Kept equal to the per-agent cap on purpose. max_trades_per_day: int = 4 allow_shorts: bool = True # shorts enabled; persona prompts decide when to use them default_stop_pct: float = 0.07 default_take_pct: float = 0.15 min_price: float = 3.0 # skip sub-$3 names max_price: float | None = None # --- options quality gate (the "high probability" mandate, enforced not just prompted) --- # Premium notional cap per option trade (% of equity). 0.10 so one large-cap 30-45DTE # contract (~$600-1000 premium) fits a $10k book — 0.05 made most contracts qty<1. max_option_weight_pct: float = 0.10 min_option_conviction: float = 0.6 # drop option picks the agent itself isn't sure about DEFAULT_RISK = RiskConfig()