LabHub
学习 学习路径 课程

资本市场与清结算

用订单事件重建最终状态

在 LabHub 中继续学习

目标

仅根据订单事件日志重建每个订单的最终状态,找出与 OMS 状态字段不一致的订单,识别因排序时钟不同而结论反转的订单,并通过与顺序无关的规则消除这种波动。

为什么重要

在证券系统中,“订单状态”不是一个存储值,而是由多个事件折叠得到的结果。如果折叠规则没有明确规定,界面、通知和结算批处理就会各自采用不同规则进行折叠,从而得出不同答案。

本练习强制执行的四点都是实际现场规则。不要相信状态字段——处理器一旦漏掉某个事件,该订单的状态字段就会永久错误,而事件不会再次流入。区分撤单请求与撤单确认——如果在请求时就更改状态,请求后发生的成交会全部消失。将同一成交到达两次视为正常情况——重传不会消失,因此必须由接收方过滤;如果不去重,数量会悄无声息地膨胀。使答案不受顺序影响——与其精确猜中顺序,不如始终采用与顺序无关的规则。

本次事件如下。结算团队反馈:“已经收到成交通知,但 OMS 界面中有订单显示为已撤销。”对象是 2026-08-27 常规交易时段的 900 笔订单,我们掌握的资料只有一份事件日志和一份 OMS 状态快照。

重放规则如下。按时间升序读取事件(时间相同时按 seq 升序)。new 将状态设为 received 并确定订单数量。ack 改为 openreject 改为 rejectedcancelled 改为 cancelledreplace 只更改订单数量,不修改状态。cancel_req 不做任何更改。对于 fillpartial_fill,先将自身数量加入累计成交量;如果累计值大于等于订单数量,则状态设为 filled,否则设为 partially_filled

步骤

  1. 创建 /root/cap/order,原样运行答案中的生成器,生成 /root/cap/order/events.jsonl/root/cap/order/oms_status.csv。更改随机种子会导致结果与评分值不符。
  2. /root/cap/order/shape.txt 中写十行:events=orders=,以及针对八种事件类型各写一行,例如 type_new= 形式的 type_<종류>=
  3. ts_exch 升序(相同时按 seq)重放事件,生成 /root/cap/order/final_exch.csv。表头为 order_id,state,cum_qty,order_qty,每个订单一行,并按 order_id 升序排列。
  4. 对比 final_exch.csvoms_status.csv。在 /root/cap/order/omsdiff.txt 中写四行:status_mismatch=qty_mismatch=any_mismatch=qty_only_mismatch=;在 /root/cap/order/omsdiff.csv 中写入不一致的订单列表,表头为 order_id,replay_state,oms_status,replay_cum_qty,oms_filled_qty
  5. 将同一日志按 ts_recv 排序,生成 /root/cap/order/final_recv.csv;在 /root/cap/order/clock.txt 中写入 exch_filled=recv_filled=flipped=;在 /root/cap/order/flipped.csv 中按 order_id,exch_state,recv_state 表头写入状态反转的订单。
  6. 找出同一订单内相同 exec_id 出现两次的情况,在 /root/cap/order/dup.csv 中按 order_id,exec_id,dup_qty,dup_amount_krw 写入,并在 /root/cap/order/dup.txt 中写入 dup_orders=over_orders=dup_qty_total=dup_amount_total=
  7. 加入两项修正规则,生成 /root/cap/order/final_fixed.csv——使用 exec_id 过滤重复成交,并在重放结束后,如果累计成交量大于等于订单数量,就将状态固定为 filled。在 /root/cap/order/fixed.txt 中写入 flip_before=flip_after=final_filled=final_cancelled=
  8. /root/cap/order/report.md 中编写报告。需要 ## 무슨 일이 있었나## 근거## 돈으로 얼마인가## 왜 이런 일이 생기나## 무엇을 고쳐야 하나 五个章节。

参考

创建事件日志和 OMS 快照

创建 /root/cap/order,原样运行答案中的生成器,生成 /root/cap/order/events.jsonl/root/cap/order/oms_status.csv。更改随机种子会导致结果与评分值不符。

使用 python3 原样运行生成器即可。更改随机种子会导致结果与评分值不符,因此请保持不变。

统计事件流的构成

/root/cap/order/shape.txt 中写十行:events=orders=,以及针对八种事件类型各写一行,例如 type_new= 形式的 type_<종류>=

按 type 分别计数即可。只有能够解释 ack 为什么不是 900,下一步才会更容易。

按交易所时间重放

ts_exch 升序(相同时按 seq)重放事件,生成 /root/cap/order/final_exch.csv。表头为 order_id,state,cum_qty,order_qty,每个订单一行,并按 order_id 升序排列。

先按 ts_exch 升序、相同时按 seq 升序排列事件,再依次折叠。只要记住 cancel_req 不改变状态,其余规则均按说明执行。

与 OMS 状态字段对比

对比 final_exch.csvoms_status.csv。在 /root/cap/order/omsdiff.txt 中写四行:status_mismatch=qty_mismatch=any_mismatch=qty_only_mismatch=;在 /root/cap/order/omsdiff.csv 中写入不一致的订单列表,表头为 order_id,replay_state,oms_status,replay_cum_qty,oms_filled_qty

进行两次比较:只比较状态字符串时的数量,与连同成交数量一起比较时的数量并不相同。这个差值正是本步骤的重点。

按接收时间重新重放并比较

将同一日志按 ts_recv 排序,生成 /root/cap/order/final_recv.csv;在 /root/cap/order/clock.txt 中写入 exch_filled=recv_filled=flipped=;在 /root/cap/order/flipped.csv 中按 order_id,exch_state,recv_state 表头写入状态反转的订单。

使用与第 3 步相同的函数,只将排序键替换为 ts_recv。按订单比较两个结果的 state,只收集不同的订单。

找出同一成交到达两次的情况

找出同一订单内相同 exec_id 出现两次的情况,在 /root/cap/order/dup.csv 中按 order_id,exec_id,dup_qty,dup_amount_krw 写入,并在 /root/cap/order/dup.txt 中写入 dup_orders=over_orders=dup_qty_total=dup_amount_total=

检查同一订单内是否有相同 exec_id 出现两次。如果只统计累计成交量超过订单数量的情况,连一半都找不到。

加入不受顺序影响的规则

加入两项修正规则,生成 /root/cap/order/final_fixed.csv——使用 exec_id 过滤重复成交,并在重放结束后,如果累计成交量大于等于订单数量,就将状态固定为 filled。在 /root/cap/order/fixed.txt 中写入 flip_before=flip_after=final_filled=final_cancelled=

加入两项规则:使用 exec_id 过滤重复成交;重放结束后,如果累计成交量大于等于订单数量,就将状态固定为已成交。随后分别使用两个时钟重放,统计结果是否一致。

编写调查报告

/root/cap/order/report.md 中编写报告。需要 ## 무슨 일이 있었나## 근거## 돈으로 얼마인가## 왜 이런 일이 생기나## 무엇을 고쳐야 하나 五个章节。

需要五个章节。原因章节必须说明时钟和顺序,措施章节必须说明去重。数字应原样写入正文。