ek-ui 0.3.3

ek 生态常驻主界面(egui/eframe):插件即界面——观测页 + 日志页,车头与 UI 同插件
Documentation

ek-ui

ek 生态的常驻主界面 crate(DV-1:egui/eframe 0.33)。UI 即插件:观测窗不是宿主外壳, 与 dm/oms/ctp 同列的一个插件——总线面收事件维护共享快照,eframe 窗口面只读渲染。 (0.2.10 BD-UI-38 用户裁定:sim 纸面网关退场,ctp/SimNow 两套前置满足需求。)

零配置口径(2026-10-17 定盘):ek-ui 不读任何配置文件,界面本身无设置; 宿主侧同样不预读配置。插件结构只由 --from 清单或 demo 缺省决定。需要配置的 插件(唯一 = ek-ctp 虚拟账号),配置面长在插件自身——菜单「账户」面板提供 手工输入位(9 格,密码掩码;无订阅字段)与账户清单,经 ask {gw}.configure 进插件 (网关注册名由 broker + 账号派生 ctp_<broker>_<账号>,不写配置文件;ek-ctp 自带配置口: 0.3.0 引入,0.5.0 补 configure 强制重连);宿主与界面都不代读、不转发。 实连 CTP 需 --features ctp-native(默认关,日常构建不碰 C++)。

界面框架(v4,BD-UI-27/28;0.2.0 BD-UI-31 体验轮;0.2.2 BD-UI-32 字号与独立窗): 全局字号 16px 面(apply_ui_style);菜单栏(运维|账户|查询合约 一键直达弹窗,帮助保留菜单)→ 行情带(全宽、无题字,tick 唯一源,按交易所二级 tab,单击行带入下单面板,双击行弹 K线窗)→ 交易带(左下单面板无题字 9 字段 + 「自动开平」勾选 + 委托/全撤 + 盘口无题字;右 2×2 监控格「委托|未成交」「成交」「持仓」 「资金|日志」,列面逐值抄录 Python 蓝图:委托 17 列含名称/交易所/类型/来源, 成交 12 列(方向上色),持仓 16 列;撤单 = 行钮或双击委托行);全表行选中跳色 (行内任意格单击 = 选中,悬停淡底,每表一行;行情带选中 = 当前合约;行情带 盘口四列带入带方向:买1 价/量 → 卖,卖1 价/量 → 买,价格列顺带填价,其余列 方向保持默认)—— 查询合约窗与 K 线窗是独立 OS 窗(原生最小化/最大化/关闭,可拖出主窗放 屏幕任意处;不支持多窗的后端自动回退主窗内弹窗);运维/账户窗同为独立 OS 窗 (BD-UI-33 四窗一型),都不占主界面 tab。默认窗 1280×860。 表头固定与表头带(0.2.5/0.2.6,BD-UI-34;0.2.27,BD-UI-41 补 chrome):六张表 (行情带/委托/成交/持仓/日志/查询合约)表头固定——纵向滚动表头钉顶,横向滚动表头同移 (单 grid 列对齐 + 滚动区顶部覆盖带纯 painter 重画);空表表头照常在场。表头带照 qdarkstyle QHeaderView::section:带底 + 1px 下边线,表头字号比正文小一档 (Small 14 vs Body 16,Python 侧正是表头 13px < 正文 ≈14.7px);浮动窗里三张短表 (账户清单/运维插件表/服务目录)走 header_band 同一配色,服务目录本轮补上表头。 网格线只给查询合约表(Python 侧只有合约表开网格,交易表 setShowGrid(False)); 斑马纹改跟主题(visuals.striped,四套主题都是 false)。日志格从「monospace 行 + 定高 180px」换成带「时间/信息」表头的表 → 窗口最大化它跟着长。页签照 QTabBar::tab:top:未选中也有头底,选中多一条 3px 下划线;「成交」「持仓」两格补 单 tab(Python 四个区全是 QTabWidget)。K 线窗打开即最大化, ESC 快捷关闭。菜单栏「主题」钮一键循环五套配色(金融深色默认/egui深色/ egui浅色/Qt灰白/Qt深色),语义色(多红空绿等)跨主题恒定。「Qt深色」(0.2.26,BD-UI-40) 复刻 Python/PySide6 版的黑色主题 QDarkStyle 3.2.3:底 #19232D、按钮 #455364→#54687A→#60798B、 选中 #346792、圆角 4px、描边 1px。 薄下单者(0.1.1,BD-UI-30):下单/撤单不直发网关——全部走 oms.submit_order 五段管线(拆单/风控/逐腿发送/记账)与 oms.cancel_order(守卫不可绕过); 「自动开平」勾选 = 拆单四态的 Auto/None 逐请求开关(风控与守卫不可旁)。 订阅两入口(订阅不在账户面板定死;一律路由到行情元账号):下单面板代码框回车即订阅(带 EX. 前缀 自动剥成裸码);菜单「查询合约」 弹窗(查询框留空 = 全部 + 勾选 + 订阅选中)。合约流由 ek-ctp 登录后自动查询, UI 只收不催。多账号面只有一个行情元账号(账户面板指定,已装配后锁定), 订阅只发它 —— 纯 TD 账号收到订阅会静默成功却永远不来 tick,所以路由在界面侧定死。

账户状态列与『断开』(0.2.19,随 ek-ctp 0.9.0):账户面板状态列是两段—— 实例装配位(svctl.list 在场)+ 登录态(每 2 秒向每个已装配且在场的账户 ask 一次 {gw}.status 折出来):已装配·在线 / ·掉线 / ·登录失败 / ·查询断供 / ·已断开 / ·登录态未知。界面只认网关的 td_logged_in(纯行情账户认 md_logged_in), 「句柄已建」不当「在线」用、"从未回报过"不当"0 秒前回报过"用; 「查询断供」= 查询连续被拒达 3 次 或 资金回报超 30 秒未更新(阈值在界面,可覆盖)。 有话可说的行在面板底部给一句 状态细节 <派生名>:<原因>(带次数/秒数)。 『断开』走 {gw}.disconnect = 停会话(实例、配置、订阅、状态计数全留,『连接』可恢复); 『移除』走 svctl.remove = 停实例 —— 两个动作两条口,不共用。

三条口径写进界面(0.2.20,随 ek-ctp 0.9.1):① 收录勾选只管该网关自己收录并上抛的合约, 公用合约表 = 在场各网关的并集,改勾选须『连接/重试』才下发(面板底部与配置弹窗各写明一次); ② 运维窗不再对账户清册里的实例提供『移除』/『重注入』 —— 那一格改写成「起停归『账户』面板 (带撤单守卫)」,实例仍列在表里;清册外的 ctp_* 实例仍留这条出口;③ 日志溢出时同一行接上 「日志窗是窗口不是历史 —— 登录/掉线/查询被拒看状态列与状态细节,别回扫这里」。 状态细节另接 ek-ctp 0.9.1 的分项:合约查询被拒 N 次(与断供句并存,不重复点名)。

「从未到手」也会超时(0.2.21):「查询断供」三条判据 —— 连续被拒达 3 次 / 距最后一次资金回报 超 30 秒 / 登录后超 30 秒资金回报一次都没到手(实连读数照出来的:登录着、零被拒、None 一直不变 的账户,原来永远显示「在线」)。刚登录几秒不算;真到手即回在线。

中文渲染(BD-UI-26):启动时自动从系统字体目录装载 CJK 回退字体 (simhei 等,只收纯 .ttf/.otf);装载证据行 stderr 可 grep ([ek-ui] CJK 回退字体已装载: <path>)。候选全空时中文显形为豆腐块并 在 stderr 警告——属环境侧字体缺失,非界面缺陷。

快速开始

cargo run            # 无参:dm + oms + ui demo 窗(网关经运维窗 svctl 激活)
cargo run -- --pick  # 启动器:勾选插件 → 写清单 → spawn 子进程 → boot-wait
use ek_station::StationConfig;
let mut cfg = StationConfig::demo(); // = dm + oms
cfg.plugins.push("ui".into());
ek_ui::run_station_ui(&cfg, &ek_ui::runtime::RunOpts::plain())?;

launcher 协议(bin级):ek-ui --from <清单> --ready-file <标记>,start 成功即写 ready\n;ek-station --from ... 同 mate(清单由 --pick 窗生成)。 ek-ui --pick 走选窗 → 工作线程 spawn(30s 就绪上限;失败退 2,成功子进程分离脱管)。

自动化测试(S1b 起,人工核查 0 项)

  • L1:tests/ui_state.rs —— 环形日志/快照/revision/停止位(线程面状态机)。
  • L2:render_body(ctx, &UiShared) 单渲染入口(真实 App 与测试共用;面板组合 在入口内,BD-UI-29:菜单/行情带 TopBottomPanel + 下单侧栏 SidePanel + CentralPanel 2×2 格 + 弹窗最后)。
  • L3:tests/ui_kittest.rs(98 钉,0 ignore;0.3.3 起 W5 右键菜单不再挂起)—— egui_kittest 官方建构(ctx 级 build, render_body 自开顶层面板):AccessKit 节点断言、 清空日志 就地交互、下单面板入列(委托钮/坏价红字/全撤扇出)、代码框回车 订阅(s20:focus+type_text+key_press 全链)、委托行双击撤单(s11:建构用 with_step_dt(0.1),kittest 每事件一帧口径,BD-UI-28⑥)、行情带单击带入 下单面板、查询合约窗勾选订阅、菜单开窗(运维/账户/查询合约)、行情带 tab 切换、静态布局结构钉 s3(BD-UI-29:右列贴边不裁切/底行沉底 无死区/侧栏在左/两列等宽随窗分配)与满表列面钉 s21(委托 17/成交 12/ 持仓 16 列,布局泄漏与列面回归当场红)。「画出来但没有标签」的那一类 (表头带、tab 下划线、行线、toast、斑马缺席)走本帧绘制指令判据: egui::FullOutput.shapes 里的实心矩形 / 线段 / 文字形状 + 裁剪矩形。 0.3.2 起不出位图、不读像素、没有快照基线:tests/snapshots/ 已删, egui_kittest 的 snapshot / wgpu feature 已撤(口径见 DESIGN.md 「口径变更」与交接报告 §17);点击一律 click_accesskit (坐标点击只打可见钮,横向滚动面外控件用 AccessKit 动作),建构面统一 harness_for() 实窗尺寸,见 BD-UI-23/27/28/29)。
  • 列面口径(0.3.3 Wave F,BD-UI-51):成交表列序照 Python TradeMonitor;判据 f1 钉 「表体第 i 格 == 表头第 i 列」(F1)、持仓成本/均价取值(F2)、列序(F3)、 展示格式只住 src/format.rs(F4)。委托表/持仓表/行情带都吃「点表头排序」。 三处列差集(行情表交易所列 / 委托表操作列 / 枚举显示语言)的裁定写在 CHANGELOG 0.3.3。
  • 装配链:tests/ui_runtime.rs —— ui 工厂可装配、eTimer 1s 快照回路、 关窗协议(stop 位 → 观察线程 close_all → 全体 on_stop)。
  • 行情面:tests/ui_market.rs —— DM 金样本回放逐位、回灌闭环(帧统计三钉)。
  • 交易面:tests/ui_converter_chain.rs(3 钉;0.2.10 BD-UI-38 改写)—— oms 五段 管线全链(Auto 拆 2 腿今先/冻结/账本清零/parent 聚合)、mode None 单腿旁路、 手数闸拒 = 网关零接触;网关位 = 测试本地 "ctp" 受理夹具(受理形制忠实 ek-ctp, 成交按 CTP 回报行直发注入)。纸面网关 tests/ui_sim.rs(9 钉)与 ek-paper 引用 已随 sim 退场撤除(网关档案见 ek-paper, 历史 BD-UI-36;退场裁定 BD-UI-38)。
  • 运维面:tests/ui_ops.rs —— 命令队列往返/两步确认/检疫检测(u0–u2)+ 移除重启环与未知工厂拒装(t0/t1)。
  • 启动器:tests/launch.rs + tests/pick_ui.rs —— spawn/ready 协议、退出码、 选窗勾选写清单与派生。
  • 字体面:src/fonts.rs 单测 f0(22 常用汉字 has_glyph)+ kittest s16 汉字密集页 排版钉(BD-UI-26 乱码根因钉:字体装上了 + 这一帧真把整串中文排出宽度; 无 CJK 候选环境显形失败,属设计)。
  • CTP 配置面:tests/ui_ctp.rs —— ui→ask ctp.configure/ctp.subscribe 总线 闭环(空地址守卫日志、服务目录 5 口、校验拒面、ctp 不在场失败不炸链)+ kittest s13(手工表单入列逐位、窗面无订阅字段口径)。
  • CTP 实连(手工):tests/ui_ctp_live.rs —— --features ctp-native + --ignored 才跑;12 步全流程(判据三态 PASS/OBSERVE/FAIL,账号 env 手工注入)。

门禁

powershell -ExecutionPolicy Bypass -File scripts/gate.ps1

五闸:fmt --check / test / clippy -D warnings / doc / check-package(strict)。

依赖纪律

ek 生态件一律 crates.io 装版引用(运行时七件直接依赖:core/event/data/dm/ctp/oms/station; 0.1.1 起运行时还经 station 传递吃到第八件 ek-risk 0.1.x(风控闸装配,含多账号面的合约预检闸,见 CHANGELOG); dev-dep converter 0.1.1 已随 0.1.1 退役——拆单器入驻 oms 管线,见 CHANGELOG); 三方库只在本 crate(eframe = egui = egui_kittest = 0.33.3 四件套锁定,见 DESIGN BD-UI-7)。 remote 授权(2026-10-17 建仓):https://cnb.cool/enkeep/ek-ui(本仓)与 https://cnb.cool/enkeep/ek-station;此前为纯本地提交(方案 §3 双启动矩阵: ek-dm 同域纪律)。