Add dynamic agent registry and options mandate
Introduces a dashboard-managed agent registry (`state/agents.json`) used by nightly research and market-open execution, including support for custom/disabled agents and per-agent time budgets. Expands personas to four agents (adds Maverick), shifts pick targets to include mandatory options, and updates prompts/finalization nudges to enforce option research without hard-failing runs. Strengthens execution safety by adding option-specific guardrails (conviction floor, premium cap, reserved option slot through trade/day/buying-power caps), validates OCC option symbols in schemas, and normalizes invalid option direction cases. The dashboard was refactored into modular views, adds an Agents admin tab, and improves live portfolio visibility with Alpaca-first data and snapshot fallback.
This commit is contained in:
1 parent
b3821abd69
commit
e1ac514f30
36 files changed
+1476
-294
No files matched your search
@@ -6,11 +6,17 @@ it back. Validators enforce basic sanity so garbage never reaches order placemen
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
|
||||
from pydantic import BaseModel, Field, field_validator, model_validator
|
||||
|
||||
# OCC option symbol: ROOT (<=6 chars) + YYMMDD + C/P + strike*1000 as 8 digits,
|
||||
# e.g. AAPL260724C00295000. LLMs sometimes fabricate near-miss symbols; reject them
|
||||
# here so an invented contract can never reach order placement.
|
||||
_OCC_SYMBOL_RE = re.compile(r"^[A-Z.]{1,6}\d{6}[CP]\d{8}$")
|
||||
|
||||
|
||||
class Direction(str, Enum):
|
||||
LONG = "long"
|
||||
@@ -87,9 +93,26 @@ class Pick(BaseModel):
|
||||
if self.instrument == Instrument.OPTION:
|
||||
if not self.contract_symbol:
|
||||
raise ValueError("option pick requires contract_symbol (from get_option_chain)")
|
||||
self.contract_symbol = self.contract_symbol.strip().upper()
|
||||
if not _OCC_SYMBOL_RE.match(self.contract_symbol):
|
||||
raise ValueError(
|
||||
f"contract_symbol '{self.contract_symbol}' is not a valid OCC symbol — "
|
||||
"copy it EXACTLY from get_option_chain output, never construct one"
|
||||
)
|
||||
if (self.option_right or "").lower() not in ("call", "put"):
|
||||
raise ValueError("option pick requires option_right 'call' or 'put'")
|
||||
self.option_right = self.option_right.lower()
|
||||
# We only BUY options. A put marked direction=short is the same bearish bet
|
||||
# expressed sloppily (LLMs do this) — normalize to a long put. A short call has
|
||||
# no long-only equivalent, so reject it outright.
|
||||
if self.direction == Direction.SHORT:
|
||||
if self.option_right == "put":
|
||||
self.direction = Direction.LONG
|
||||
else:
|
||||
raise ValueError(
|
||||
"cannot short a call (selling options unsupported) — express a "
|
||||
"bearish view with a long put instead"
|
||||
)
|
||||
return self
|
||||
|
||||
@model_validator(mode="after")
|
||||
|
||||
Reference in new issue
Block a user