From 8372c388a3cc71ec0ac889e877d71b723fd0cf49 Mon Sep 17 00:00:00 2001 From: zlt Date: Wed, 26 Aug 2026 10:29:31 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=89=8D=E7=AB=AF=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DEVLOG.md | 3 + app/services/strategy_advisor.py | 9 +- app/web/static/index.html | 468 +++++++++++++++---------------- scripts/test_batch17_units.py | 2 +- 4 files changed, 243 insertions(+), 239 deletions(-) diff --git a/DEVLOG.md b/DEVLOG.md index 9cbdc25..4633f56 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):前端文字整改与双栏布局(用户三条标准)** +用户定下三条标准并全页执行:交易员可读且含义明确;开发人员口吻的文字彻底清除;系统文字最大限度精简,提示能删则删、必须留的进悬浮问号不占版面。整改清单:删掉「随便点」「只是看一眼」这类不严肃表述,预演说明并入按钮旁的悬浮提示;预演结果头行压成「预演结果(未执行)· 查 N 只持仓」;执行状态行改为「今日自动挂载已于 09:41 执行:查 4 · 挂载 0 · 被挡 1 · 跳过 1」句式;颜色约定整条彩字图例压成一个悬浮问号;告警级别筛选的「只前端过滤、不查后端」删除改悬浮;上游信号来源行去掉内部代号(mtf);操作日志说明收紧为一句;空策略引导语改严肃措辞;后端返回里会显示到页面的英文类型码全部换成中文名(网格、跟踪止盈、做T)。布局:交易员视图改双栏栅格(左七右五)——左栏持仓加策略,右栏上游信号常驻展开,两边可同屏实时盯;窗口窄于 1500 像素自动叠回单栏,其余区块次序不变。全量 560 例通过。 + **次日上午第五批(2026-08-26 盘中):把「预演」与「正式跑」在页面上分清** 用户反馈「试算只判断」的提示看不懂到底有用没用——根子是页面只有预演镜,没人回答「今天的正式一跳跑没跑、做了什么」,而零动作的一跳在台账上没有任何痕迹(设计如此,台账只记真动作)。补法:advisor 每次真跑(含总开关关着的那次)在每个出口写一份摘要进运行参数(新登记 PMS_AUTO_LAST_SCAN,写失败只告警;set_param 返回值按纪律接住),策略接口把总开关状态、今天跑没跑、各类计数一并返回;页面「我的策略」常驻一行仪表:「今天的正式一跳已在 09:41 跑过:查 4 只,挂载 0、被挡 1、跳过 1」或「还没跑(09:40 自动执行)」,按钮改名「预演 · 现在系统想做什么」,预演结果头一句明说「什么都没动」。批十七加一例钉住「真跑每个出口都写、预演一笔不写」,总数 560。 diff --git a/app/services/strategy_advisor.py b/app/services/strategy_advisor.py index 1eaba6c..0058b64 100644 --- a/app/services/strategy_advisor.py +++ b/app/services/strategy_advisor.py @@ -69,6 +69,7 @@ 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} +_CN_TYPE = {"GRID": "网格", "TRAIL": "跟踪止盈", "T0": "做T"} # 页面文案用中文名, 不给交易员看代码 def lot_of(ts_code) -> int: @@ -496,7 +497,7 @@ def scan(*, dry_run: bool = False, now=None) -> dict: 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 += " (挂着人工策略, 自动挂载不碰)" + 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"), @@ -530,7 +531,8 @@ def _tend_existing(st, p, a, fresh, hv, prm, buypause, handoff_cool, today, is_auto = note.startswith("自动挂载") stype = str(st.get("type") or "").upper() if not is_auto: - out["skipped"].append({"ts_code": code, "why": f"挂着人工策略 ({stype}), 自动挂载不碰它"}) + out["skipped"].append({"ts_code": code, "why": + f"挂着人工策略({_CN_TYPE.get(stype, stype)}), 自动挂载不介入"}) return if stype == "GRID": # ---- 边四: 接力切换 (先于边三判 —— 都成立时说明已在拉升, 换止盈比停买更对) ---- @@ -583,7 +585,8 @@ def _tend_existing(st, p, a, fresh, hv, prm, buypause, handoff_cool, today, elif r.get("error"): out["errors"].append(f"{code} 解除买入暂停失败: {r['error']}") else: - out["skipped"].append({"ts_code": code, "why": f"已挂自动 {stype}, 本轮无事"}) + out["skipped"].append({"ts_code": code, + "why": f"已挂自动{_CN_TYPE.get(stype, stype)}, 本轮无需变更"}) def _attach_one(edge, why, p, a, hv, prm, view, black, live_codes, optout, diff --git a/app/web/static/index.html b/app/web/static/index.html index bee8ede..445431b 100644 --- a/app/web/static/index.html +++ b/app/web/static/index.html @@ -57,6 +57,10 @@ body{margin:0;background:var(--plane);color:var(--ink); .m .v{color:var(--ink);font-size:21px;font-weight:680;margin-top:5px;letter-spacing:-.2px;font-variant-numeric:tabular-nums;} .m .v .muted,.m .v span{font-weight:500;} .m .v.up{color:var(--up);} .m .v.down{color:var(--down);} +/* 双栏布局: 持仓与策略在左、上游信号在右 (2026-08-26) */ +.tcols{display:grid;grid-template-columns:minmax(0,7fr) minmax(0,5fr);gap:12px;align-items:start} +@media (max-width:1500px){.tcols{grid-template-columns:minmax(0,1fr)}} +.tcol{min-width:0} /* 颜色约定图例 */ .legend{display:flex;gap:15px;flex-wrap:wrap;align-items:center;color:var(--muted);font-size:12px;margin:0 2px 16px;} .legend .sw{display:inline-block;width:9px;height:9px;border-radius:2px;margin-right:4px;vertical-align:middle;} @@ -297,16 +301,241 @@ pre.json{background:var(--surface-2);border:1px solid var(--hair);border-radius: 下方查看全部 ▾ + + + +
+
账户总资产
{{ money(ov.total_asset) }}
+
可用资金 (估算)
+
{{ money(ov.cash_source==='ws' ? ov.cash_avail : ov.cash_est) }}
+
持仓市值
{{ money(ov.portfolio_mv) }}
+
仓位
{{ pct(ov.portfolio_pct) }} / {{ pct(ov.portfolio_cap) }}
+
浮动盈亏
+
{{ money(ov.float_pnl) }} {{ ov.float_pnl_pct==null?'':pct(ov.float_pnl_pct) }}
+
持仓数
{{ ov.names_count }} / {{ ov.max_names }}
+
等我拍板
+
{{ proposals.length }} 条
+
自主档位
{{ tx('autonomy', ov.autonomy) }}
+
+
颜色约定?
+ +
+

需要注意

+
· {{ a }}
+
+ + +
+

等我拍板 · {{ proposals.length }} 条

+
暂无需要你确认的提议。
+
+
+
{{ nm(p.ts_code) }} {{ p.ts_code }} + {{ tx('action', p.action) }}
+
{{ p.expire_at }} 前有效
+
+
决策系统:{{ p.judge_reason }}
+
{{ propWhy(p) }}
+
+ 约 {{ p.qty }} 股 · 参考价 {{ (p.hard_numbers||{}).price==null ? '—' : (p.hard_numbers||{}).price }} + · 约需 {{ money(((p.hard_numbers||{}).price||0)*(p.qty||0)) }} +
+ 采纳 + 驳回 +
+
采纳=记一笔待执行指令,由择时在窗口内择机下单;驳回=今日不再提这只。
+
+
+ + + +
+
+

我的持仓 · {{ heldPositions.length }} 只

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+

我的策略 · {{ strategies.length }} 个 + + {{ stratEnabled ? '策略层已启用' : '策略层总开关未开(PMS_STRATEGY_ENABLED)' }} + 显示已撤下/已完成 + + {{ autoInfo.enabled ? '自动挂载已开' : '自动挂载总开关未开' }} + + 预演 + ? +

+ +
+ + +
+ + +
+
+ 预演结果(未执行)· 查 {{ autoScanRes.checked }} 只持仓 +
+ +
+ {{ x.stage }} + {{ nm(x.ts_code) }} + {{ x.why }} + + + + +
+ +
+ 想挂 + {{ nm(x.ts_code) }} {{ tx('stype', x.type) }} —— {{ x.why }}
+
+ 想换挂 + {{ nm(x.ts_code) }} 网格换跟踪止盈 —— {{ x.why }}
+
+ 想停买入 + {{ nm(x.ts_code) }} —— {{ x.why }}
+
+ 想恢复买入 + {{ nm(x.ts_code) }}
+
+ 被挡 + {{ nm(x.ts_code) }} —— {{ x.why }}
+
+ · {{ x.why }}
+
✗ {{ e }}
+
+ {{ autoScanRes.unknown_states.length }} 只票的吸筹定性超出约定词表(已按无标志处理), + 样本:{{ autoScanRes.unknown_states.slice(0,3).map(u=>u.state).join('、') }}。需与决策系统核对 +
+
+ 本轮无动作:无符合触发条件的信号 +
+
+
尚未挂载交易方案。可在「我的持仓」行内「更多 ▾ → 挂交易方案」创建。
+ + + + + + + + + +

操作日志 · {{ opLog.length }} 条 {{ showOpLog?'▲ 收起':'▼ 展开' }}

+ +
+

上游信号 · 只读参考,不进下单逻辑 {{ showUpstream?'▲ 收起':'▼ 展开' }}

- - - -
-
账户总资产
{{ money(ov.total_asset) }}
-
可用资金 (估算)
-
{{ money(ov.cash_source==='ws' ? ov.cash_avail : ov.cash_est) }}
-
持仓市值
{{ money(ov.portfolio_mv) }}
-
仓位
{{ pct(ov.portfolio_pct) }} / {{ pct(ov.portfolio_cap) }}
-
浮动盈亏
-
{{ money(ov.float_pnl) }} {{ ov.float_pnl_pct==null?'':pct(ov.float_pnl_pct) }}
-
持仓数
{{ ov.names_count }} / {{ ov.max_names }}
-
等我拍板
-
{{ proposals.length }} 条
-
自主档位
{{ tx('autonomy', ov.autonomy) }}
-
-
- 颜色约定: - 红=涨/盈 - 绿=跌/亏 - 琥珀=需注意 - 橙=被拦下 - 蓝=可操作/正常 - ? -
- -
-

需要注意

-
· {{ a }}
-
- - -
-

等我拍板 · {{ proposals.length }} 条

-
暂无需要你确认的提议。
-
-
-
{{ nm(p.ts_code) }} {{ p.ts_code }} - {{ tx('action', p.action) }}
-
{{ p.expire_at }} 前有效
-
-
决策系统:{{ p.judge_reason }}
-
{{ propWhy(p) }}
-
- 约 {{ p.qty }} 股 · 参考价 {{ (p.hard_numbers||{}).price==null ? '—' : (p.hard_numbers||{}).price }} - · 约需 {{ money(((p.hard_numbers||{}).price||0)*(p.qty||0)) }} -
- 采纳 - 驳回 -
-
采纳=记一笔待执行指令,由择时在窗口内择机下单;驳回=今日不再提这只。
-
-
- - -
-

我的持仓 · {{ heldPositions.length }} 只

- - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
@@ -648,110 +750,6 @@ pre.json{background:var(--surface-2);border:1px solid var(--hair);border-radius:
- -
-

我的策略 · {{ strategies.length }} 个 - - {{ stratEnabled ? '策略层已启用' : '策略层总开关未开(PMS_STRATEGY_ENABLED)' }} - 显示已撤下/已完成 - - {{ autoInfo.enabled ? '自动挂载已开' : '自动挂载总开关未开' }} - - 预演 · 现在系统想做什么 -

- -
- - - 「预演」按钮只是看一眼:按此刻的行情和信号算一遍会做什么,不挂载、不留痕,随便点。 -
- - -
-
- 以下为预演结果:按此刻的行情和信号,系统会做什么。只是看一眼,什么都没动。 - 本轮查了 {{ autoScanRes.checked }} 只持仓票。 -
- -
- {{ x.stage }} - {{ nm(x.ts_code) }} - {{ x.why }} - - - - -
- -
- 想挂 - {{ nm(x.ts_code) }} {{ tx('stype', x.type) }} —— {{ x.why }}
-
- 想换挂 - {{ nm(x.ts_code) }} 网格换跟踪止盈 —— {{ x.why }}
-
- 想停买入 - {{ nm(x.ts_code) }} —— {{ x.why }}
-
- 想恢复买入 - {{ nm(x.ts_code) }}
-
- 被挡 - {{ nm(x.ts_code) }} —— {{ x.why }}
-
- · {{ x.why }}
-
✗ {{ e }}
-
- 有 {{ autoScanRes.unknown_states.length }} 只票的吸筹说法不在约定词表里(按无标志处理), - 样本:{{ autoScanRes.unknown_states.slice(0,3).map(u=>u.state).join('、') }}——需与决策系统核对。 -
-
- 今天没有想动的:持仓里暂时没有够格的信号,这是正常的克制。 -
-
-
还没有挂任何交易方案。到「我的持仓」某行「更多 ▾ → 挂交易方案」给它挂一个。
- - - - - - - - - -

操作日志 · {{ opLog.length }} 条 {{ showOpLog?'▲ 收起':'▼ 展开' }}

- -
@@ -1650,7 +1648,7 @@ createApp({ const lastRefresh = ref(''); const autoRefresh = ref(true); const upstream = ref({ sources: {} }); - const showUpstream = ref(false); // 默认折叠, 点标题展开 + const showUpstream = ref(true); // 双栏后信号在右栏常驻显示, 点标题可折叠 (2026-08-26) const showAlerts = ref(false); const alertShowMap = reactive({ money_flow:true, capital:true, qrs:true, volume:true, multi:true, price_notice:false, buy_emitted:false, other:true }); // 级别筛选记忆: 存 sessionStorage —— 普通刷新保留, 关标签页/新开标签=回默认。默认关 普通/提示。 diff --git a/scripts/test_batch17_units.py b/scripts/test_batch17_units.py index 326253c..6fccf41 100644 --- a/scripts/test_batch17_units.py +++ b/scripts/test_batch17_units.py @@ -643,7 +643,7 @@ def _(): out2 = _out() adv._tend_existing(auto_trail, _pos(price=10.6), {"cls": adv.CLS_CLEAR}, True, 0.9, _prm(), {}, set(), TODAY, False, out2, fake_svc) - assert any("本轮无事" in s["why"] for s in out2["skipped"]), out2["skipped"] + assert any("本轮无需变更" in s["why"] for s in out2["skipped"]), out2["skipped"] # 半途而废: 撤成挂败 → errors 里有「人工处理」, 留痕 HANDOFF/REJECT orig_led, orig_upd = pms_repo.insert_ledger, pms_repo.update_strategy pms_repo.insert_ledger = lambda **kw: rec.ledger.append(kw) or 1