tradingSystem/app/core/consensus.py

73 lines
3.4 KiB
Python
Raw Normal View History

# -*- 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}