feat(config): expose paper broker tuning via env (REQ-010 AC-5, BAT-009)
Wire the existing PaperBroker scenario knobs (fill_after_polls / qty_per_poll / reject_symbols) to daemon env so REQ-011 AC-2 e2e scenarios (delayed / partial / reject) can be reproduced by a daemon restart. Unset == prior PaperBroker() behaviour, byte-for-byte (no regression). - config.py: PaperBrokerConfig + from_env parsing (TREX_PAPER_*) - daemon.py: _build_broker injects config.paper into PaperBroker - .env.example: document the 3 paper tuning keys (paper-only, e2e) - tests: paper broker defaults + env tuning parsing SDLC: REQ-010 CHG-20260606-01 (AC-5 added) / -02 (Implemented); BAT-009 batch-lite release-candidate; REL-001 feedback handoff records pre-deployment e2e observations incl. event-publisher idle-drop and paper correlation_id collision (GitHub #4, #5). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -40,6 +40,19 @@ class PortfolioHubConfig:
|
||||
timeout: float = 5.0
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class PaperBrokerConfig:
|
||||
"""Paper broker tuning for e2e test scenarios (REQ-011).
|
||||
|
||||
Defaults reproduce immediate, full fills with no rejects, so an unset
|
||||
environment is byte-for-byte the prior `PaperBroker()` behaviour.
|
||||
"""
|
||||
|
||||
fill_after_polls: int = 0
|
||||
qty_per_poll: Optional[int] = None
|
||||
reject_symbols: frozenset[str] = frozenset()
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class RabbitMQConfig:
|
||||
"""RabbitMQ transport adapter config (REQ-022, dcy-006 OQ-6)."""
|
||||
@@ -63,6 +76,8 @@ class DaemonConfig:
|
||||
broker: str # 'paper' | 'kis'
|
||||
execution_interval_sec: float
|
||||
kis: Optional[KISConfig] = None
|
||||
# REQ-011: paper broker tuning (only consulted when broker == 'paper').
|
||||
paper: PaperBrokerConfig = PaperBrokerConfig()
|
||||
# REQ-017/019: ledger writer config (None => in-memory stub ledger,
|
||||
# appropriate for slice-1 paper-broker integration tests).
|
||||
portfolio_hub: Optional[PortfolioHubConfig] = None
|
||||
@@ -93,6 +108,15 @@ class DaemonConfig:
|
||||
allow_live=os.environ.get("TREX_KIS_ALLOW_LIVE", "").lower() in ("1", "true", "yes"),
|
||||
redis_url=os.environ.get("TREX_KIS_REDIS_URL", ""),
|
||||
)
|
||||
qpp_raw = os.environ.get("TREX_PAPER_QTY_PER_POLL", "").strip()
|
||||
reject_raw = os.environ.get("TREX_PAPER_REJECT_SYMBOLS", "")
|
||||
paper = PaperBrokerConfig(
|
||||
fill_after_polls=int(os.environ.get("TREX_PAPER_FILL_AFTER_POLLS", "0")),
|
||||
qty_per_poll=int(qpp_raw) if qpp_raw else None,
|
||||
reject_symbols=frozenset(
|
||||
s.strip() for s in reject_raw.split(",") if s.strip()
|
||||
),
|
||||
)
|
||||
portfolio_hub: Optional[PortfolioHubConfig] = None
|
||||
pf_base = os.environ.get("TREX_PORTFOLIO_HUB_BASE_URL", "").strip()
|
||||
if pf_base:
|
||||
@@ -118,6 +142,7 @@ class DaemonConfig:
|
||||
broker=broker,
|
||||
execution_interval_sec=float(os.environ.get("TREX_EXECUTION_INTERVAL_SEC", "1.0")),
|
||||
kis=kis,
|
||||
paper=paper,
|
||||
portfolio_hub=portfolio_hub,
|
||||
ledger_interval_sec=float(os.environ.get("TREX_LEDGER_INTERVAL_SEC", "1.0")),
|
||||
rabbitmq=rabbitmq,
|
||||
|
||||
@@ -78,7 +78,11 @@ def _build_broker(config: DaemonConfig) -> BrokerPort:
|
||||
base_url=k.base_url, timeout=k.timeout, allow_live=k.allow_live,
|
||||
token_cache=token_cache,
|
||||
)
|
||||
return PaperBroker()
|
||||
return PaperBroker(
|
||||
fill_after_polls=config.paper.fill_after_polls,
|
||||
qty_per_poll=config.paper.qty_per_poll,
|
||||
reject_symbols=set(config.paper.reject_symbols),
|
||||
)
|
||||
|
||||
|
||||
def _build_ledger(config: DaemonConfig) -> LedgerPort:
|
||||
|
||||
Reference in New Issue
Block a user