From 48a562f170d365bc6f9dde23e1e04bd06d93539e Mon Sep 17 00:00:00 2001 From: zlt Date: Mon, 7 Sep 2026 16:34:37 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=82=E8=80=83=E7=9B=AE=E6=A0=87=E4=BB=B7?= =?UTF-8?q?=EF=BC=9A=E7=8A=B6=E6=80=81=E5=BA=94=E7=AD=94=E9=87=8C=E7=9A=84?= =?UTF-8?q?=E4=BC=B0=E5=80=BC=E5=AD=90=E5=AD=97=E5=85=B8=E5=BD=92=E4=B8=80?= =?UTF-8?q?=EF=BC=8C=E6=8C=81=E4=BB=93=E9=A1=B5=E5=8F=AA=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E4=B8=AD=E6=80=A7=E6=83=85=E6=99=AF=E4=B8=8D=E8=A7=A6=E5=8F=91?= =?UTF-8?q?=EF=BC=88=E7=AC=AC=E4=BA=8C=E5=8D=81=E4=BA=8C=E6=89=B9=E5=8A=A0?= =?UTF-8?q?=E4=B8=80=E4=BE=8B=EF=BC=8C=E5=85=A8=E5=A5=97=20678=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/services/logic_state_service.py | 14 ++++++++++++++ app/services/plan_feed.py | 8 ++++++++ app/web/static/index.html | 4 ++++ scripts/run_tests.py | 6 +++--- scripts/test_batch22_units.py | 23 +++++++++++++++++++++++ 5 files changed, 52 insertions(+), 3 deletions(-) diff --git a/app/services/logic_state_service.py b/app/services/logic_state_service.py index 1afcf70..7a36ea1 100644 --- a/app/services/logic_state_service.py +++ b/app/services/logic_state_service.py @@ -176,6 +176,16 @@ def now_view(st) -> dict: "text": (reasons[0] if reasons else (st.get("why") or ""))[:160]} +def ref_target_view(st): + """参考目标价: 第四件的中性情景估值 (中位每股收益乘中位市盈率), 2026-09-07 拍板在持仓页显示, + 只显示不触发, 不替代用户手设的目标价 (到价提议只认命令表里那个)。算不出就不给。""" + v = st.get("valuation") if isinstance(st, dict) and isinstance(st.get("valuation"), dict) else None + if not v or v.get("na") or v.get("neut") is None: + return None + return {"price": v["neut"], "pess": v.get("pess"), "opt": v.get("opt"), "quarter": v.get("quarter"), + "firms": v.get("firms"), "as_of": v.get("as_of"), "text": st.get("valuation_text")} + + def entry_view(ts_code: str) -> dict: """「当初为什么买」: 首批未平批次 → 它的指令 → 该指令或它来自的提议在账本上的放行记录 → 硬数字里的 判决依据、论断、判决与入场时的逻辑状态。三种情形都要说得出话: 有指令链、外部成交并入、账本无行。""" @@ -229,6 +239,10 @@ def decorate_positions(rows: list, states: dict | None = None) -> list: r["logic_now"] = now_view(states.get(code)) except Exception as e: # noqa: BLE001 r["logic_now"] = {"state": None, "text": f"读数处理失败: {type(e).__name__}"} + try: + r["ref_target"] = ref_target_view(states.get(code)) + except Exception: # noqa: BLE001 + r["ref_target"] = None if int(r.get("total_qty") or 0) <= 0: r["entry"] = None continue diff --git a/app/services/plan_feed.py b/app/services/plan_feed.py index 551070e..0256cbc 100644 --- a/app/services/plan_feed.py +++ b/app/services/plan_feed.py @@ -613,6 +613,14 @@ def parse_logic_states(payload) -> dict: continue st["source"] = _text_or_none(it.get("source")) st["date"] = day + # 安全边际三情景 (第四件): 持仓页拿中性情景作参考目标价 (2026-09-07 拍板, 只显示不触发)。 + v = it.get("valuation") if isinstance(it.get("valuation"), dict) else None + st["valuation"] = ({"neut": _float_or_none(v.get("neut")), "pess": _float_or_none(v.get("pess")), + "opt": _float_or_none(v.get("opt")), "price": _float_or_none(v.get("price")), + "quarter": _text_or_none(v.get("quarter")), "firms": _int_or_none(v.get("firms")), + "as_of": _text_or_none(v.get("as_of")), "na": _text_or_none(v.get("na"))} + if v else None) + st["valuation_text"] = _text_or_none(it.get("valuation_text")) out[code] = st return out diff --git a/app/web/static/index.html b/app/web/static/index.html index 8264ba3..695ff78 100644 --- a/app/web/static/index.html +++ b/app/web/static/index.html @@ -1565,6 +1565,10 @@ body.dock-r:not(.r-fold) .side-r .strip{display:none;} {{ s.row.user_stop_price!=null ? s.row.user_stop_price : '-' }}/{{ s.row.user_target_price!=null ? s.row.user_target_price : '-' }} 未设 + +
参考 {{ s.row.ref_target.price }}({{ s.row.ref_target.firms }} 家中性估值,只显示不触发)