交易系统工程 / 手动执行

SPXW 0DTE 控制台 —— 键盘驱动的手动执行面板

运行中

面板的完整导览:每个按键做什么、屏幕每个区域显示什么,以及面板之下的机器——作为唯一下单入口的显式状态机、以 broker 真相为准的仓位记账、主动追价平仓、硬软两层止损,和一条足以还原任何交易时段的审计日志。

这是什么

SPXW 0DTE 控制台是一个键盘驱动的手动执行面板,通过 Interactive Brokers TWS 交易 SPX 周度(SPXW)当日到期期权。它刻意不含任何策略与信号:人来决策、按键,软件唯一的职责是让这个决策被正确执行——或者按照既定规则拒绝执行。技术栈同样朴素:Python asyncio 后端(ib_insync)、经 WebSocket 连接的单文件 React 前端(零构建),持久化用 SQLite。

这是 v2 版本,针对 v1 面板运行的第一周产生的十二个 PR,其中六个实质性修复集中在同一层——订单与执行状态。本地仓位状态会偷偷偏离 broker 真相;执行逻辑是一锅互相纠缠的旗标;进程一崩,所有在途意图全部丢失,因为什么都没有持久化;IOC 加本地超时的平仓模型又天生和 TWS 服务器侧的价格管理打架。与其打第七个补丁,不如围绕三个承诺重新设计这一层:显式状态机、以 broker 真相作为仓位的唯一权威、持久化意图——并把 v1 的每一条教训固化为结构性不变量,而不是靠记性。

交易时段中的控制台:状态条、Call/Put 行权价面板、下单前预览、持仓条、风控条、控制区与日志/blotter。
交易时段中的控制台:状态条、Call/Put 行权价面板、下单前预览、持仓条、风控条、控制区与日志/blotter。

屏幕:从上到下

布局为时间压力下的扫读顺序而设计——五个区域,越重要越靠上。

**状态条。**连接模式(LIVE 或 DEMO)、SPX 与 ES 现货价及各自的报价延迟毫秒数、数据农场健康状态、AUTO-EXIT 开关状态、区分手续费的当日盈亏,以及当前执行状态。

**行权价面板。**左 Call 右 Put。每个面板自动瞄准第一档虚值(OTM)行权价,大字显示买卖价、点差与距现货点数,外加围绕目标刻意收窄的 ±2 档小梯子——v1 的二十行梯子被砍掉了,因为实际交易的永远是平值附近。LOCK 把目标钉在某个行权价上;ATM/OTM 微调按钮把目标上下移动一档。

**下单前预览。**这个面板的招牌新增:一块持续显示此刻每个按键会提交什么的区域——确切的合约、限价、美元成本、报价年龄,以及一个安全裁决。绿色表示就绪;红色裁决会写明拦截原因(实值行权价、报价陈旧、超保费上限),此时按键会被拒绝。它源自一次具体事故:数据源冻结后 SPX 现货一直停留在陈旧价位,行权价选择器选中了一张实值合约,而屏幕上没有任何东西在买入之前把这件事暴露出来。一块渲染”按键后果”的预览面,能在这一整类错误发生之前拦住它。

下单前预览显示两个按键均就绪,下方是持仓条与只读的风控条。
下单前预览显示两个按键均就绪,下方是持仓条与只读的风控条。

**持仓条。**执行状态、持仓、均价与浮动盈亏——或者干脆一个 FLAT。

**风控条。**只读显示当前武装着的每一道保护:−50% 硬止损、带触发门槛的移动止损、保本地板、日损停止线,以及数量与保费上限。软止损被关闭时,被压制的条目会以删除线渲染——面板绝不显示一道实际上并不生效的保护。

**控制区与日志。**可点击的按钮与按键一一对应(供触屏使用),旁边是数量步进器。日志/blotter 实时滚动每一次状态转移、订单、成交与告警,最新在上,每条都带原因。底部是 EMERGENCY STOP 紧急停止条。

键盘

动作
F1 / F2按预览的行权价买入 Call / Put。已持仓时,同向按键为加仓——钉在已持行权价上,绝不跟随漂移后的目标;反向按键会被拒绝(单方向规则)。
Space平仓:以主动追价把仓位平到 FLAT 为止。
Shift+Space紧急平仓——同样的追价,最高优先级。
Esc撤销在途的开仓单。
A切换 AUTO-EXIT(软止损层,见下文)。
R生成并打开当日交易时段报告。
长按 X(2 秒)紧急停止。刻意只杀应用、不动仓位——如果软件必须死,平仓这件事应该在 TWS 里做,而不是交给一个正在被怀疑的软件。

执行机器

面板之下是一台显式状态机——FLAT → OPENING → LONG → CLOSING → FLAT——它是整个代码库中唯一会提交订单的地方。每次状态转移都带原因落日志,并且天然幂等:OPENING 或 CLOSING 期间的重复指令由状态本身拒绝,而不是靠散落各处的旗标。

四个机制承担了大部分安全重量:

日志记录下的一次移动止损离场(最新在上):快速追价到达次数上限,交接给每 15 秒挂 bid 的耐心重试——硬止损仍然武装——随后重试成交。
日志记录下的一次移动止损离场(最新在上):快速追价到达次数上限,交接给每 15 秒挂 bid 的耐心重试——硬止损仍然武装——随后重试成交。

风控引擎:硬层与软层

保护被拆成权限不同的两层。

硬层无法从面板关闭:持仓上的 −50% 硬止损、触发即强平并锁定当日的日损 kill-switch,以及日终强平加”日终后禁止重开”锁。软层——带触发门槛的移动止损,和让冲高回落的盈利单在保本附近离场、而不是坐视其往返成亏损的保本地板——放在 AUTO-EXIT 开关(A 键)之后,留给想要纯手动离场的日子。这个开关的不对称性正是设计意图:关掉软止损时每一道硬保护依然武装,而风控条会明确显示哪些被压制了。

两条新鲜度规则贯穿所有风控。止损只在新鲜报价上行动——报价陈旧或无买价时,产生限频的降级告警而不是动作,原则是”不动比乱动安全”。开仓则以 SPX 现货的年龄为门,而不是数据源的 live 标志——那个标志一旦变成 live 就永不回退,数据源冻结后它会永远显示”live”。每个风控动作都先闩锁意图、再走与手动平仓完全相同的状态机路径;不存在绕过状态机下单的旁路。

可观测性

每个交易时段写两个文件:一份人读的应用日志,一份结构化事件流(JSON Lines,东部时间戳),经队列异步落盘,日志永不阻塞下单路径。每条指令都记录 SPX 现货、选中的行权价、距现货点数、报价年龄,被拒绝时附原因码——任何决策事后都能被还原。成交进入 SQLite blotter。

每个时段还盖有一条来源戳记:会话 ID 加上一个覆盖全部影响行为配置的哈希。不同日期的日志可以合并做后续研究,而绝不会悄悄混入两套配置——paper/live 标志也随每条记录同行。一条命令即可生成任意一天的时段报告——笔数、胜率、盈亏、离场原因与被拦订单统计——数据来自 blotter 与事件流。

刻意砍掉的东西

三个 v1 功能被有意移除。实时 Greeks:手动打点时没人读 Greeks 矩阵,它却消耗一个 IV 求解器和大半性能预算——距平值点数加点差就足以支撑决策。迷你 K 线图:真正的图在另一块屏幕的 TWS 里。以及一键反手(平仓即反向开仓):旧面板上最危险的一个键,改成了两步显式操作。

同样的品味也适用于运行时:不上 Rust、不引入编译型热路径。促成重写的那些失败全是状态机正确性问题,不是吞吐问题——50 毫秒的快照循环从来不是瓶颈,工程预算于是投给了状态机、持久化与对账。

模式与韧性

控制台按配置连接 paper 或 live 的 TWS 端点,当前模式作为标志随每条日志记录;状态条徽章则区分 LIVE(真实行情)与 DEMO(合成行情)。--demo 模式完全不需要 TWS,用合成行情驱动整个面板——包括完整的买入/平仓流程——供盘后熟悉操作。当日期权链不可用时(假日、盘后),面板降级启动而不是崩溃:起得来、亮出状态、拒绝交易。前端是响应式单文件,同时是可安装的 PWA(内联 manifest、独立窗口显示),同一面板可以在同网段的手机上使用。

同一时段在手机尺寸视口下的样子:五个区域叠成单列。
同一时段在手机尺寸视口下的样子:五个区域叠成单列。

工程状态

引擎已完成全部规划阶段,携带 258 项测试——单元、集成、对抗性 broker 模拟(晚成交、价格带拒单、断连、部分成交、注入漂移)与崩溃恢复演练——在逐 PR 的工作流下开发。十二条不可协商的安全不变量,每一条都标注着引发它的具体日期事故,把守着执行层的每一次改动。控制台自 2026 年 7 月下旬起投入日常使用,v1 面板保留作回退。