diff --git a/BIONIC_PMS_INTERFACE.md b/BIONIC_PMS_INTERFACE.md index 9dd5303..d5e52d2 100644 --- a/BIONIC_PMS_INTERFACE.md +++ b/BIONIC_PMS_INTERFACE.md @@ -299,3 +299,4 @@ docker compose run --rm --no-deps pms-web python scripts/probe_bionic.py --base |---|---|---| | V1.0 | 2026-08-03 | 首版定稿并双侧落码。择时部分是一套盘中判定规则(资金阈值、动量追买等) | | V1.1 | 2026-08-03 | 按用户审核意见重做择时:删掉 V1.0 的盘中判定规则(违反「提前计算为主、盘中监控为辅、不另做盘中判断、可以接受买不上」),改为由昨夜支撑压力推出执行区间、盘中只做区间比对与当日监控核对;研判留痕不再写 `decision_ledger`(每晚判分全表扫描,已核实);文档与代码注释清理生造词 | +| V1.2 | 2026-09-08 | 量价研判链(《量价研判链吸收方案_2026-09-08》):请求侧硬数字白名单多送 `events_text`、`pricing_text` 两句整句(催化事件与定价状态,事件与量价不是产业逻辑);应答侧新建仓研判可并列多带 `pv_heads`(`h5`、`h20` 各含 `score` −1 到 1、`direction` 看多/中性/看空、`justification`),PMS 归一后进提议硬数字 `judge_pv_heads`,只显示不触发;三值 verdict 口径不变,缺 `pv_heads` 就是 None,向下兼容 | diff --git a/app/services/judge.py b/app/services/judge.py index b3f32af..e84f1e4 100644 --- a/app/services/judge.py +++ b/app/services/judge.py @@ -135,6 +135,26 @@ def _conf_or_none(v): return None +def _pv_heads_or_none(v): + """应答里的 pv_heads 归一: {h5: {score, direction, justification}, h20: {...}}; 评分夹到 -1 到 1, + 两个头都没有评分就是 None。""" + if not isinstance(v, dict): + return None + out = {} + for k in ("h5", "h20"): + h = v.get(k) + if not isinstance(h, dict): + continue + score = _conf_or_none(h.get("score")) + if score is None: + continue + score = max(-1.0, min(1.0, score)) + direction = "看多" if score > 0.2 else ("看空" if score < -0.2 else "中性") + out[k] = {"score": round(score, 3), "direction": direction, + "justification": str(h.get("justification") or "").strip()[:120]} + return out or None + + def _map_verdict(data: dict) -> dict: """把决策系统应答的 verdict 归一到 PASS / REJECT / UNAVAILABLE, 并带出原因与置信度。 @@ -153,16 +173,19 @@ def _map_verdict(data: dict) -> dict: verdict = str(data.get("verdict") or data.get("decision") or "").upper() reason = data.get("reason") or data.get("rationale") or "" conf = _conf_or_none(data.get("confidence")) + # 两个期限的头 (2026-09-08 量价研判链): 决策系统在应答里并列给的 5 日与 20 日判断, 原样带出进提议硬数字, + # 只显示不触发。缺就是 None, 旧应答一个字不用改。 + heads = _pv_heads_or_none(data.get("pv_heads")) if verdict in ("PASS", "APPROVE", "APPROVED", "ALLOW", "通过"): return {"verdict": PASS, "reason": reason, "degraded": False, "raw": data, - "confidence": conf} + "confidence": conf, "pv_heads": heads} if verdict in ("REJECT", "DENY", "DENIED", "BLOCK", "驳回"): return {"verdict": REJECT, "reason": reason, "degraded": False, "raw": data, - "confidence": conf} + "confidence": conf, "pv_heads": heads} if verdict in ("UNAVAILABLE", "PMS_UNAVAILABLE", "NA", "N/A", "不可用"): logger.warning("[研判闸] 决策系统回不可用, 降级人工确认: %s", reason or "(无原因)") return {"verdict": UNAVAILABLE, "reason": reason or "决策系统研判不可用", - "degraded": True, "raw": data, "confidence": conf} + "degraded": True, "raw": data, "confidence": conf, "pv_heads": heads} logger.error("[研判闸] 答复无法识别 (%s), 按不可用降级", verdict or data) return {"verdict": UNAVAILABLE, "reason": f"研判答复无法识别: {verdict or data}", "degraded": True, "raw": data, "confidence": conf} diff --git a/app/services/proposal_service.py b/app/services/proposal_service.py index 9d55211..033612d 100644 --- a/app/services/proposal_service.py +++ b/app/services/proposal_service.py @@ -527,9 +527,12 @@ def _route_one(c, view, params, stock_params, brake_active, now, dry_run, out, out["rejected"].append({"ts_code": code, "action": action, "by": "judge", "failed": [verdict.get("reason") or "决策系统驳回"]}) if not dry_run: + # 驳回也把把握度记进硬数字 (2026-09-08): 低把握驳回转交人那道保险 (PMS_JUDGE_REJECT_CONF_MIN) + # 是否在起作用, 只能从驳回行的把握度分布看出来; 此前只有提议行记它, 驳回行没有, 复核无据。 pms_repo.insert_ledger(ts_code=code, action=action, arbiter="judge", verdict="REJECT", price_at=price, - hard_numbers=c["hard_numbers"], + hard_numbers={**(c["hard_numbers"] or {}), + "judge_conf": verdict.get("confidence")}, reason=verdict.get("reason") or "决策系统驳回") return if verdict.get("degraded"): @@ -737,7 +740,9 @@ def _make_proposal(c, price, verdict) -> str: "source": c.get("source") or ae.SRC_ENGINE, # 研判应答的结论与置信度 (2026-09-03): 人裁决时要看得见决策系统怎么说、有多确定。 # judge_reason 另有一列, 这两项进硬数字是为了随账本走 (采纳/驳回时原样落账)。 - "judge_verdict": verdict.get("verdict"), "judge_conf": verdict.get("confidence")} + "judge_verdict": verdict.get("verdict"), "judge_conf": verdict.get("confidence"), + # 两个期限的头 (2026-09-08 量价研判链): 决策系统并列给的 5 日与 20 日判断, 只显示不触发。 + "judge_pv_heads": verdict.get("pv_heads")} try: pms_repo.insert_proposal( proposal_id=pid, ts_code=c["ts_code"], action=c["action"], qty=c["qty"], diff --git a/app/web/static/index.html b/app/web/static/index.html index b524c8e..126412a 100644 --- a/app/web/static/index.html +++ b/app/web/static/index.html @@ -1034,6 +1034,7 @@ body.dock-r:not(.r-fold) .side-r .strip{display:none;}