Skip to content

merge: 将生产执行与交易安全改动合入 main - #10

Merged
PorridgeW merged 16 commits into
mainfrom
production-execution
Aug 27, 2026
Merged

PorridgeW merged 16 commits into
mainfrom
production-execution

Conversation

@PorridgeW

Copy link
Copy Markdown
Collaborator

本 PR 合并 production-execution 的完整改动,包括:\n- 强制订单类型与 UUID v7 幂等键,未知结果只读核验\n- 多账户选择、连接后显式核验及每笔交易前账户复核\n- 人工订单撤单二次确认、窗口安全保护与未知弹窗反馈\n- 委托表空表/占位行识别、市价导航兼容与撤单确认后柜台状态核验\n\n验证:pytest -q 通过(393 passed, 27 skipped);编译与 diff 检查通过。

BREAKING CHANGE: buy、sell、cancel 现均要求 client_order_id,且必须为 gl-<小写 UUID v7> 格式。调用方须在创建交易动作时生成并持久保存:新订单或新撤单使用新 ID;网络重发、query_order 查询同一动作时原样复用。交易端只校验与幂等防重,不生成或改写 ID。历史台账中的旧格式 ID 仍可通过 query_order 查询。

1. 下单与撤单幂等键强制化
   tools_schema、内置 fallback schema 和 dispatcher 同步要求 client_order_id;缺失、大小写错误、非 UUID v7、错误版本或 variant 的 ID 均在触碰交易端前以 invalid_params 拒绝。相同 ID 不同参数仍拒绝;相同 ID 重发绝不产生第二次交易动作。

2. submitted_unconfirmed 后的一次性只读核验
   buy/sell/cancel 首次执行或同 ID 幂等重放得到 submitted_unconfirmed 时,受控端自动执行一次限时只读核验,结果写入 data.auto_query。顶层回执仍保持 submitted_unconfirmed,核验超时、窗口忙或异常也不会掩盖未知语义;绝不自动重发下单或撤单。

3. 撤单结果精确核验
   cancel 的 client_order_id 标识撤单动作。未知结果时按首次撤单请求保存的目标 entrust_no 读取含终态的内部全量委托表,而非按买卖单启发式匹配。返回 cancel_state:已撤、部成后已撤、已成、仍在飞、废单、未知;仅已撤和部成后已撤表示柜台确认撤单成功。读取失败、零命中或多命中一律保守返回未知。query_order(撤单 client_order_id) 同样走此路径。

4. 查单关联收紧与台账回显修复
   买卖单缺少 entrust_no 时,启发式匹配新增方向校验;限价活跃委托还必须匹配委托价,防止将同代码但方向相反或价格不同的订单误认为本单。撤单台账不再覆盖原买卖订单的 entrust_no -> client_order_id 回显关联。

5. 契约、文档与测试同步
   README、PROTOCOL、工具 Schema 与 PyInstaller fallback 全部更新;新增 UUID v7 格式、自动核验、撤单终态、重复提交和启发式误匹配的覆盖测试。

测试:300 passed,10 skipped;git diff --check 通过。
BREAKING CHANGE: 默认配置下,cancel 不再直接撤销台账中没有 entrust_no 映射的人工/外部订单。首次 cancel 返回 confirmation_required、submitted=false、订单摘要和短时 confirmation_token;调用方展示摘要后,必须以新的 UUID v7 client_order_id 调用 confirm_external_cancel。调用方须处理 confirmation_required,不能把它自动重试为真实撤单。若业务允许无确认撤单,只能在受控端本地设置 external_cancel_confirmation=direct。

1. 任意订单可撤:已登记订单保持原 cancel 路径;人工/外部订单默认先按 entrust_no 读取全量委托表并返回摘要,提示阶段绝不点击 xiadan GUI。确认阶段消费一次性令牌后再次读表,严格比对合同号、代码、方向、价格、委托量、已成量与可撤状态;订单已成交/已撤、字段变化、读表失败或合同号不唯一均 submitted=false,停止撤单。

2. confirmation_token 仅进程内保存,60 秒有效、一次性使用、不写 SQLite。相同 cancel ID 重放会重新读表、换发令牌并使旧令牌失效;令牌已使用、过期、无效或连接切换后均返回 confirmation_required,且不点击 GUI。确认动作保存 entrust_no,query_order 可继续按合同号精确读取 cancel_state;台账无法保存提示回执时撤销令牌并拒绝。

3. WsClient.send_frame 返回 bool;断线、写异常或写入期间连接切换均为 False。order_watch/watchlist_watch 对未成功帧保留进程内 FIFO、原始 seq/ts,重连后按序重放;积压 order_event 不重新读取同花顺窗口,也绝不触发或重发真实交易。

4. xiadan 绑定增加唯一窗口、PID 与可执行文件身份校验。全局热键、鼠标点击、WM_CHAR、BM_CLICK、验证码确认和市价提交在实际发送前重新检查调用代次、前台焦点及目标控件归属;超时旧线程在后续检查点 aborted。已进入提交后的弹窗核验失败仍如实返回 submitted_unconfirmed。

5. 配置、桌面端开关、README、PROTOCOL、tools schema 与 fallback schema 同步;新增人工订单确认、令牌生命周期、断线 FIFO、窗口失焦/代次作废等回归覆盖。

测试:328 passed, 10 skipped;聚焦回归 188 passed;git diff --check 和 JSON schema 校验通过。
BREAKING CHANGE: 默认配置下,cancel 不再直接撤销台账中没有 entrust_no 映射的人工/外部订单。首次 cancel 返回 confirmation_required、submitted=false、订单摘要和短时 confirmation_token;调用方展示摘要后,必须以新的 UUID v7 client_order_id 调用 confirm_external_cancel。调用方须处理 confirmation_required,不能把它自动重试为真实撤单。若业务允许无确认撤单,只能在受控端本地设置 external_cancel_confirmation=direct。

1. 任意订单可撤:已登记订单保持原 cancel 路径;人工/外部订单默认先按 entrust_no 读取全量委托表并返回摘要,提示阶段绝不点击 xiadan GUI。确认阶段消费一次性令牌后再次读表,严格比对合同号、代码、方向、价格、委托量、已成量与可撤状态;订单已成交/已撤、字段变化、读表失败或合同号不唯一均 submitted=false,停止撤单。

2. confirmation_token 仅进程内保存,60 秒有效、一次性使用、不写 SQLite。相同 cancel ID 重放会重新读表、换发令牌并使旧令牌失效;令牌已使用、过期、无效或连接切换后均返回 confirmation_required,且不点击 GUI。确认动作保存 entrust_no,query_order 可继续按合同号精确读取 cancel_state;台账无法保存提示回执时撤销令牌并拒绝。

3. WsClient.send_frame 返回 bool;断线、写异常或写入期间连接切换均为 False。order_watch/watchlist_watch 对未成功帧保留进程内 FIFO、原始 seq/ts,重连后按序重放;积压 order_event 不重新读取同花顺窗口,也绝不触发或重发真实交易。

4. xiadan 绑定增加唯一窗口、PID 与可执行文件身份校验。全局热键、鼠标点击、WM_CHAR、BM_CLICK、验证码确认和市价提交在实际发送前重新检查调用代次、前台焦点及目标控件归属;超时旧线程在后续检查点 aborted。已进入提交后的弹窗核验失败仍如实返回 submitted_unconfirmed。

5. 配置、桌面端开关、README、PROTOCOL、tools schema 与 fallback schema 同步;新增人工订单确认、令牌生命周期、断线 FIFO、窗口失焦/代次作废等回归覆盖。

测试:328 passed, 10 skipped;聚焦回归 188 passed;git diff --check 和 JSON schema 校验通过。
BREAKING CHANGE: buy/sell 现在必须显式传入 order_type。LIMIT 必须传有限且大于 0 的 price;FIVE_LEVEL_IOC 禁止传 price,避免入口根据 price 缺失状态猜测实盘订单语义。

1. 买卖契约收紧:dispatcher、README、架构文档、公开 tools schema 和 fallback schema 同步增加 LIMIT/FIVE_LEVEL_IOC;非法、缺失或冲突的 order_type 在台账预留、窗口加锁和 backend 调用之前拒绝,返回 invalid_params 与 submitted=false。

2. 幂等指纹升级:order_ledger 将 order_type 纳入 client_order_id 请求指纹;同一 ID 在限价与五档即成剩撤之间切换时返回冲突,网络重试仍须原样复用原 ID 和原订单语义。

3. 弹窗反馈补强:恢复原有验证码 OCR、肯定按钮点击、Enter/WM_CLOSE 兜底处理;对未能确认类型的弹窗记录 unknown、reason、正文和实际 action,并通过 unknown_dialogs 写入回执,便于上游核对真实交易结果。

4. 回归覆盖:新增显式订单类型、价格约束、订单类型幂等冲突、弹窗分类和 unknown_dialogs 回执测试,并同步更新既有 dispatcher/schema 测试请求。

验证:339 passed, 27 skipped;git diff --check 通过;docs/tools_schema.json JSON 校验通过。
保留远端 production-execution 已发布的未登记订单撤单确认、断线队列和窗口安全改动,并整合本地后续修复与本次功能提交:

1. 保留成交表回执基线修复:按 v2 契约识别字符串成功码,允许空成交表作为合法基线,同时校验 data 必须为列表,避免正常空表被误判读取失败或历史成交被误算成本次成交。
2. 保留本地提交 0501bca:买卖显式 order_type、订单类型进入幂等指纹、未知弹窗反馈和对应回归测试。
3. 采用非强制合并方式保留远端提交,避免覆盖远端已有历史。

验证:339 passed, 27 skipped;git diff --check 通过。
1. 新增只读 list_accounts 工具:点击当前同花顺账户下拉 ComboBox,等待 0.5 秒后截取主窗口并 OCR 读取带 Alt+N 的账户行,不发送 Alt+N、不选择账户。

2. 根据 Windows 控件快照将账户下拉控件从未经证实的 0x06AF 修正为 0x0912,并在点击前核验 ComboBox、可见、启用及当前同花顺进程归属;运行时按控件重新查找,不缓存 HWND。

3. 保留账户名称 OCR 原文中的 *,同步更新 dispatcher、公开 schema、协议说明与回归测试;账户切换继续按 0x094C 文本核验并在失败时阻断买卖。

验证:相关测试 22 passed;完整测试此前 344 passed、27 skipped;JSON 校验、Python 编译检查和 git diff --check 通过。
每笔买卖、撤单及人工撤单确认前重新核对当前账户;异常时在读取订单表和发送交易输入前阻断。

从展开的 ComboLBox 直接读取账户列表,按显示顺序映射 Alt+1..Alt+9,并过滤编辑账户。

修正实机市价买卖顶层菜单路径;验证码处理后的无表头空表可作为空订单基线,普通无输出仍严格视为读取失败。

trader.log 写入 trader.* DEBUG 与脱敏的 WS/RPC 收发审计记录;令牌、密码、验证码和配对码不落盘。

补充账户核验、表格基线及日志脱敏回归测试。
账户下拉列表读取不再修改共享 SendMessageW 的参数签名,避免首次列账户后 0x094C 文本读取因二参数调用失败,使 switch_account 和后续 list_accounts 恢复可用。

RPC 内部异常改为记录完整堆栈;握手应答中的配对码和凭证字段统一脱敏。

新增 ListBox 调用隔离及握手日志脱敏回归测试。
市价单依次精确尝试顶层市价买入/卖出,以及市价委托下的买入/卖出,兼容两种已由 Windows 实机日志确认的菜单结构,且不会匹配普通 F1/F2 买卖入口。

限价委托基线与行规范化同时支持实际表头买卖,确保合同号、代码、方向、数量、价格的完整指纹可用于提交后可靠归属新订单。

补充市价路径回退、真实委托表头和买卖方向映射回归测试。
- 连接后上报可选账户,并要求通过 switch_account 明确选择后才允许交易\n- 切换按下拉列表目标核验,目标已是当前账户时不再误锁交易\n- 每笔买卖和撤单继续核对当前账户,读取或匹配失败即禁止交易\n- 识别带改价输入框的撤单确认弹窗并点击肯定按钮,不再误送验证码 OCR\n- 确认框缺少可识别肯定按钮时保留弹窗并返回未提交,避免误报成功
- 将列表账户与选择器账户按券商和脱敏持有人名核验\n- 仅允许选择器在两者之间附加营业部描述\n- 券商或持有人不一致、列表身份不唯一时继续阻止交易\n- 示例和测试均使用脱敏虚构文本
- 撤单确认后只读轮询 F3,唯一目标明确已撤/部撤才返回成功\n- 目标消失、仍在飞、状态不明或读表失败统一降级为 submitted_unconfirmed\n- 未确认结果沿用一次全量委托表自动核验,绝不再次点击撤单\n- 同步工具说明、协议与 F3 回执判定测试
@PorridgeW
PorridgeW merged commit e755d87 into main Aug 27, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant