126 lines
4.4 KiB
Python
126 lines
4.4 KiB
Python
"""Daemon configuration resolution (REQ-005, REQ-010, REQ-012/013)."""
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
from dataclasses import dataclass
|
|
from typing import Optional
|
|
|
|
|
|
def _load_dotenv() -> None:
|
|
"""Best-effort load of a .env file into os.environ (REQ-010).
|
|
|
|
Real OS environment variables take precedence over .env (override=False),
|
|
matching 12-factor expectations. If python-dotenv is not installed or no
|
|
.env exists, this is a no-op (no regression).
|
|
"""
|
|
try:
|
|
from dotenv import find_dotenv, load_dotenv
|
|
except ImportError: # pragma: no cover - optional at runtime
|
|
return
|
|
load_dotenv(find_dotenv(usecwd=True), override=False)
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class KISConfig:
|
|
base_url: str
|
|
app_key: str
|
|
app_secret: str
|
|
account_ref: str
|
|
timeout: float
|
|
allow_live: bool
|
|
redis_url: str = "" # REQ-016: optional token cache backend
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class PortfolioHubConfig:
|
|
"""portfolio-hub ledger adapter config (REQ-017)."""
|
|
|
|
base_url: str
|
|
token: str = ""
|
|
timeout: float = 5.0
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class RabbitMQConfig:
|
|
"""RabbitMQ transport adapter config (REQ-022, dcy-006 OQ-6)."""
|
|
|
|
url: str
|
|
timeout: float = 5.0
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class SnapshotScheduleConfig:
|
|
"""Daily snapshot refresh schedule (REQ-030)."""
|
|
|
|
kst_time: str = "07:30"
|
|
tick_sec: float = 60.0
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class DaemonConfig:
|
|
dsn: str
|
|
total_slots: int
|
|
broker: str # 'paper' | 'kis'
|
|
execution_interval_sec: float
|
|
kis: Optional[KISConfig] = None
|
|
# REQ-017/019: ledger writer config (None => in-memory stub ledger,
|
|
# appropriate for slice-1 paper-broker integration tests).
|
|
portfolio_hub: Optional[PortfolioHubConfig] = None
|
|
ledger_interval_sec: float = 1.0
|
|
# REQ-022 (BAT-007): RabbitMQ transport config. Required by the new
|
|
# sync+thread daemon — HTTP API has been removed (REQ-025).
|
|
rabbitmq: Optional[RabbitMQConfig] = None
|
|
# REQ-030 (BAT-008): daily snapshot refresh.
|
|
snapshot_schedule: SnapshotScheduleConfig = SnapshotScheduleConfig()
|
|
|
|
@staticmethod
|
|
def from_env() -> "DaemonConfig":
|
|
_load_dotenv()
|
|
dsn = os.environ.get("TREX_POSTGRESQL_DSN")
|
|
if not dsn:
|
|
raise RuntimeError(
|
|
"TREX_POSTGRESQL_DSN is required to start the slot-core daemon."
|
|
)
|
|
broker = os.environ.get("TREX_BROKER", "paper").strip().lower()
|
|
kis: Optional[KISConfig] = None
|
|
if broker == "kis":
|
|
kis = KISConfig(
|
|
base_url=os.environ["TREX_KIS_BROKER_BASE_URL"],
|
|
app_key=os.environ["TREX_KIS_BROKER_APP_KEY"],
|
|
app_secret=os.environ["TREX_KIS_BROKER_APP_SECRET"],
|
|
account_ref=os.environ["TREX_KIS_BROKER_ACCOUNT_REF"],
|
|
timeout=float(os.environ.get("TREX_KIS_BROKER_TIMEOUT", "5")),
|
|
allow_live=os.environ.get("TREX_KIS_ALLOW_LIVE", "").lower() in ("1", "true", "yes"),
|
|
redis_url=os.environ.get("TREX_KIS_REDIS_URL", ""),
|
|
)
|
|
portfolio_hub: Optional[PortfolioHubConfig] = None
|
|
pf_base = os.environ.get("TREX_PORTFOLIO_HUB_BASE_URL", "").strip()
|
|
if pf_base:
|
|
portfolio_hub = PortfolioHubConfig(
|
|
base_url=pf_base,
|
|
token=os.environ.get("TREX_PORTFOLIO_HUB_TOKEN", "").strip(),
|
|
timeout=float(os.environ.get("TREX_PORTFOLIO_HUB_TIMEOUT", "5")),
|
|
)
|
|
rabbitmq: Optional[RabbitMQConfig] = None
|
|
mq_url = os.environ.get("TREX_RABBITMQ_URL", "").strip()
|
|
if mq_url:
|
|
rabbitmq = RabbitMQConfig(
|
|
url=mq_url,
|
|
timeout=float(os.environ.get("TREX_RABBITMQ_TIMEOUT", "5")),
|
|
)
|
|
snapshot_schedule = SnapshotScheduleConfig(
|
|
kst_time=os.environ.get("TREX_SNAPSHOT_SCHEDULE_KST", "07:30").strip() or "07:30",
|
|
tick_sec=float(os.environ.get("TREX_SNAPSHOT_TICK_SEC", "60")),
|
|
)
|
|
return DaemonConfig(
|
|
dsn=dsn,
|
|
total_slots=int(os.environ.get("TREX_TOTAL_SLOTS", "10")),
|
|
broker=broker,
|
|
execution_interval_sec=float(os.environ.get("TREX_EXECUTION_INTERVAL_SEC", "1.0")),
|
|
kis=kis,
|
|
portfolio_hub=portfolio_hub,
|
|
ledger_interval_sec=float(os.environ.get("TREX_LEDGER_INTERVAL_SEC", "1.0")),
|
|
rabbitmq=rabbitmq,
|
|
snapshot_schedule=snapshot_schedule,
|
|
)
|