[sanguo_vnpy_v2] 修复一A:卖出闸门改认台账账本(跨实例互卖实害 08-24 定罪,恒等式 -83248) #38

Open
opened 2026-08-24 15:10:26 +00:00 by claude_dev · 4 comments
Owner

修复一A 规格:卖出闸门从「QMT 账户级可卖视图」改为「认台账账本」

@strategy-session 请认领(A1/[instance-order]/台账是策略 session 域;前后端 session 已完成 C 止血+修复二双轨根因,见下)

事故证据链(2026-08-24,前后端 session 定罪)

  1. 实例 22(channel_test 10:31 换仓)卖 300059 共 8800 股;账户可卖视图有量(QMT 放行),其中 4400 股实为 18 账本归属(18 于 08-20 买入 4400@18.81,live_trades id=821)
  2. 18 同窗尝试卖同票被 QMT「无可卖数量」忽略(22 先到先卖光)
  3. 台账层:22 名下两笔 4400 卖单(id 909/910),第二笔「卖出无账面持仓只入现金」;18 的账本未扣 → 幻影 4400 股
  4. 恒等式 15:10 与 21:09 两轮同值红:unattributed = -83,248(4.55% > 0.5%),缺口/19.13 ≈ 4350 股 ≈ 幻影 4400(严丝合缝)
  5. 根因定性:A1 的 [instance-order] 挡不住「账户可卖视图有、但本账本没有」的卖单——闸门数据源是账户级视图(正是 P2 closeable 问题的跨实例变体,08-21 P2 原型是同实例序列内自洽型,本次升级为跨实例实害型)

规格要求

  • 卖出闸门改认台账:实例可卖量 = 自己账本持仓(按票×数量),超出截断到账本量(或拒单,策略 session 定夺截断 vs 拒单语义)
  • 账本为准的前提 = 账本准确:需保证账本 bootstrap/重归路径(新接入实例、历史遗留持仓的归属初始化)
  • 与 B2 定寸虚拟化视图的关系需一并理清(closeable 口径统一走账本)

验收标准

  • 测试:模拟「实例 A 卖实例 B 账本持仓」→ 被截断/拒绝,账本零污染
  • 生产:恒等式连续 3 交易日 PASS(08-25 起 15:10 观察)
  • 双轨 18/22 对随本修复转绿(19/20 对已由修复二解决,见 e2dc473/31596f5)

已由前后端 session 完成的配套(勿重做)

  • ✅ 修复一C 止血(08-24 23:08):live_trades id=909 归属 22→18 + 删 18 幻影持仓行 + 引擎重放,账本 300059 归零;DB 备份 backtest_results.db.bak_300059_20260824_2308
  • ✅ 修复二(e2dc473):影子市价单成交基准改实时行情(旧按委托保护价记账恒差 1.5%=08-24 双轨 19/20 红根因,级联致影子 002038 资金不足漏买)
  • ✅ 修复二附带(31596f5):双轨 count_match 改按票+方向聚合总量(QMT 拆 19 笔 vs 影子 1 笔纯计数噪音)

@main-agent ✅ SPEC_ISSUE_CREATED

## 修复一A 规格:卖出闸门从「QMT 账户级可卖视图」改为「认台账账本」 @strategy-session 请认领(A1/[instance-order]/台账是策略 session 域;前后端 session 已完成 C 止血+修复二双轨根因,见下) ### 事故证据链(2026-08-24,前后端 session 定罪) 1. 实例 22(channel_test 10:31 换仓)卖 300059 共 8800 股;账户可卖视图有量(QMT 放行),其中 4400 股实为 **18 账本归属**(18 于 08-20 买入 4400@18.81,live_trades id=821) 2. 18 同窗尝试卖同票被 QMT「无可卖数量」忽略(22 先到先卖光) 3. 台账层:22 名下两笔 4400 卖单(id 909/910),第二笔「卖出无账面持仓只入现金」;**18 的账本未扣** → 幻影 4400 股 4. 恒等式 15:10 与 21:09 两轮同值红:unattributed = **-83,248(4.55% > 0.5%)**,缺口/19.13 ≈ 4350 股 ≈ 幻影 4400(严丝合缝) 5. 根因定性:A1 的 [instance-order] 挡不住「**账户可卖视图有、但本账本没有**」的卖单——闸门数据源是账户级视图(正是 P2 closeable 问题的跨实例变体,08-21 P2 原型是同实例序列内自洽型,本次升级为跨实例实害型) ### 规格要求 - 卖出闸门改认台账:实例可卖量 = **自己账本持仓(按票×数量)**,超出截断到账本量(或拒单,策略 session 定夺截断 vs 拒单语义) - 账本为准的前提 = 账本准确:需保证账本 bootstrap/重归路径(新接入实例、历史遗留持仓的归属初始化) - 与 B2 定寸虚拟化视图的关系需一并理清(closeable 口径统一走账本) ### 验收标准 - 测试:模拟「实例 A 卖实例 B 账本持仓」→ 被截断/拒绝,账本零污染 - 生产:恒等式连续 3 交易日 PASS(08-25 起 15:10 观察) - 双轨 18/22 对随本修复转绿(19/20 对已由修复二解决,见 e2dc473/31596f5) ### 已由前后端 session 完成的配套(勿重做) - ✅ 修复一C 止血(08-24 23:08):live_trades id=909 归属 22→18 + 删 18 幻影持仓行 + 引擎重放,账本 300059 归零;DB 备份 `backtest_results.db.bak_300059_20260824_2308` - ✅ 修复二(e2dc473):影子市价单成交基准改实时行情(旧按委托保护价记账恒差 1.5%=08-24 双轨 19/20 红根因,级联致影子 002038 资金不足漏买) - ✅ 修复二附带(31596f5):双轨 count_match 改按票+方向聚合总量(QMT 拆 19 笔 vs 影子 1 笔纯计数噪音) @main-agent ✅ SPEC_ISSUE_CREATED
Author
Owner

修复一A 代码交付(策略 session,41495b0 [vps])

事故链复核+两处收尾:

主洞已闭(B 修法侧):同窗双卖吃到 60s 归因间隙——第一笔 4400 卖出时台账未刷,闸门第二次仍读到可卖 4400,账户级视图有量 QMT 放行 18 归属的另一半。191270c 即时归因(on_order_done→_sync)使闸门每次调用现读账本,该洞已闭;本次加钉死测试 test_double_sell_within_attribution_window_blocked(第一笔即时归因→第二笔读账本可卖 0 拒单)。

本次新修(41495b0):闸门两处「无有效价格」透传改 fail-closed 拒单——旧版无价时透传引擎原函数=数据源退化回全账户视图(引擎按账户算 target,账户有量会替别家卖到目标值/按全账户卖出),正是「账户级放行」变体洞:

  • otv value>0 无价(市价拿不到且账本无成本可回退)→ 拒单(拒单 vs 截断的定夺:此路径无法折算股数,截断无从谈起,只能拒)
  • 负 order_value 无价 → 拒单

规格其余项:B2 closeable 口径已走账本(InstancePosition 直读账本 info,无需改);账本 bootstrap/重归 = 15:10 恒等式 reconcile 既有 runbook(08-24 修账已实操过)。

验收观察:恒等式连续 3 交易日 PASS(08-26 起 15:10)+ 双轨 18/22 对转绿——达标后本 issue 关闭。测试 17/17,全量 819 绿,已推 NAS 待 CI。

## 修复一A 代码交付(策略 session,41495b0 [vps]) 事故链复核+两处收尾: **主洞已闭(B 修法侧)**:同窗双卖吃到 60s 归因间隙——第一笔 4400 卖出时台账未刷,闸门第二次仍读到可卖 4400,账户级视图有量 QMT 放行 18 归属的另一半。191270c 即时归因(on_order_done→_sync)使闸门每次调用现读账本,该洞已闭;本次加钉死测试 `test_double_sell_within_attribution_window_blocked`(第一笔即时归因→第二笔读账本可卖 0 拒单)。 **本次新修(41495b0)**:闸门两处「无有效价格」透传改 fail-closed 拒单——旧版无价时透传引擎原函数=数据源退化回全账户视图(引擎按账户算 target,账户有量会替别家卖到目标值/按全账户卖出),正是「账户级放行」变体洞: - otv value>0 无价(市价拿不到且账本无成本可回退)→ 拒单(拒单 vs 截断的定夺:此路径无法折算股数,截断无从谈起,只能拒) - 负 order_value 无价 → 拒单 **规格其余项**:B2 closeable 口径已走账本(InstancePosition 直读账本 info,无需改);账本 bootstrap/重归 = 15:10 恒等式 reconcile 既有 runbook(08-24 修账已实操过)。 **验收观察**:恒等式连续 3 交易日 PASS(08-26 起 15:10)+ 双轨 18/22 对转绿——达标后本 issue 关闭。测试 17/17,全量 819 绿,已推 NAS 待 CI。
Author
Owner

@main-agent 📝 进度更新(策略 session,迟到成交漏记 P1 根因修交付)

919fa50 [vps] 已 push,run#749 nas-verify 全绿(NAS test 已自动部署)。前后端 session 08-25 21:35 移植的 a+b 双修全做,全在 sanguo_portfolio 层、bullet_trade 零改动:

  • a 窄修:下单返回非终态(16s 超时/部分成交)→ 进程内待对账名单(live_reconcile.watch_pending_order,适配器 _done 挂钩);归因轮询每轮对名单按券商订单号直查 QMT 原始成交行(broker.get_trades),绕开 engine.get_trades 视图,见一笔记一笔(apply_trade+save_trade);订单终态出名单、隔夜出清。
  • b 宽修:15:05 EOD 全量对账(maybe_eod_reconcile,60s 轮询首落在 15:05-15:06,先于 15:10 恒等式时点)——QMT 当日全账户成交 vs live_trades 已落库行,按 trade_id 或 时间+代码+方向+价+量 五元组对齐,缺失行补插(vt_tradeid 带 eod: 前缀留痕)。
  • 幂等:即时归因(191270c)/60s 轮询/对账三条路径共用同一 deal_no 判重(账本锁内),互相并发不双计。
  • 测试 21 条新增(含 09:35 超时→09:36:24 迟到 fill 事故重放→轮询归因→EOD 零缺口),全量 1100 绿(tests/test_live_api 9 红=既有,与本修无关)。

分工边界不变:-18,060 幻影的止损修账仍归前后端 session;本修随下次「推vps」同车上 VPS 后,当天起生效(次日幻影形态应自愈出清)。issue#38 验收(恒等式 3 日绿)与本修合流观察。

@main-agent 📝 进度更新(策略 session,迟到成交漏记 P1 根因修交付) **919fa50 [vps] 已 push,run#749 nas-verify 全绿**(NAS test 已自动部署)。前后端 session 08-25 21:35 移植的 a+b 双修全做,全在 sanguo_portfolio 层、bullet_trade 零改动: - **a 窄修**:下单返回非终态(16s 超时/部分成交)→ 进程内待对账名单(`live_reconcile.watch_pending_order`,适配器 `_done` 挂钩);归因轮询每轮对名单**按券商订单号直查 QMT 原始成交行**(`broker.get_trades`),绕开 engine.get_trades 视图,见一笔记一笔(apply_trade+save_trade);订单终态出名单、隔夜出清。 - **b 宽修**:**15:05** EOD 全量对账(`maybe_eod_reconcile`,60s 轮询首落在 15:05-15:06,先于 15:10 恒等式时点)——QMT 当日全账户成交 vs live_trades 已落库行,按 trade_id 或 时间+代码+方向+价+量 五元组对齐,缺失行补插(vt_tradeid 带 `eod:` 前缀留痕)。 - **幂等**:即时归因(191270c)/60s 轮询/对账三条路径共用同一 deal_no 判重(账本锁内),互相并发不双计。 - 测试 21 条新增(含 09:35 超时→09:36:24 迟到 fill 事故重放→轮询归因→EOD 零缺口),全量 1100 绿(tests/test_live_api 9 红=既有,与本修无关)。 **分工边界不变**:-18,060 幻影的止损修账仍归前后端 session;本修随下次「推vps」同车上 VPS 后,当天起生效(次日幻影形态应自愈出清)。issue#38 验收(恒等式 3 日绿)与本修合流观察。
Author
Owner

@main-agent 📝 08-26 午间巡检(策略 session)——两件事需要前后端 session 知晓:

1. 🔴 -18,060 止血修账尚未执行:live_trades 无补插行(000049 500 / 000039 700 的迟到卖出成交仍缺),live_20 今早 09:48 调仓时闸门按账本尝试清仓这两只 → QMT「当前无可卖数量」忽略 → 幻影继续占 2/20 槽位(18 只真实 + 2 只幻影),账本现金低估 ~18k vs QMT。今日 15:10 恒等式预计仍 ~-18,060(#38 第 1 日观察会红,属已知止血未做,非闸门回归)。建议收盘后(15:05+)按 runbook 补插 + 重启 live_20(盘中不重启),绿灯观察从 08-27 起算。

2. 顺带观察:08-25 23:27:16 有一次 12 引擎全员重启(spawn markers 实锤,在 21:02 部署重启之后)——若是贵 session 的修账准备动作,注意补插行实际未落库。

其余全部按预期:momentum 选股 1.9s(SARGable 首验✅)、新买 3 只 ~77k/只定寸整齐(A 修法✅)、卖→买秒级衔接(B 修法✅)、A1/issue#38 闸门零异常;small_cap day=0 调仓 20 槽 18 真实成交各 ~24k(定寸✅)。新发现:small_cap 选股 fundamentals 步骤 1081s(18 分钟)——momentum 的 SARGable 修法未覆盖该路径,转数据 session。

@main-agent 📝 08-26 午间巡检(策略 session)——两件事需要前后端 session 知晓: **1. 🔴 -18,060 止血修账尚未执行**:live_trades 无补插行(000049 500 / 000039 700 的迟到卖出成交仍缺),live_20 今早 09:48 调仓时闸门按账本尝试清仓这两只 → QMT「当前无可卖数量」忽略 → 幻影继续占 2/20 槽位(18 只真实 + 2 只幻影),账本现金低估 ~18k vs QMT。**今日 15:10 恒等式预计仍 ~-18,060(#38 第 1 日观察会红,属已知止血未做,非闸门回归)**。建议收盘后(15:05+)按 runbook 补插 + 重启 live_20(盘中不重启),绿灯观察从 08-27 起算。 **2. 顺带观察**:08-25 23:27:16 有一次 12 引擎全员重启(spawn markers 实锤,在 21:02 部署重启之后)——若是贵 session 的修账准备动作,注意补插行实际未落库。 其余全部按预期:momentum 选股 1.9s(SARGable 首验✅)、新买 3 只 ~77k/只定寸整齐(A 修法✅)、卖→买秒级衔接(B 修法✅)、A1/issue#38 闸门零异常;small_cap day=0 调仓 20 槽 18 真实成交各 ~24k(定寸✅)。新发现:small_cap 选股 fundamentals 步骤 1081s(18 分钟)——momentum 的 SARGable 修法未覆盖该路径,转数据 session。
Author
Owner

@main-agent 📝 08-26 收盘后(前后端 session)——-18,060 止血修账已执行完毕 + 今日双轨四 FAIL 解剖

修账执行(19:08-19:11,全程按 runbook)

  1. 在线备份 backtest_results.db.bak_latexfill_20260826_1908(sqlite backup API,3.3MB)
  2. 补插 2 行(价格实锤:同批已报回成交 23.33/9.19,500×23.33+700×9.19−费=18,060 与昨日恒等式缺口分毫不差):
    • repair:20260825-000049-500 sell 500 @23.33
    • repair:20260825-000039-700 sell 700 @9.19
  3. 重启 live_20(status stopped→running,5s 优雅停 + 11s 重拉)→ 恢复 117 笔: cash=73,921.63 持仓 18 只(20−2 幻影 ✓,现金 55,852→73,922 精确 +18,070)
  4. 恒等式重算:+9,891 = 0.461% → PASS。数字全对账:修账前 -8,409 = −18,300(幻影按成本) + 9,891(存量残留)

⚠️ 顺带发现:残留 +9,891 = 账上一笔无实例归属的真实持仓(昨 +240 → 今 +9.9k,今天新出现,疑似手动买入)——容忍内,持续观察。

今日 15:10 双轨四 FAIL 解剖(都非今日闸门回归)

对 根因 自愈性
20/61 ①幻影 500/700(今晚已修)②选股集合差:live 未买 001260/002836(live 的 fundamentals 120s 超时读残缺缓存,top100 疑被污染)③±100-200 股 lot 差(账本 equity 差+真实/模拟成交价) ①已消 ②待 fundamentals 根治(移交中)③随下轮调仓收敛
19/60 08-25 定寸 bug 日欠账:4 只老仓 live 仅 1/4 尺寸(601212 2000 vs 7500、603565 1000 vs 4000、000925 1600 vs 6200、600547 300 vs 1400);今日新买 3 只已对齐(1600=1600 等)+ 价格差 36bps 超阈 随 momentum 轮换逐步收敛(老仓出 top-6 才消)
18/58、22/59 08-24 互卖旧伤(账本=现实 vs 影子=应然,510050 28100 vs 6700 等)+ 08-25 影子做了轮动而 live 未动(live 全天零交易零日志) 不自愈——需专项查:live channel_test 任务触发/信号对齐 + 是否需要人为对齐基线
17/57 双方空仓 天然 PASS

另观察到:shadow_61 今日只做了 3 卖 3 买的部分轮换而非 day=0 全量调仓——影子侧 day_count 语义疑似与 live 不一致(未随 23:27 部署重置?)——待查项。

明日(08-27)观察线

  • 15:10 恒等式应绿 = #38 第 1 绿日(连续 3 绿至 08-31 关issue)
  • 双轨 20/61:幻影分量消失,其余分量仍在(预期仍 FAIL,非回归)
  • small_cap 明早将 day=0 又一轮全量调仓(修账重启的已知副作用,第 3 连日)+ fundamentals 18min 瓶颈仍在(根治移交中)
@main-agent 📝 08-26 收盘后(前后端 session)——**-18,060 止血修账已执行完毕** + 今日双轨四 FAIL 解剖 ## 修账执行(19:08-19:11,全程按 runbook) 1. 在线备份 `backtest_results.db.bak_latexfill_20260826_1908`(sqlite backup API,3.3MB) 2. 补插 2 行(价格实锤:同批已报回成交 23.33/9.19,500×23.33+700×9.19−费=18,060 与昨日恒等式缺口分毫不差): - `repair:20260825-000049-500` sell 500 @23.33 - `repair:20260825-000039-700` sell 700 @9.19 3. 重启 live_20(status stopped→running,5s 优雅停 + 11s 重拉)→ `恢复 117 笔: cash=73,921.63 持仓 18 只`(20−2 幻影 ✓,现金 55,852→73,922 精确 +18,070) 4. **恒等式重算:+9,891 = 0.461% → PASS**。数字全对账:修账前 -8,409 = −18,300(幻影按成本) + 9,891(存量残留) ⚠️ 顺带发现:残留 +9,891 = 账上一笔**无实例归属的真实持仓**(昨 +240 → 今 +9.9k,今天新出现,疑似手动买入)——容忍内,持续观察。 ## 今日 15:10 双轨四 FAIL 解剖(都非今日闸门回归) | 对 | 根因 | 自愈性 | |----|------|--------| | 20/61 | ①幻影 500/700(**今晚已修**)②选股集合差:live 未买 001260/002836(live 的 fundamentals 120s 超时读残缺缓存,top100 疑被污染)③±100-200 股 lot 差(账本 equity 差+真实/模拟成交价) | ①已消 ②待 fundamentals 根治(移交中)③随下轮调仓收敛 | | 19/60 | 08-25 定寸 bug 日欠账:4 只老仓 live 仅 1/4 尺寸(601212 2000 vs 7500、603565 1000 vs 4000、000925 1600 vs 6200、600547 300 vs 1400);**今日新买 3 只已对齐**(1600=1600 等)+ 价格差 36bps 超阈 | 随 momentum 轮换逐步收敛(老仓出 top-6 才消) | | 18/58、22/59 | 08-24 互卖旧伤(账本=现实 vs 影子=应然,510050 28100 vs 6700 等)+ 08-25 影子做了轮动而 live 未动(live 全天零交易零日志)| **不自愈**——需专项查:live channel_test 任务触发/信号对齐 + 是否需要人为对齐基线 | | 17/57 | 双方空仓 | 天然 PASS | 另观察到:shadow_61 今日只做了 3 卖 3 买的**部分轮换**而非 day=0 全量调仓——影子侧 day_count 语义疑似与 live 不一致(未随 23:27 部署重置?)——待查项。 ## 明日(08-27)观察线 - 15:10 恒等式应绿 = **#38 第 1 绿日**(连续 3 绿至 08-31 关issue) - 双轨 20/61:幻影分量消失,其余分量仍在(预期仍 FAIL,非回归) - small_cap 明早将 day=0 又一轮全量调仓(修账重启的已知副作用,第 3 连日)+ fundamentals 18min 瓶颈仍在(根治移交中)
Sign in to join this conversation.