From ab09154594aa2f13ad19e7ac8baba55e475e96b5 Mon Sep 17 00:00:00 2001 From: zlt Date: Mon, 7 Sep 2026 16:35:29 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8E=A5=E5=8F=A3=20/logic=5Fstate=20=E9=9A=8F?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E5=9B=9E=E5=AE=89=E5=85=A8=E8=BE=B9=E9=99=85?= =?UTF-8?q?=E4=B8=89=E6=83=85=E6=99=AF=EF=BC=88=E6=8C=81=E4=BB=93=E9=A1=B5?= =?UTF-8?q?=E5=8F=82=E8=80=83=E7=9B=AE=E6=A0=87=E4=BB=B7=E7=94=A8=EF=BC=9B?= =?UTF-8?q?=E7=AE=97=E5=A4=B1=E8=B4=A5=E4=B8=8D=E6=8B=96=E5=9E=AE=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E6=9F=A5=E8=AF=A2=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api.py | 11 +++++++++++ plan.py | 12 ++++++++++++ 2 files changed, 23 insertions(+) diff --git a/api.py b/api.py index b32a49d..cb01f7e 100644 --- a/api.py +++ b/api.py @@ -20,6 +20,7 @@ import pandas as pd from fastapi import FastAPI, HTTPException, Request from fastapi.responses import PlainTextResponse +import card import config import db import logic_state_daily @@ -185,4 +186,14 @@ def logic_state_lookup(codes: str | None = None, code: str | None = None, out.append({"input": c, "code": k, "date": d, "source": "computed", "verdict": None, "card_rank": None, "plan_version": None, **(plan._state_out(computed.get(k)) or {})}) # noqa: SLF001 + # 安全边际三情景随状态一起回(第四件;2026-09-07 拍板持仓页显示中性情景作参考目标价,只显示不触发)。 + # 逐票日频表里不存它,每次按此刻现算;算失败整批不带这两键,状态照回。 + try: + vals = plan.valuations_for(list(keyed), d) + for item in out: + v = vals.get(item["code"]) + item["valuation"] = v + item["valuation_text"] = card.valuation_view(v) + except Exception as e: # noqa: BLE001 —— 估值算不出不该拖垮状态查询 + _access.warning("logic_state valuation failed date=%s err=%r", d, e) return {"date": d, "count": len(out) + len(bad), "states": out + bad} diff --git a/plan.py b/plan.py index 6ca6e1f..b5ae734 100644 --- a/plan.py +++ b/plan.py @@ -259,6 +259,18 @@ def logic_states_for(codes: list, ds: str) -> dict: return out +def valuations_for(codes: list, ds: str) -> dict: + """给定几只票的安全边际三情景(第四件),按前缀码索引。给接口 /logic_state 用:持仓页要显示 + 参考目标价(中性情景,2026-09-07 拍板:只显示不触发,不替代用户手设的目标价),而持仓票 + 不在计划里。取数与计划装配同一处:券商研报原始行、前复权收盘价。""" + codes = [str(c).strip() for c in (codes or []) if str(c).strip()] + if not codes: + return {} + rows = sources.broker_reports(codes, ds) + prices = sources.close_prices(ds) + return sources.valuation_scenarios(codes, ds, prices, rows=rows) + + def _assemble_cards(ds: str, codes: list, ev: dict, upside: pd.Series, mkt_days: set, risk: set | None = None) -> tuple[dict, list]: """候选卡装配(2026-09-02 方案第 2.2 节第三项):对档位表里的全部票(主榜与观察档,