diff --git a/DEVLOG.md b/DEVLOG.md index 32e3b89..e64db81 100644 --- a/DEVLOG.md +++ b/DEVLOG.md @@ -50,6 +50,9 @@ app/services/strategy_advisor.py(新增);app/services/strategy_service.py **真机判收** 部分判收(2026-08-25 盘中)。桥机 make deploy + make test 见 ALL SUITES PASS;dry-run 试算真机四票读数全部合理:688802.SH 想挂网格但「按投入比例折出 47,250 元买不起一手」被挡(科创板高价票,判定正确);002179.SZ 有在途指令主动让路;其余两票无信号静默跳过;unknown_states 为空(子串归类修对了)。**尚未判收的**:真挂一条(等在途清了重扫或次日 09:40)、边三/边四真机走一遍、strategy_runner 对自动网格的逐档发单。 +**次日上午第四批(2026-08-26 盘中):每票阶段可视化** +用户拍板把状态机补成看得见的:扫描结果新增 stages,对**每只**持仓票各出一行——处在五阶段(吸筹震荡、启动拉升、高位派发、深亏修复、中性)的哪一段、一句话理由、热度、浮盈、定性原文;已挂自动策略的票阶段以策略为准(网格即吸筹震荡进行中、止盈即启动拉升保护中),人工策略票按信号判并注明「自动挂载不碰」;信号判定次序与连边一致,派发优先于深亏(保守方向)。页面按钮的结果顶部渲染五阶段视图,不动的票也说清为什么不动。判定函数 stage_of 纯逻辑可测,批十七扩到 40 例,总数 559。同日运维记录:桥的计划触发已在北京 07:10 跑通(计划日 T-1,判收通过);deploy 恰好压掉 09:40 调度位,用试算端点的正式模式手动补跑(补跑与调度位同一份实现);清掉两个三周前 compose run 未带 --rm 的残留容器。 + **当日盘中第三批(赶进度拍板后加的两件)** 一,科创板取整从「挂载侧兜」补到「执行侧真修」:strategy_runner 新增 _min_lot(688/689 按 200 股),网格手工挂的 100 股档在评估时抬成合法数量、卖出量不足 200 股原地等不推进档位;跟踪止盈的部分卖低于 200 股时量够就抬到 200(方向是保利润,偏保守)、可卖本身不足 200 时部分卖放弃,全清路径按交易所例外允许不足 200 股一次性全卖。主板行为一字未变,单测把两侧都钉住(批十七扩到 38 例,总数 557)。做T是命令授权的手工策略,科创板做T的开仓与平回数量怎么处理需要单独拍板,本次不动。 二,管理页「我的策略」加了「自动挂载 · 看看今天想挂什么」按钮:调 09:40 调度位同一份实现的试算模式,把想挂、想换挂、想停买入、被挡、跳过的每一条连原因渲染成可读文字,不再需要敲命令;空结果明说「没有想动的是正常克制」。 diff --git a/app/services/strategy_advisor.py b/app/services/strategy_advisor.py index 411ffa8..80057b4 100644 --- a/app/services/strategy_advisor.py +++ b/app/services/strategy_advisor.py @@ -62,6 +62,10 @@ NOTE_AUTO = "自动挂载: " NOTE_HANDOFF = "自动挂载(接力): " MARK_HANDOFF_OUT = "[接力撤下]" +# 阶段名 (方案第三节五阶段; 页面显示与判分同用这份字面量) +STG_ACCUM, STG_LAUNCH = "吸筹震荡", "启动拉升" +STG_DISTRIB, STG_REPAIR, STG_NEUTRAL = "高位派发", "深亏修复", "中性" + ACCUM_WINDOW_DAYS = 45 # 每票取近 45 自然日内最新一条结论 HEAT_MAX_AGE_DAYS = 4 # 热度表末日落后超此自然日 → 热度信号本轮不可用 _RULE_OF_TYPE = {"GRID": R_GRID, "TRAIL": R_TRAIL} @@ -151,6 +155,30 @@ def plan_edge(*, cls, fresh, heat, cushion, prm): return None, "" +def stage_of(*, cls, fresh, heat, heat_th, cushion, stype=None, is_auto=False): + """判定一只持仓票当前处在哪个阶段 (方案第三节的五阶段)。返回 (阶段, 一句话理由)。 + + 已挂自动策略的票, 阶段以策略为准 —— 策略本身就是阶段判断落了地。无策略的票按 + 信号判, 次序与连边判断一致, 保守方向优先: 派发最先, 然后吸筹、拉升、深亏, 都 + 不是就是中性。这个函数只读不写, 每次扫描对全部持仓各出一行, 页面按钮直接显示。 + """ + t = str(stype or "").upper() + if is_auto and t == "GRID": + return STG_ACCUM, "自动网格进行中, 区间内低买高卖" + if is_auto and t == "TRAIL": + return STG_LAUNCH, "自动跟踪止盈保护中, 创新高抬线回落即卖" + if cls == CLS_DISTRIB: + return STG_DISTRIB, "决策系统定性为高位派发" + if cls == CLS_CLEAR and fresh: + return STG_ACCUM, "明确吸筹且结论新鲜" + hot = heat is not None and _f(heat, 0.0) >= heat_th + if hot and cushion is not None and _f(cushion, 0.0) > 0: + return STG_LAUNCH, f"热度 {_f(heat):.2f} 达标且有浮盈" + if cushion is not None and _f(cushion, 0.0) < 0: + return STG_REPAIR, "安全垫为负, 交给补仓评估与清弱票, 不配策略" + return STG_NEUTRAL, "无明确信号, 留给动作引擎的常规动作" + + def count_auto_today(rows, today_ymd: int) -> int: """今天已常规自动挂载几条 (接力挂出的不算 —— 它是换不是增)。rows=策略行 (含已归档)。""" n = 0 @@ -340,7 +368,7 @@ def scan(*, dry_run: bool = False, now=None) -> dict: out = {"ok": True, "enabled": prm["enabled"], "dry_run": dry_run, "checked": 0, "attached": [], "handoffs": [], "paused": [], "resumed": [], "blocked": [], "skipped": [], "errors": [], - "unknown_states": []} + "unknown_states": [], "stages": []} if not prm["enabled"]: out["skipped"].append({"why": "策略自动挂载总开关关闭 (PMS_AUTO_STRATEGY_ENABLED)"}) return out @@ -438,6 +466,16 @@ def scan(*, dry_run: bool = False, now=None) -> dict: and a["age_days"] <= prm["accum_stale_tdays"] * 2) hv = heat.get(code) st = strat_by_code.get(code) + is_auto = bool(st and str(st.get("note") or "").startswith("自动挂载")) + stg, stg_why = stage_of(cls=a.get("cls"), fresh=fresh, heat=hv, + heat_th=prm["heat_th"], cushion=p.get("cushion_pct"), + stype=(st or {}).get("type"), is_auto=is_auto) + if st and not is_auto: + stg_why += " (挂着人工策略, 自动挂载不碰)" + out["stages"].append({"ts_code": code, "stage": stg, "why": stg_why, + "accum_state": a.get("state"), "heat": hv, + "cushion_pct": p.get("cushion_pct"), + "strategy": (st or {}).get("type")}) if st: _tend_existing(st, p, a, fresh, hv, prm, buypause, handoff_cool, today, dry_run, out, strategy_service) diff --git a/app/web/static/index.html b/app/web/static/index.html index 83f192f..ea33ee3 100644 --- a/app/web/static/index.html +++ b/app/web/static/index.html @@ -665,6 +665,17 @@ pre.json{background:var(--surface-2);border:1px solid var(--hair);border-radius: 试算只判断、不挂载不留痕;真跑在每个交易日 09:40 由调度自动执行。本轮查了 {{ autoScanRes.checked }} 只持仓票。 + +