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) }}
+
+ 颜色约定?
+
+
+
+
+
+
等我拍板 · {{ 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 }} 只
+
+
+
+
+
+
持仓批次
+
+ {{ tx('lot', l.row.lot_type) }}
+
+
+
+
+
+
无持仓批次
+
载入中…
+
+
+
该股账本
+
今日暂无记录
+
+ {{ (l.decided_at||'').slice(5,16) }}
+ {{ tx('arbiter', l.arbiter) }}{{ tx('verdict', l.verdict) }} {{ tx('action', l.action) }} — {{ l.reason }}
+
+
+
+
+
+
+ {{ nm(s.row.ts_code) }}
{{ s.row.ts_code }}
+
+
+ {{ s.row.price }} 估
{{ s.row.avg_cost||'—' }}
+
+
+
+ {{ pct(s.row.price/s.row.avg_cost-1) }}
+ —
+
+
+
+ {{ money(s.row.market_value) }}
{{ pct(s.row.pct_of_scale) }}
+
+
+ {{ tx('cushion', s.row.cushion_state) }}
+ {{ pct(s.row.cushion_pct) }} · 连负{{ s.row.neg_cushion_days }}日
+
+
+ {{ tx('posStatus', s.row.status) }}
+ {{ tx('frozen', s.row.frozen_reason) }}
+
+ {{ nextStep(s.row) }}
+
+
+ 减仓
+ 清仓
+ rowMore(c,s.row)">
+ 更多 ▾
+
+
+ 设止损价
+ 设目标价
+ {{ (s.row.frozen_reason && s.row.frozen_reason!=='NONE') ? '解冻' : '冻结(禁增持)' }}
+ 加入黑名单
+ 挂交易方案(做T/网格/跟踪止盈)
+
+
+
+
+
+
+
+
+
+
我的策略 · {{ strategies.length }} 个
+
+ {{ stratEnabled ? '策略层已启用' : '策略层总开关未开(PMS_STRATEGY_ENABLED)' }}
+ 显示已撤下/已完成
+
+ {{ autoInfo.enabled ? '自动挂载已开' : '自动挂载总开关未开' }}
+
+ 预演
+ ?
+
+
+
+
+ 今日自动挂载已于 {{ (autoInfo.last_scan.at||'').slice(11,16) }} 执行:查
+ {{ autoInfo.last_scan.checked }} 只 · 挂载 {{ ((autoInfo.last_scan.counts||{}).attached)||0 }} ·
+ 接力 {{ ((autoInfo.last_scan.counts||{}).handoffs)||0 }} · 停买 {{ ((autoInfo.last_scan.counts||{}).paused)||0 }} ·
+ 被挡 {{ ((autoInfo.last_scan.counts||{}).blocked)||0 }} · 跳过 {{ ((autoInfo.last_scan.counts||{}).skipped)||0 }}
+
+
+ 今日自动挂载未执行(交易日 09:40 定时运行)
+
+
+
+
+
+
+ 预演结果(未执行)· 查 {{ autoScanRes.checked }} 只持仓
+
+
+
+ {{ x.stage }}
+ {{ nm(x.ts_code) }}
+ {{ x.why }}
+ · 热度 {{ Number(x.heat).toFixed(2) }}
+ · 浮盈 {{ pct(x.cushion_pct) }}
+ · 定性「{{ x.accum_state }}」
+
+
+
+
+ 想挂
+ {{ 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 }}
+
+ · {{ nm(x.ts_code) }}:{{ x.why }}
+
✗ {{ e }}
+
+ {{ autoScanRes.unknown_states.length }} 只票的吸筹定性超出约定词表(已按无标志处理),
+ 样本:{{ autoScanRes.unknown_states.slice(0,3).map(u=>u.state).join('、') }}。需与决策系统核对
+
+
+ 本轮无动作:无符合触发条件的信号
+
+
+
尚未挂载交易方案。可在「我的持仓」行内「更多 ▾ → 挂交易方案」创建。
+
+ {{ nm(s.row.ts_code) }} {{ s.row.ts_code }}
+ {{ tx('stype', s.row.type) }}
+ {{ s.row.autonomy==='auto'?'自动执行':'待我拍板' }}
+ {{ stratStateText(s.row) }}
+ 买入已暂停
+ 决策系统风控:{{ s.row.buy_paused.reason || '资金异动' }}(卖出/平回不受影响;确认无碍点右侧「恢复买入」)
+
+ {{ tx('stratStatus', s.row.status) }}
+
+ 暂停
+ 恢复
+ 恢复买入
+ 撤下
+ 移除
+ 恢复显示
+
+
+
+
操作日志 · {{ opLog.length }} 条 {{ showOpLog?'▲ 收起':'▼ 展开' }}
+
+ 每次操作留痕一行;被约束挡下的操作记录原因。
+ 还没有操作记录。
+
+ {{ (o.at||'').slice(11,16) }}
+ {{ o.result }}
+ {{ o.op }} · {{ nm(o.ts_code) }}
+ — {{ o.reason }}
+
+
+
+
上游信号 · 只读参考,不进下单逻辑 {{ showUpstream?'▲ 收起':'▼ 展开' }}
- 最近取数 {{ (upstream.at||'').slice(11,19) }}(每次刷新拉一次;源自 mtf / 盘中择时层 / 决策系统)
+ 最近取数 {{ (upstream.at||'').slice(11,19) }} · 来源:决策系统 / 盘中择时
级别筛选
{{ L.label }} {{ levelCount(L.key) }}
- 点一下切换显隐,只前端过滤、不查后端
+ ?
@@ -467,134 +696,7 @@ 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) }}
-
-
- 颜色约定:
- 红=涨/盈
- 绿=跌/亏
- 琥珀=需注意
- 橙=被拦下
- 蓝=可操作/正常
- ?
-
-
-
-
-
-
-
等我拍板 · {{ 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 }} 只
-
-
-
-
-
-
持仓批次
-
- {{ tx('lot', l.row.lot_type) }}
-
-
-
-
-
-
无持仓批次
-
载入中…
-
-
-
该股账本
-
今日暂无记录
-
- {{ (l.decided_at||'').slice(5,16) }}
- {{ tx('arbiter', l.arbiter) }}{{ tx('verdict', l.verdict) }} {{ tx('action', l.action) }} — {{ l.reason }}
-
-
-
-
-
-
- {{ nm(s.row.ts_code) }}
{{ s.row.ts_code }}
-
-
- {{ s.row.price }} 估
{{ s.row.avg_cost||'—' }}
-
-
-
- {{ pct(s.row.price/s.row.avg_cost-1) }}
- —
-
-
-
- {{ money(s.row.market_value) }}
{{ pct(s.row.pct_of_scale) }}
-
-
- {{ tx('cushion', s.row.cushion_state) }}
- {{ pct(s.row.cushion_pct) }} · 连负{{ s.row.neg_cushion_days }}日
-
-
- {{ tx('posStatus', s.row.status) }}
- {{ tx('frozen', s.row.frozen_reason) }}
-
- {{ nextStep(s.row) }}
-
-
- 减仓
- 清仓
- rowMore(c,s.row)">
- 更多 ▾
-
-
- 设止损价
- 设目标价
- {{ (s.row.frozen_reason && s.row.frozen_reason!=='NONE') ? '解冻' : '冻结(禁增持)' }}
- 加入黑名单
- 挂交易方案(做T/网格/跟踪止盈)
-
-
-
-
-
-
-
+
@@ -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 ? '自动挂载已开' : '自动挂载总开关未开' }}
-
- 预演 · 现在系统想做什么
-
-
-
-
- 今天的正式一跳已在 {{ (autoInfo.last_scan.at||'').slice(11,16) }} 跑过:查
- {{ autoInfo.last_scan.checked }} 只,挂载 {{ ((autoInfo.last_scan.counts||{}).attached)||0 }}、
- 接力 {{ ((autoInfo.last_scan.counts||{}).handoffs)||0 }}、停买入 {{ ((autoInfo.last_scan.counts||{}).paused)||0 }}、
- 被挡 {{ ((autoInfo.last_scan.counts||{}).blocked)||0 }}、跳过 {{ ((autoInfo.last_scan.counts||{}).skipped)||0 }}。
-
-
- 今天的正式一跳还没跑(每个交易日 09:40 由调度自动执行,跑完这里会显示结果)。
-
- 「预演」按钮只是看一眼:按此刻的行情和信号算一遍会做什么,不挂载、不留痕,随便点。
-
-
-
-
-
- 以下为预演结果:按此刻的行情和信号,系统会做什么。只是看一眼,什么都没动。
- 本轮查了 {{ autoScanRes.checked }} 只持仓票。
-
-
-
- {{ x.stage }}
- {{ nm(x.ts_code) }}
- {{ x.why }}
- · 热度 {{ Number(x.heat).toFixed(2) }}
- · 浮盈 {{ pct(x.cushion_pct) }}
- · 定性「{{ x.accum_state }}」
-
-
-
-
- 想挂
- {{ 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 }}
-
- · {{ nm(x.ts_code) }}:{{ x.why }}
-
✗ {{ e }}
-
- 有 {{ autoScanRes.unknown_states.length }} 只票的吸筹说法不在约定词表里(按无标志处理),
- 样本:{{ autoScanRes.unknown_states.slice(0,3).map(u=>u.state).join('、') }}——需与决策系统核对。
-
-
- 今天没有想动的:持仓里暂时没有够格的信号,这是正常的克制。
-
-
-
还没有挂任何交易方案。到「我的持仓」某行「更多 ▾ → 挂交易方案」给它挂一个。
-
- {{ nm(s.row.ts_code) }} {{ s.row.ts_code }}
- {{ tx('stype', s.row.type) }}
- {{ s.row.autonomy==='auto'?'自动执行':'待我拍板' }}
- {{ stratStateText(s.row) }}
- 买入已暂停
- 决策系统风控:{{ s.row.buy_paused.reason || '资金异动' }}(卖出/平回不受影响;确认无碍点右侧「恢复买入」)
-
- {{ tx('stratStatus', s.row.status) }}
-
- 暂停
- 恢复
- 恢复买入
- 撤下
- 移除
- 恢复显示
-
-
-
-
操作日志 · {{ opLog.length }} 条 {{ showOpLog?'▲ 收起':'▼ 展开' }}
-
- 每一次页面写操作都留一行;被仓位 / 盈亏 / T+1 可卖 / 单股上限挡下的,连原因一起记,不静默。
- 还没有操作记录。
-
- {{ (o.at||'').slice(11,16) }}
- {{ o.result }}
- {{ o.op }} · {{ nm(o.ts_code) }}
- — {{ o.reason }}
-
-
-
@@ -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