本文是 post_clear_check 按清算步骤补核对的目标设计。窗口 1 落地之前,现行代码口径仍以 doc/业务链路核对设计.md 第 5 节为准;本文是改造目标,两份文档不同时自称现行。
实现按第 9 节的五个窗口串行做。每个窗口开工时把该窗口状态从「未做」改成「本窗口」,做完再改成「已完成」。本文不改核对代码,也不改 .cursor/skills/post-clear-check/SKILL.md。
POST_CLEAR_CHECK_OWN_HOST 上的自有库:不做。见第 7 节。数字公式仍以 docs/tmp/product_prototype/共赢票据重要字段、计算公式等说明V2.xlsx 和产品原型为准。架构文档只决定读哪一份快照、哪一列是输入、哪一列是产出。
三端清算口径只认下面这些:
| 文档 | 用途 |
|---|---|
docs/架构设计/清算/00_清算系统架构重构总纲.md |
两阶段模型、六项准则、发布与门禁 |
docs/架构设计/清算/01_TRS端清算重构详细方案.md |
TRS 十步、事实与数据集 |
docs/架构设计/清算/02_发行端清算重构详细方案.md |
发行六步、固定归档 |
docs/架构设计/清算/03_销售端清算重构详细方案.md |
销售七步、钱包与上游版本 |
docs/架构设计/清算/实施计划/ 下三份实施计划 |
代码落点。与方案正文冲突时,以实施计划里「代码与本计划以此为准」的补记为准 |
docs/清算/测试证据/ 下的 md |
只证明重构已按上述口径落地,不当核对公式 |
不读、本文也不引用这四份旧文:
docs/清算/三端清算最终实施方案.mddocs/清算/发行端A股清算与营业日日切实施细节V1.mddocs/清算/连续漏清与跨交易日补清修复.mddocs/清算/清算与最近批次重算技术实施方案V1.md事后能读到哪张表,以当前代码和 DDL 为准,不以方案正文里「拟新增」的句子为准。
工具自身的链路合同、飞书版式、依据三种写法,仍以 doc/业务链路核对设计.md 为准。改某一条链路的节点时,先改该文档第 4 节的该条,再改代码。步骤挂靠以本文第 5 节为准;窗口 1 会把业务链路核对设计的第 5 节改成指向本文。
三端是同一个模型:
Cleared_T = 上一日已发布结果 + 本轮冻结的 T 日事实与参数
Live = 把 T 日结果按后续已记账事实投影出去
T 日候选在发布前就封存。后续事实不回写进候选。
flowchart LR
baseline[上一日已发布结果]
frozen[本轮冻结输入]
stepSnap[分步工作快照]
cleared[T日候选]
live[实时投影]
baseline --> stepSnap
frozen --> stepSnap
stepSnap --> cleared
cleared --> live
核对必须绑已发布的那一份数据集,不能按 batch_id 把一个批次里所有轮次的归档行加在一起。发行重算复用 batch_id,换 dataset_revision,对外只认 published_flag=1 的那条。销售、TRS 重算是新批次,仍只读该批次已发布的那份数据集。
库是 db_issue_clear。一轮清算一个 clearing_dataset。clr_* 用 archive_stage 加 archive_step_no 区分范围:
| 范围 | 含义 |
|---|---|
input/0 |
第 2 步冻结的事实和参数 |
work/2、work/3、work/4 |
第 2、3、4 步完成时的不可变快照 |
cleared/0 |
第 5 步从 work/4 复制的 T 日结果 |
没有 work/5。当前投影不归档,只在实时表和 clearing_writeback_log。发行这份回写日志没有 source_cursors。报表读 cleared。运行期动态表 clearing_table_backup 已退役。
因此发行第 2、3、4 步可以按留下的快照分别核对。第 5 步的 T 日结果读 cleared/0,它应与 work/4 一致;当前投影另算,不把实时票据当成 T 日结果。
clearing_dataset.kind 三份职责不同:
| kind | 能否当留存快照 |
|---|---|
input |
能。只读事实,第 2 步封存后不改 |
pre_clearing |
不能。第 3、4、6 步会改写它,终态既不是第 2 步也不是第 3 步 |
cleared |
能。第 5 步封存的 T 日候选,第 6 步不回写它 |
note_view 是第 6 步投影。第 7 步才发布,并用候选生成日终和报表。
因此销售第 3 步和第 4 步没有各自的快照,只能用 input 重算,再和第 5 步的 cleared 比。钱包只核这个 T 日结果,不读实时钱包,也不把营业日晚于 T 的流水加进 T 日结果。
事实和参数在本批 kind=pre_clearing、copy_no=1 的只读分区,以及 clearing_snapshot。第 5、6 步把计算结果写进同一工作集。第 7 步才把 T 日结果复制为 kind=cleared。批次完成前这份候选的状态是 backing_up,第 10 步才切到 available。工具只在批次 completed 之后开跑,此时应能读到 available。
T 日汇率调整在 clearing_snapshot.entity_type='clearing_fund_ledger'。TRS006 合并本批原始流水快照和这份调整,不回查实时 fund_ledger。
TRS 以第 7 步的 cleared 为 T 日终态。第 5、6 步写同一工作集(kind=pre_clearing、copy_no=1)。replace_mirror_rows 只替换本步传入的实体,按数据集整表删除再插入,没有各自留存的快照。第 7 步把该工作集克隆为 kind=cleared(完成前 backing_up,第 10 步才 available)。
窗口 1 对写入点的只读确认:clr_fund_account 只在第 5 步的 strong_rows 里替换(result["funds"])。第 6 步的 strong_rows 只有 trade_order 和 user_position,不替换资金账户,第 5 步各列保留到 cleared。clr_user_position 第 6 步整行替换:build_step6 先复制第 5 步的持仓行,再把 available_qty 写成 position_qty、frozen_qty 写成 0,并重写 market_value、float_pnl、book_float_pnl。position_qty、cost_amount、cost_px、book_cost_amount 和身份列原样带过。被覆盖的可用、冻结和估值没有独立留存。
窗口 5 不把第 5 步和第 6 步拆成两份快照节点。cleared 上数量和成本仍是第 5 步的值,可用、冻结和估值是第 6 步写在同一行上的结果。
仍只有两种处理:挂到已有链路,或明确不支持。批次级的是/否检查挂「核对门禁」,不挂到主订单、资金账户或用户账号上。
不支持的步骤不写进卡片「涉及」,也不发卡。已经挂上节点的步骤要写进「涉及」。涉及行用下表「名称」列的原文,这就是三端代码里的步骤名,不另起简称。名称还写着「备份」「票据激活」的,核对内容以「挂到哪里」为准,不按旧名称去找物理副本或激活消息。
| 步骤 | 名称 | 结论 | 挂到哪里 |
|---|---|---|---|
| 1 | 开启清算 | 挂靠 | 核对门禁。查已发布数据集的 baseline_kind、base_dataset_id,以及本批固定的 TRS 版本仍是该日当前发布版本。没有金额公式 |
| 2 | 备份清算前数据 | 挂靠 | 买入执行、卖出执行、票据存续、增额、展期、资金交收。见下文 |
| 3 | 订单及票据处理 | 挂靠 | 已在买入执行、卖出执行、票据存续、增额、展期。补 work/3 节点 |
| 4 | 交易交收处理 | 挂靠 | 已在资金交收。补 work/4 节点 |
| 5 | 备份清算完成的数据、生成营业日日终数据与核心日常报表、更新T+1实时数据 | 挂靠 | 报表和 T 日订单结算读 cleared/0;当前投影另挂票据存续和买卖执行 |
| 6 | 确认交易日切换、推进营业日、票据激活、清算完成 | 挂靠 | 核对门禁。营业日已推进,且该日只有一个 published_flag=1。不写金额式。激活已前移到第 5 步,本步不再核激活消息 |
第 2 步节点:
input/0 的客户执行事实列(成交名义本金、均价)与源表一致。order_qty、fx_settle 是清算产出,不得拿实时表当输入。work/2 的期初等于上一已发布 cleared 的结转。第 3 步补节点:work/3 的结算口径等于用 input 和封存费率、汇率算出的结果。现有「报表对不对」保留,报表对 cleared,不对实时票据。
第 4 步补节点:work/4 从上一日未交收加本日订单推演。本批交收不重复。历史单不因首次写成 T 日交收而在重算中消失。
第 5 步:cleared/0 应与 work/4 一致。实时值等于 cleared 加后续事实,客户终态订单不被改写。yesterday_* 是第 5 步从本轮 T 日结果滚入的物化值,挂票据存续;清算公式本身不读这几列当输入。
| 步骤 | 名称 | 结论 | 挂到哪里 |
|---|---|---|---|
| 1 | 开启清算 | 挂靠 | 核对门禁。manifest 里的发行 batch_id:cleared_dataset_id 必须等于发行该日当前已发布轮次 |
| 2 | 备份清算前数据 | 挂靠 | 账户资产、资金变动、资金交收。只读 kind=input |
| 3 | 订单及票据处理 | 挂靠 | 与第 4 步合成核对,见下文。不读 pre_clearing 的终态当第 3 步结果 |
| 4 | 交易交收处理 | 挂靠 | 与第 3 步合成核对 |
| 5 | 备份清算完成的数据 | 挂靠 | 账户资产。cleared 不含 business_date>T 的流水,也不含后续当日买卖 |
| 6 | 更新T+1交易日的票据详情实时数据 | 挂靠 | 票据存续。本步写入的实时钱包不进入钱包核对 |
| 7 | 营业日日切 | 部分挂靠 | 报表节点保持原链路,改为对候选。延后流水挂资金变动。发布成功挂核对门禁 |
第 2 步:当日原始流水排除 clearing_step_no IN (3,4)。上一批仍未交收的第 3 步买卖流水会原样封进下一日 input,步骤号仍是 3,这是历史未交收来源,不是当日原始流水。期初钱包等于上一日已发布 cleared,不是实时余额减去后续发生额。
第 3、4 步:没有独立快照。在账户资产、资金变动、资金交收上,用 input 加第 1 步固定的发行结果重算,与 cleared 比。第 3 步之后 T 日 buy_today/sell_today 必须为 0。
第 6 步:实时钱包不进入核对。note_view 按发行当前状态版本写入,低版本不覆盖。这个当前值不得写进 clr_note_view_cleared。
第 7 步报表归属不变:OTC001 账户资产,OTC002 资金变动,OTC003 买入执行与卖出执行,OTC004 票据存续,OTC007、OTC008、OTC010 资金交收。这些报表对候选,不对实时钱包。延后入站和 relay 资金回调的流水营业日是切日之后的营业日。
| 步骤 | 名称 | 结论 | 挂到哪里 |
|---|---|---|---|
| 1 | 开启清算与清算前备份 | 挂靠 | 委托执行、用户资产。封存集合与按交易日、营业日规则重查源表一致;账面汇率、融资额度用本批封存值。不把实时资金、持仓当 T 日起点 |
| 2 | 检查订单终态 | 不支持 | 批次已经完成才开跑,不再单独发卡。委托执行里「执行根应不应该出现」已经覆盖 |
| 3 | 计算用户汇率 | 部分挂靠 | 汇率数值没有权威公式,不计算「应该等于多少」。用户资产只加一条一致性:第 5 步和第 8 步用的是本批封存汇率,不是事后的实时 fx_book |
| 4 | 确认应付利息 | 挂靠 | 已在用户资产。补「T 日债务不因 T+1 已收取而被冲掉」,输入读本批封存的计息证据 |
| 5 | 订单与资金清算 | 挂靠 | 已在委托执行、用户资产。T 日结果以第 7 步 cleared 为准 |
| 6 | 持仓清算 | 挂靠 | 同上。与第 5 步没有各自留存的快照,不拆节点。cleared 上数量和成本仍是第 5 步的值;available_qty、frozen_qty 和估值是第 6 步写在同一行上的结果。clr_fund_account 第 6 步不替换,第 5 步各列保留 |
| 7 | 生成已清算数据集 | 挂靠 | 委托执行、用户资产。cleared 不含 trade_date>T 的成交和后续非交易 |
| 8 | 生成清算报表 | 挂靠 | 保持现有挂靠,报表对 cleared |
| 9 | 确认交易日切换并推进营业日 | 挂靠 | 核对门禁。只查日期推进 |
| 10 | 完成清算 | 挂靠 | 核对门禁。只查版本已切换到本批 cleared。开跑条件里已有的「批次 completed」不重复成一张卡 |
第 5 步的汇率调整按「T 日清算成交现金 − T 日原始买卖凭证」核对,读本批快照里的 clearing_fund_ledger,不读实时流水。后续成交保持原发生额,不按 T 日汇率重算。
询价报价、票据风控、授信与预警平仓线、市场汇率、港美股、B 类、基金、两端 OTC009 与 OTC012 的落库表、TRS011、TRS015。这些保持 doc/业务链路核对设计.md 第 2.2 节的原因,不因为本次改造加进来。
这三处必须在加任何新节点之前改掉。新节点若建在这三处读数上,会把投影差额当成公式错误,或把整段核对跳过。
db_issue_clear.clearing_table_backup。reader.choose_locations 在登记表没有行时退回 db_issue 实时表。该表已不存在,退回是静默的。实时票据和对冲持仓是第 5 步投影,不是 T 日结果。有后续买卖时,OTC004 对实时票据会误报。对冲仓位「没有副本就不读实时」则会整段跳过。db_trs.fund_ledger。新口径是本批原始快照加 clearing_fund_ledger 调整。实时流水含 CLR:%,也含后续营业日。daycut_fund_eod 或 kind=cleared 去比实时钱包。T 日结果只在本批 input 与 kind=cleared 之间重算。窗口 1 不重写 11 条链路的 Excel 公式。无后续业务的营业日,换读 cleared 后,结论应与现在对实时表的结论一致。有后续业务的日子,票据的「当前」与「T 日」分开。钱包只核本批归档里的 T 日结果,不另核实时钱包。报表和 T 日结果读已发布候选。
不在三端清算之前,把清算输入备份到自有库 MySQL。
check_run、check_result、check_line。再镜像三端输入,就要跟着 DDL 改表,和这套工具运行时不读 leopard 源码和 ddl/ 的隔离相反。现有进程是清算完成后跑一轮就退出,没有清算前钩子。input 或快照,再写派生列。若实施时发现某列既被改写又没进冻结分区,那是清算封存缺口,应补业务侧封存,而不是在核对工具侧平行备份。不给自有库加业务镜像表,也不新增清算前任务。
窗口 1 改 .cursor/skills/post-clear-check/SKILL.md,只动这几处:
docs/清算/三端清算最终实施方案.md,窗口 1 把这两处改成第 2 节的架构设计目录和本文。不要一个 agent 窗口做完。reader.py 约 1600 行,业务链路核对设计约 600 行,11 条链路的公式和测试叠在一起无法复核。chain.py、reader.py 是共享文件,多窗口并行会互相覆盖,只串行。
不跑工具全量用例,不跑 leopard 全仓测试。窗口 2 至 5 都依赖窗口 1 的取数。不在窗口 1 之前加节点。
每个窗口的验收是该窗口点名的定向测试,加上一个有后续业务的营业日、一个无后续业务的营业日。有后续业务的日子用来确认 T 日候选和当前投影被拆开;无后续业务的日子用来确认换读候选后,原有公式结论不漂移。
| 窗口 | 状态 | 范围 | 不做 |
|---|---|---|---|
| 1 | 已完成 | 取数契约、核对门禁、第 8 节的 skill 与业务链路核对设计第 5 节 | 不新增 Excel 节点 |
| 2 | 已完成 | 票据存续、增额、展期 | 不改买卖执行公式,不改销售钱包三条 |
| 3 | 已完成 | 账户资产、资金变动、资金交收 | 不改票据三条,不改 TRS 两条 |
| 4 | 已完成 | 买入执行,然后卖出执行 | 两条不交错改 order_rules.py |
| 5 | 已完成 | 委托执行、用户资产 | 不加用户汇率的金额公式 |
状态:已完成。
发行改读已发布数据集的 input、work/2、work/3、work/4、cleared/0,不再读 clearing_table_backup,也不再在登记表缺失时退回实时表充当 T 日结果。实时表只留给第 5 步当前投影节点,那些节点在窗口 2、4 才加。
TRS 资金改读本批快照和 clearing_fund_ledger。同时确认第 6 步有没有覆盖第 5 步写在 clr_fund_account、clr_user_position 上的列,把结论补进本文 4.3 和 5.3,再决定窗口 5 要不要拆开第 5 步和第 6 步。
销售钱包只核本批 input 与 kind=cleared 的 T 日结果,不读实时钱包。日终 daycut_fund_eod 只与候选比。
核对门禁加上第 5 节里挂到门禁的那些是/否检查:发行基线与上游版本、发行发布唯一、销售锁定的发行版本、TRS 日期推进与版本切换。开跑条件里已有的「批次 completed」不再做一张卡。
本窗口同时改 skill(第 8 节)和业务链路核对设计第 5 节的引用。不重写 11 条链路的节点公式。
状态:已完成。
三条都归资金账户,读同一批发行 input 和 cleared。增额、展期当前没有结论行。同一窗口按票据存续、增额、展期的顺序做完。这是对 skill「一次一条链路」的有意识放宽:三条共用取数,增额和展期又没有现成结论行,拆开会三次改同一处取数。若要严格一条链路一个窗口,就拆成三个,顺序不变。
节点以本文 5.1 的第 2、3、5 步和 5.2 的第 6 步为准。先改业务链路核对设计第 4.7、4.8、4.9 节,再改代码。
状态:已完成。
销售 input 与 cleared,发行 work/4。同一窗口按账户资产、资金变动、资金交收的顺序做完。放宽理由与窗口 2 相同:三条都读销售数据集,分开会三次改同一处取数。严格遵守时拆成三个窗口,顺序不变。
先改业务链路核对设计第 4.6 节(账户资产)、第 4.4 节(资金变动)、第 4.5 节(资金交收),顺序与本窗口一致,再改代码。第 3 步和第 4 步用重算对比 cleared,不读 pre_clearing 终态。
状态:已完成。
执行事实读 input,结算口径读 work/3 或 cleared。两条公式不同。同一窗口内先做完买入执行,再做卖出执行,不交错改 order_rules.py。
先改业务链路核对设计第 4.2、4.3 节,再改代码。
状态:已完成。
T 日回放、封存汇率一致性、利息不被 T+1 收取冲掉、cleared 不含后续成交。汇率调整读 clearing_fund_ledger。不计算用户汇率「应该等于多少」。
先改业务链路核对设计第 4.10、4.11 节,再改代码。第 5 步和第 6 步是否拆节点,以窗口 1 补进本文 4.3 的结论为准。