# -*- coding: utf-8 -*- """择时系统立场合成 (2026-09-11 三源合议, 纯逻辑, 零外部依赖)。 输入是决策系统的昨夜定性 (BUY/WATCH/SELL/AVOID/DROPPED, 或超期/缺) 与当天盘中转多留痕。 规则见《技术面接入与三源合议方案》第四节: 昨夜 BUY 看多, WATCH 中性, SELL/AVOID/DROPPED 看空, 超期或缺无读数。 当天盘中转多留痕把无读数与中性升为看多, 与看空相遇归中性。 立场取值只有: 看多 / 看空 / 中性 / 无读数。无读数是弃权, 绝不折成看空 (设计原则二)。 研判闸不当选票 (设计原则三): 这一票只用昨夜定性与盘中转多留痕, 不重复计入研判结论。 """ from __future__ import annotations _NIGHTLY = {"BUY": "看多", "WATCH": "中性", "SELL": "看空", "AVOID": "看空", "DROPPED": "看空"} def synthesize(nightly, *, intraday_flip_at=None, fresh=True) -> dict: """nightly: 昨夜定性字符串 (BUY 等) 或 None/空; fresh: 昨夜结论是否在有效期内 (超期传 False); intraday_flip_at: 当天盘中转多留痕的时刻字符串, 没有传 None。""" n = str(nightly or "").strip().upper() base = _NIGHTLY.get(n, "中性") if (n and fresh) else "无读数" stance = base if intraday_flip_at: # 当天盘中转多留痕 if base in ("无读数", "中性"): stance = "看多" elif base == "看空": stance = "中性" # 盘中转多与昨夜看空相遇, 归中性 # base 已是看多则维持看多 return {"stance": stance, "nightly": (n or None), "fresh": bool(fresh), "intraday_flip_at": intraday_flip_at, "no_read_why": ("没有昨夜结论或已超期" if stance == "无读数" else None)}