# -*- coding: utf-8 -*- """三源合议与路由 (2026-09-11, 纯逻辑, 零外部依赖)。 三票 (基本面 / 技术面 / 择时系统) 各是看多/看空/中性/无读数之一, 合成方向再定路由。 方案第四节的合议规则 (台账 009): 三票多数决定方向; 无读数弃权不计; 平局中性; 只有一方表态算弱; 三方一致算强。 路由表见方案附录丙。方向词与合议词一律中文原文, 取值只有看多/看空/中性/无读数。 """ from __future__ import annotations _BULL, _BEAR, _NEUT, _NA = "看多", "看空", "中性", "无读数" def _reason(fund, tech, timing, direction, strength): head = "、".join([f"基本面{fund}", f"技术面{tech}", f"择时{timing}"]) return head + " → " + direction + (("·" + strength) if strength else "") def _route(fund, tech, timing, direction, tech_phase, fund_required): """附录丙路由表, 从上到下第一个命中。返回 (路由, 原因)。路由取值: 放行/观察/交人/跳过。""" if fund_required and fund == _NA: return "跳过", "没有买方评析" if direction == _BEAR: return "跳过", f"方向看空(基本面{fund}、技术面{tech}、择时{timing})" if direction == _NEUT and tech_phase == "收口等待" and fund != _BEAR: return "观察", "等技术面开口" if direction == _NEUT and fund == _BULL and tech == _BEAR: return "观察", "等技术面转向" if fund == _BEAR and tech == _BULL: return "交人", "基本面看空、技术面看多,试探仓" if direction == _BULL: voiced = [v for v in (fund, tech, timing) if v in (_BULL, _BEAR)] if timing == _BEAR: # 异议在择时系统 return "交人", "方向看多但择时系统有异议" if len(voiced) <= 1: # 只有一方表态 return "交人", "方向看多但只有一方表态" return "放行", "方向看多" # 看多强, 或异议只在技术面 if fund == _NA and tech == _NA and timing == _NA: return "放行", "三方都无读数,机械方案" return "观察", "方向中性" def decide(fund, tech, timing, *, tech_phase=None, fund_required=True) -> dict: """fund/tech/timing 是三个立场字符串 (看多/看空/中性/无读数)。tech_phase 是技术面相位 (收口等待 等), 路由用。fund_required: 无买方评析是否拦 (开关 PMS_FUND_REQUIRED)。""" votes = {"fund": fund, "tech": tech, "timing": timing} voiced = [v for v in (fund, tech, timing) if v in (_BULL, _BEAR)] bulls = sum(1 for v in voiced if v == _BULL) bears = sum(1 for v in voiced if v == _BEAR) # ---- 方向: 多数决, 无读数弃权不计, 平局中性 ---- if bulls > bears: direction = _BULL elif bears > bulls: direction = _BEAR else: direction = _NEUT # ---- 强弱: 只有一方表态弱, 三方一致强, 其余 (两方表态) 为中 ---- if direction == _NEUT: strength = None elif len(voiced) <= 1: strength = "弱" elif bulls == 3 or bears == 3: strength = "强" else: strength = "中" route, route_reason = _route(fund, tech, timing, direction, tech_phase, fund_required) return {"direction": direction, "votes": votes, "strength": strength, "reason": _reason(fund, tech, timing, direction, strength), "route": route, "route_reason": route_reason}