Files
big-qmt/docs/strategy-audit-2026-09-12.md
2026-09-12 16:25:34 +08:00

87 lines
7.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# IPO、Trend、ZT 策略审计
复审日期2026-09-12。基线`7a7049ce44965d27c42f08ede1818d16495d8232` 加本次读取的工作区代码,包含手工修改及未提交文件。
范围三个策略及直接相关的委托簿、状态存储、SDK、服务端成交映射、网格和快照模块。本次只更新报告不修改策略、测试或生产数据不连接交易账户。
仅保留复审后仍需处理的问题。已修复及用户已标记忽略的条目、历史复现和过时统计已移除;编号沿用原报告。部分修复的问题仅描述尚未解决的策略范围。
## 结论
**待处理P0 0 项、P1 2 项、P2 2 项。** IPO 本次未确认新的待处理问题。
| 编号 | 级别 | 范围 | 问题 |
|---|---|---|---|
| P1-07 | P1 | ZT | 按委托编号去重,分笔成交可能漏记 |
| P1-08 | P1 | Trend | 超时撤单仍覆盖手工单及其他非 IPO 策略订单 |
| P2-01 | P2 | Trend | 止盈峰值跨仓位沿用 |
| P2-07 | P2 | 共用模块测试 | 旧 OrderBook 构造调用导致回归测试错误 |
P0 表示已确认的紧急严重风险P1 表示主要交易控制或记账问题P2 表示特定条件下的可靠性和回归验证问题。本次未确认 P0。
## P1
### P1-07ZT 按委托编号去重,分笔成交可能漏记
**位置:** [state.py](../py-client/libs/state.py) 第 55、146156、362389 行;[服务端成交映射](../api/qmt_rest_new.py) 第 371387 行;[ZT 启动](../py-client/strategy/zt/boot.py) 第 4951 行。
**证据:** 服务端将 `m_strOrderSysID` 映射为 `order_sys_id`成交表以该字段建立唯一索引。ZT 增量路径插入第一条后将编号加入 `existing`,其余同编号记录不再插入。不同 `ref`、时间和数量不参与身份识别。启动时两次成交查询也按此编号转成字典比较,会折叠同委托的多条记录。
**本轮复现:** 临时数据库中,同一委托编号、不同 `ref` 的 40 股和 60 股买入成交,对应账户快照为 100 股。`sync_account()` 仅记入 40 股并隔离该证券;重新加载数据库并再次同步,仍为 40 股,未恢复。
**影响与边界:** 逐笔回报可能漏记后续成交;累计回报也无法通过当前只追加逻辑更新已存数量。库存、金额及成本可能不完整,证券持续暂停交易。复现证明代码无法处理上述输入,不代表已确认目标柜台采用哪一种回报契约。
**修改建议:** 先核验实际回报是逐笔还是累计,以及唯一身份字段。逐笔回报透传真实成交编号并据此去重;累计回报按增量差额更新。启动稳定性比较也需保留完整回报。不要未经核验拼接时间、价格或 `ref` 作为唯一键;修改存储键时同时明确已有数据的处理方式。
**验收:** 同委托分笔成交累计为 100 股;重复查询和重启不重复记账;累计回报按已确认契约处理;初始化比较不因同编号覆盖而遗漏变化。
### P1-08Trend 超时撤单仍覆盖手工单及其他策略订单
**位置:** [Trend boot.py](../py-client/strategy/trend/boot.py) 第 40、119 行;[OrderBook.refresh()](../py-client/libs/order.py) 第 61、7788 行。
**证据:** Trend 启动及每轮运行均传入完整账户委托,未指定 `cancel_prefix`,默认值为 `None`。所有满足超时及可撤状态的非 `IPO-*` 委托都会进入撤单路径,包括空备注手工单和 `zt-*` 订单。
**本轮复现:** 四笔超时、状态 50 的模拟订单分别使用 `TREN-BUY-*``zt-base-*``IPO-*` 和空备注。按 Trend 当前调用方式刷新Trend、ZT 和手工订单触发撤单IPO 未触发;四笔均保留缓存。
**影响与边界:** 运行 Trend 可能干扰人工或其他策略希望继续等待的委托。本项仅保留 Trend 范围;当前 IPO 排除有效,不再沿用旧报告的 IPO 误撤结论。Mock 只能证明撤单调用,不能证明柜台受理。
**修改建议:** 若 Trend 只管理自己的订单应明确归属后限制自动撤单同时保留全账户在途防重。Trend 开仓使用信号前缀、持仓管理使用 `TREN-*`,不能简单改为单一 `trend-` 前缀。如果全账户非 IPO 撤单是预期行为,应明确记录这一范围后再决定是否关闭本项。
**验收:** Trend 自有超时订单能撤,手工单和其他策略订单不被 Trend 自动撤销;全部活动委托继续参与防重。
## P2
### P2-01Trend 止盈峰值跨仓位沿用
**位置:** [Trend positions.py](../py-client/strategy/trend/positions.py) 第 120121、198199 行;[Trend boot.py](../py-client/strategy/trend/boot.py) 第 60、113119 行;[网格跟踪器](../py-client/libs/grid_take_profit.py) 第 4474 行。
**证据:** Trend 使用普通 `GridTrailingTracker`,键仅包含账户及证券。清仓、重新建仓和补仓成本变化时,没有清理旧峰值;每轮快照更新也未同步网格生命周期。
**本轮复现:** 使用真实 `manage_positions()`、真实 tracker 和模拟委托簿,依次输入成本 10 元、价格 12 元的持仓,价格 11.9 元的同一持仓,空持仓,再输入成本 10 元、价格 11 元的新持仓。各步新增卖出调用次数为 `0、1、0、1`。新仓位第一次观察仍沿用旧峰值触发卖出。
**影响:** 重新建仓或成本基准变化后,当前收益率可能被当成旧仓位的回撤,提前触发止盈。本项仅保留 Trend 范围。
**修改建议:** 根据已确认的清仓、重新建仓及成本变化同步止盈基准。不要仅在提交成功时清理,避免撤单或部分成交丢失有效峰值。
**验收:** 新仓位首次观察只建立峰值;同一仓位正常回撤仍触发卖出;未成交提交、撤单及同一成本下部分卖出不误清理。
### P2-07OrderBook 旧构造调用导致回归测试错误
**位置:** [test_deal_model.py](../py-client/tests/test_deal_model.py) 第 71 行;[OrderBook 构造函数](../py-client/libs/order.py) 第 3538 行。
**本轮复现:** 测试调用 `ActiveOrders('trend')`,字符串被当成 `lock_timeout_sec`,在 `max(1, lock_timeout_sec)` 处抛出 `TypeError`。完整测试 86 项中 85 项通过、1 项错误、0 项断言失败。
**影响与边界:** 回归套件无法全绿。实际 Trend/ZT 入口已使用无参构造,本项不意味着策略必然启动失败。
**修改建议:** 将测试改为当前构造接口;撤单范围通过 `refresh()` 参数和调用方约定验证,不为旧测试重新引入已删除的构造参数。
**验收:** 该测试通过并保持默认刷新、ZT 范围过滤、IPO 排除和在途防重断言有效。
## 本轮验证及边界
- 完整执行 `unittest` 发现的 86 项测试85 通过、1 项错误,详情见 P2-07。其中 IPO 专项 15 项、ZT 相关 26 项全部通过。
- 额外执行真实状态同步、委托刷新和 Trend 持仓管理路径,分别复现 P1-07、P1-08、P2-01结果已写入对应条目。
- 验证使用模拟客户端及临时 SQLite 数据库,未发送真实委托、撤单或采集请求,未修改生产数据库和锁文件。
- 成交唯一身份、逐笔/累计语义及柜台实际受理结果仍需目标环境确认,未将未核验事实写成确定结论。
- 不新增旧 IPO 编号兼容要求,不恢复已忽略事项,不将已修复内容作为待办重复列出。