"""策略单次运行所需的公共上下文对象。""" import logging from concurrent.futures import ThreadPoolExecutor from dataclasses import dataclass, field from config import AccountConfig, GlobalConfig, HTTP_TIMEOUT from sdk import Client from libs.grid_take_profit import GridTrailingTracker from libs.http import get_json from libs.order import OrderBook from libs.watch import DipWatch @dataclass(slots=True) class Runtime: """集中保存策略运行期间共享的客户端、配置和内存组件。""" client: Client global_cfg: GlobalConfig account_cfg: AccountConfig orders: OrderBook open_watch: DipWatch add_watch: DipWatch profit_tracker: GridTrailingTracker executor: ThreadPoolExecutor | None = None server_inital: dict[str, list[str]] = field(init=False) def __post_init__(self) -> None: """读取服务端初始化数据,失败时保留空证券列表。""" self.server_inital = {"all_codes": [], "today_pass_codes": []} try: url = f"{self.global_cfg.api_host.rstrip('/')}/a/initial" payload = get_json(url, HTTP_TIMEOUT) if not isinstance(payload, dict) or str(payload.get("code")) != "0": raise ValueError(f"服务端初始化响应失败: {payload!r}") data = payload.get("data") if not isinstance(data, dict): raise ValueError("服务端初始化 data 必须为对象") for key in ("all_codes", "today_pass_codes"): codes = data.get(key) if not isinstance(codes, list) or not all(isinstance(code, str) for code in codes): raise ValueError(f"服务端初始化 {key} 必须为字符串列表") self.server_inital = data except Exception: logging.exception("[初始化] 获取服务端初始化数据失败")