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} 组")