63 lines
7.0 KiB
Markdown
63 lines
7.0 KiB
Markdown
# PMS 三项对账差异排查与修复规格
|
||
|
||
2026-10-15,北京时间。对象是 155 模拟 PMS,ws 下发、propose_only 新建仓。188 真实仓不在本次范围。
|
||
|
||
## 事实与预判
|
||
|
||
只读 reconcile(apply_fix=False) 发现 002050.SZ 账本 800 / QMT 700,002979.SZ 账本 0 / QMT 1900,688100.SH 账本 2400 / QMT 1400。
|
||
八个委托的 trading_order.order_id 与 pms_qmt_order.instruction_id 相同,qmt_order_id 与 broker_order_id 也全部一致。
|
||
WebSocket 逐笔回报均 processed=1,汇总委托全部已进入 PMS_REPLAY_CURSOR.seen。
|
||
|
||
| 股票 | 当日重复回放的汇总数量 | 结果 |
|
||
| --- | --- | --- |
|
||
| 002050.SZ | 买入 100 | 净多 100;批次 1361 以委托限价 31.560 重复入账,逐笔实际为 73 股 30.690 和 27 股 30.650 |
|
||
| 002979.SZ | 卖出 1300、500、100、100,合计 2000 | 重复核销后数量扣到零,与 QMT 1900 不符;数量下限截断使差额不是 2000 |
|
||
| 688100.SH | 买入 700、卖出 400、买入 700 | 重复净买入 1000;部分重复买入又被错误认作外部 BASE |
|
||
|
||
根因在 ledger_service.replay_fills:注释承诺 trading_order 只兜外部/人工成交,实际没有排除本 PMS 的 WebSocket 委托。
|
||
这不是新计划版本造成的;三项当日账本更新时间均早于 10:42 PMS 部署。成交价格也因汇总表回退委托价格而被污染。
|
||
|
||
## 修复原理及边界
|
||
|
||
在 trading_order 回放认领前,以委托编号及券商编号精确查询本实例 pms_qmt_order,不按股票、时间和数量猜测重复。
|
||
属于本实例出口表的委托只由 WebSocket 逐笔入账,汇总镜像只推进既有 seen 游标并留跳过原因。
|
||
即使逐笔迟到、部分到达、联调单或当前模式已经切回 shadow,也不得从汇总表补记同一委托。
|
||
身份查不到的外部/人工成交保留原回放。身份读取失败、两个标识对应不同委托、代码/方向/券商身份冲突时,不入账、不记 seen,留错供下一跳重试。
|
||
单表 SQL,不新增表、调度或交易参数。历史账本与历史指令进度不由此补丁自动回写。
|
||
|
||
## 验收
|
||
|
||
先用合成数据复现双来源买入、卖出、部分成交与乱序。新增第 39 批测试;执行配置隔离与禁止联网的全量测试。
|
||
部署前再核验实例、在途委托与容器指纹;匹配候选镜像断网全量通过后,按本聊天授权重建 PMS 四进程。
|
||
真机检查健康、通道、回放无重复动作与只读身份分类。已有错账单独标记,不能把修复代码通过说成历史账已恢复。
|
||
|
||
## 历史修复约束
|
||
|
||
日终 RECON 只调数量,并会把差额按行情价格当成新增或核销,不能修复被污染的原始成本、已实现盈亏和指令 exec_qty。
|
||
因此不为消除告警直接 force 对账。先保存当前批次、原逐笔成交、汇总回放游标及指令快照,评估能否完整重建。
|
||
历史已有 RECON 与过往双记相互叠加;冻结证据不足时不能伪造无误差历史。任何后续修复须另存可逆备份与调整依据。
|
||
|
||
|
||
## 12:05 实测结果
|
||
|
||
修复提交 e9afc7a 已于 12:02:54 部署 155 四个 PMS 服务。新增 12 例、开发机全量 43 批、候选镜像断网全量 43 批均通过。
|
||
真实八笔委托的只读归属核验全部正确。健康、数据库、QMT 通道正常,待入账和在途出口委托为零。
|
||
当前为午休,修复后自然新成交回放尚待事件验证;三项历史差异仍保留,不报告为清零。
|
||
原始证据文件 ~/pms_logs/reconciliation-evidence-20261015-before-fix-v2.json 的 SHA256 为 8e0badf4d771fbf8a3227250c6cc2c2bf3c8234dda2fc33a31f0ab00920f5501。
|
||
原始交易持仓表额外出现 562590.SH 与 688825.SH 属另一项事实源覆盖差异,继续按既有 ws_first 取实际持仓,不混同三项账本差异。
|
||
|
||
|
||
## 历史修复开发规格与预判(2026-10-15 12:30,北京时间)
|
||
|
||
用户已明确授权先备份,再逐笔恢复数量、成本、盈亏和指令执行进度。修复限定 155 模拟仓 002050.SZ、002979.SZ、688100.SH。188 不在范围内。首份完整备份为主机 pms_logs/historical-repair-backup-20261015-1225.json,SHA256 为 81cfc59600d7ca07de7fc4b83b7c5b153719d0ea248be21fd9d910bcfc32e636。包含全部持仓、批次、指令、方案、命令、出口单、手续费、策略、提议、日报、净值,三票动作账本,完整留存逐笔成交及下游成交表。写前还要重新备份并校验并发变化。
|
||
|
||
实现采用纯函数重建与单表 SQL 事务写回。逐笔成交必须能唯一对应出口子单,代码、方向、委托号、累计数量一致;同成交号冲突、漏笔、卖超、外部成交无法解释、来源读取失败均阻断。每笔真实买入以父指令、数量、价格、原入账时间唯一对应原批次。重复买入批次须能聚合对应同一条下游汇总单,RECON 调整须单列;不能直接按数量差删除。真实卖出按既有批次优先级逐笔重算核销量与盈亏。原批次 ID 保留,虚假批次归零并注明备份与修复批号,不删除原证据。
|
||
|
||
成本使用成交金额或等价的“剩余批次成本减已实现盈亏”,避免三位小数核销均价再乘数量带来的舍入误差。费用不摊进成本;缺失费用保持未知。父指令按真实逐笔量与金额重建 exec_qty/exec_avg_price,同时在 progress 中保存原值、子单证据和剩余量。原误判完成但未足量的指令改为 CANCELLED 并记录“历史修复暂停剩余执行”,前提是所有子单均已终态,绝不恢复自动续单;原在执行的指令保持生命周期。真实超目标成交如 002979 的 1,300 股网格指令成交 2,600 股要如实保留并标异常。方案、命令当前为空,无需伪造。
|
||
|
||
完整性边界按当前留存批次的起始日验证,之前成交净数量必须为零。002050 从 09-22、002979 从 09-21、688100 从 10-14 重建。688100 的 08-27 至 09-01 已闭合旧轮次缺父指令及原批次,单列成交金额,不混入当前账期。历史安全垫峰值、手续费、过往日报与全组合净值如缺原始材料不宣称恢复;保存原值和修复附注。
|
||
|
||
写回只在受影响子单无在途、无未处理逐笔时进行。短暂停止 pms-beat 与 pms-worker,保留通道接收能力;所有快照比较和更新位于同一数据库事务,每条 SQL 仍经过表名前缀与单表守卫。事务写入审计记录;备份指纹不符、数据已变或中途失败均不提交。重复执行同一批号返回已完成。回退必须先比较修复后字段,若已有新成交则拒绝覆盖。写完只读核对,再恢复调度。
|
||
|
||
预判:重建后数量分别为 700、1,900、1,400;全部相关子单逐笔量等于累计量;虚假买入批次和 RECON 调整不再贡献成本或盈亏;指令真实进度不会因修复自动生成新单;原始成交、回放游标、策略阈值和明日启用门槛不变。测试覆盖金额、部分成交、漏笔、匹配歧义、并发、幂等、失败回滚及旧指令不复活。生产读回后逐条判收。
|