diff --git a/app/web/static/index.html b/app/web/static/index.html
index 6986ad4..8d74e77 100644
--- a/app/web/static/index.html
+++ b/app/web/static/index.html
@@ -2206,9 +2206,17 @@ createApp({
};
// ===================== 交易员视图:翻译层 + 名称 + 动作 =====================
const T = {
+ // 账本的动作有十六个:八个真动作(planner.py:31 那批常量)加八个伪动作
+ // (账本里直写的字面量,例如对账修正、信号留痕)。少一个就会在页面上露原码。
action: { OPEN:'建新仓', FILL:'回落补足', ADD:'盈利加仓', DCA:'浮亏补仓', TRIM:'保盈减仓',
- EXIT:'清仓', T0:'做T', T0_ROUND:'做T', SWITCH:'换仓', HALT:'停手' },
- side: { buy:'买入', sell:'卖出' },
+ EXIT:'清仓', T0:'做T', T0_ROUND:'做T', SWITCH:'换仓', HALT:'停手',
+ RECON:'对账修正', CLEANUP:'收尾清理', MACRO:'大盘冷热',
+ SIGNAL:'信号留痕', SIGNAL_BUY:'买入信号',
+ // 挂方案这一条要用中性词:想挂但放弃的三处调用也以 ATTACH 落库,
+ // 写成「挂成功」会说反。
+ ATTACH:'挂方案', HANDOFF:'方案接力', NOTE:'记一笔' },
+ // none 是停手那一类动作真实产出的方向(planner.py:34),不补会印成原码。
+ side: { buy:'买入', sell:'卖出', none:'不动' },
autonomy: { full:'全自动', propose_only:'只提议,等你拍板', off:'暂停' },
cushion: { SOLID:'厚垫', THIN:'薄垫', NONE:'浮亏无垫' },
lot: { BASE:'首批', FILL:'回落补足', ADD:'盈利加仓', DCA:'浮亏补仓', T0:'做T仓', RECON:'对账修正' },
@@ -2216,14 +2224,42 @@ createApp({
posStatus: { PLANNED:'计划建仓', OPENING:'建仓中', HOLDING:'持有中', EXITING:'清仓中', CLOSED:'已清仓' },
insStatus: { PROPOSED:'等着校验', RULE_PASSED:'合规检查已过', JUDGE_PASSED:'决策系统复核已过', DISPATCHED:'已挂单,等成交',
CONFIRMED:'已成交', REJECTED:'被挡下', EXPIRED:'到期作废', CANCELLED:'已撤销' },
- arbiter: { rule:'合规检查', judge:'决策系统', user:'你' },
- verdict: { PASS:'放行', REJECT:'驳回', NOTE:'记一笔', UNAVAILABLE:'决策系统现在读不到' },
+ arbiter: { rule:'合规检查', judge:'决策系统', user:'你', system:'系统自动' },
+ // 这一组是**评审账本**的结论,只有四个值。研判闸的结论是另一组 judgeVerdict,
+ // 两者别混:账本记的是「这一步放行还是驳回」,研判记的是「决策系统怎么说」。
+ verdict: { PASS:'放行', REJECT:'驳回', NOTE:'记一笔', WARN:'留了提醒',
+ UNAVAILABLE:'决策系统现在读不到' },
// 参考位这一列的数是谁给的。系统每个交易日盘前重算一遍并把整列重写, 所以它基本上
// 永远是系统口径; 用户设的止损价只在下达当天投影到这一列上, 第二天早上就换回系统值了。
// 用户自己设的两个价另有「我设的」一列, 那一列读命令表, 不会被盖。
refSource: { bionic:'决策系统给的', self_calc:'系统自算', user:'你今天设的', none:'取不到' },
stype: { T0:'做T', GRID:'网格', TRAIL:'跟踪止盈' },
stratStatus: { ACTIVE:'运行中', PAUSED:'已暂停', CANCELLED:'已撤下', DONE:'已完成' },
+ // 研判闸的结论。注意 PASS 不代表真问过决策系统:不在研判范围内的动作直接回 PASS。
+ judgeVerdict: { PASS:'通过', REJECT:'决策系统驳回', UNAVAILABLE:'决策系统读不到',
+ STRATEGY:'交易方案发起', STRATEGY_RISK:'方案风控发起' },
+ // 择时执行器的出手判定。不是评审结论,别并进 verdict 组。
+ execAct: { FIRE:'出手', WAIT:'条件没到', SKIP:'当日跳过', STOP:'今日不再出手',
+ REJECT:'终检没过' },
+ cmdStatus: { PENDING:'待处理', EFFECTIVE:'生效中', SUPERSEDED:'已被覆盖',
+ PLANNING:'规划中', EXECUTING:'执行中', PARTIAL:'部分完成',
+ DONE:'已完成', CANCELLED:'已撤销' },
+ planStatus2: { PENDING:'待处理', GATED:'等解锁', EXECUTING:'执行中',
+ DONE:'已完成', PARTIAL:'部分完成', CANCELLED:'已撤销' },
+ orderStatus: { QUEUED:'待发出', SENDING:'已认领', SENT:'已发出',
+ SEND_FAILED:'发送失败', ABORTED:'未发即作废', ACCEPTED:'已受理',
+ SUBMITTED:'已报交易所', PARTIAL:'部分成交', FILLED:'全部成交',
+ CANCELLED:'已撤单', EXPIRED:'已过期', REJECTED:'被拒绝' },
+ cancelState: { NONE:'—', REQUESTED:'已请求撤', SENT:'撤单已发出' },
+ originType: { plan:'命令方案', proposal:'自主提议', system:'系统自动',
+ strategy:'交易方案' },
+ inboxState: { 0:'待入账', 1:'已入账', 2:'已消化', 3:'挂起待人工' },
+ connState: { INIT:'未启动', CONNECTING:'连接中', ONLINE:'已连上',
+ OFFLINE:'掉线', STOPPED:'已停' },
+ // 个股交易方案的自主档,取值与全局参数那套(full/propose_only/off)完全不同,
+ // 字段同名但不是一回事,绝不能合并成一组。
+ stratAutonomy: { auto:'自动执行', confirm:'待我拍板' },
+ dispatchMode: { shadow:'影子·不真下单', ws:'实盘下发' },
};
const tx = (g, c) => {
const m = T[g];
diff --git a/scripts/test_page_enum_guard.py b/scripts/test_page_enum_guard.py
index 3720ad0..c4f50d9 100644
--- a/scripts/test_page_enum_guard.py
+++ b/scripts/test_page_enum_guard.py
@@ -39,16 +39,41 @@ PAGE = os.path.join(os.path.dirname(HERE), "app", "web", "static", "index.html")
# 后端会送到页面的枚举字段。取值全集在 T 表里,两者要一起改。
# 只列**枚举**字段:后端已经写成中文句子的自由文本(basis、why、note 这类)不在此列,
# 那些本来就该原样显示。
+# 字段名到翻译组的对应。**同名不等于同组**:全局参数的 autonomy 是
+# full / propose_only / off(param_store.py:142),而个股交易方案的 autonomy 是
+# auto / confirm(strategy_service.py:23),两套取值完全不同。所以这份对应表里
+# 按"字段在哪个对象上"区分,不能只按字段名。
+FIELD_GROUP = {
+ "frozen_reason": "frozen", "cushion_state": "cushion", "lot_kind": "lot",
+ "arbiter": "arbiter", "stype": "stype", "ref_source": "refSource",
+ "autonomy": "autonomy", # 全局参数那一套
+ "strategy_autonomy": "stratAutonomy", # 个股交易方案那一套,取值不同
+ "judge_verdict": "judgeVerdict", "origin_type": "originType",
+ "cancel_state": "cancelState", "conn_state": "connState",
+ "proc_state": "inboxState",
+}
+
ENUM_FIELDS = [
"frozen_reason", # 冻结来路:COMMAND_HALT / BRAKE / MANUAL / NONE
"cushion_state", # 安全垫:SOLID / THIN / NONE
"lot_kind", # 批次:BASE / FILL / ADD / DCA / T0 / RECON
- "arbiter", # 谁裁的:rule / judge / user
+ "arbiter", # 谁裁的:rule / judge / user / system
"stype", # 交易方案类型:T0 / GRID / TRAIL
- "autonomy", # 自主档:full / propose_only / off
+ "autonomy", # 全局自主档:full / propose_only / off
"ref_source", # 参考位来源:bionic / self_calc / user / none
+ "judge_verdict", # 研判闸结论:PASS / REJECT / UNAVAILABLE / STRATEGY / STRATEGY_RISK
+ "origin_type", # 提议来路:plan / proposal / system / strategy
+ "cancel_state", # 撤单进度:NONE / REQUESTED / SENT
+ "conn_state", # 通道状态:INIT / CONNECTING / ONLINE / OFFLINE / STOPPED
]
+# 这三个字段的取值是**开放集**,不许声称全集,也不许在兜底里吞掉原值:
+# reject_code 由交易对端下发,协议文档明写可以补充
+# level 上游信号原样透传,本仓库没有产出方
+# accum_state 决策系统给的中文原文,本来就不需要翻译
+# 它们不进上面的名单,但在这里登记一笔,免得以后有人当成漏网又去补翻译。
+OPEN_SET_FIELDS = ["reject_code", "level", "accum_state", "msg_type"]
+
# 这些字段带 `CODE: ` 前缀,显示前必须剥掉。
CODED_FIELDS = ["failed_checks"]
@@ -132,9 +157,7 @@ def main():
# 五、翻译表与本文件的字段名单要对得上
for f in ENUM_FIELDS:
- group = {"frozen_reason": "frozen", "cushion_state": "cushion",
- "lot_kind": "lot", "arbiter": "arbiter", "stype": "stype",
- "autonomy": "autonomy", "ref_source": "refSource"}.get(f)
+ group = FIELD_GROUP.get(f)
if group and f" {group}: {{" not in src and f" {group}:{{" not in src:
bad.append(f"字段 {f} 在名单里,但 T 表里没有对应的 {group} 组")