TT Lab
开始
学习 学习路径 课程

资本市场与清结算

撤销通知来了两次,持仓翻成了反方向

在 TT Lab 中继续学习

目标

把对已经发出的成交的撤销和更正通知,与原成交连起来,不擦除原账簿,而是追加冲销记录,做出新的账簿。重新计算持仓并与已经发出的报告对照,确认即使两次收到同一条通知,账簿也相同,然后给出重新报告对象和更正报告。

为什么重要

成交账本是已经流向很多地方的数据。如果悄悄改写其中的一行,昨天发出的报告与今天看到的账本就会对不上,而对不上的原因,哪里都留不下来。所以金融账簿是往后写的。撤销,是追加符号相反的冲销记录;更正,是冲销之后,再以修正后的值重新写一遍。困难的不是这条规则本身,而是边缘情况。通知可能指向并不存在的成交,同样的通知可能因重发而到来两次,更正也可能落到已经被撤销的成交上。只要漏掉一个,持仓就会翻到反方向,而这件事通常要到第二天报告出错之后才会暴露。

步骤

  1. 用 python3 在 /root/bust/data 中生成 fills.jsonl、notices.jsonl、position_report.csv 和 rules.json。
  2. 按到达顺序读取通知,把判定写入 /root/bust/notice_match.csv。
  3. 把要应用的撤销作为冲销记录追加进去,生成 /root/bust/ledger_bust.jsonl。
  4. 把更正作为冲销和重新记账追加进去,生成 /root/bust/ledger_final.jsonl,并把按订单统计的平均单价输出到 /root/bust/order_avg.csv。
  5. 重新计算持仓,只把出现偏差的标的写入 /root/bust/position_diff.csv。
  6. 把同一个通知数据流放进去两次,生成 /root/bust/ledger_twice.jsonl 和 /root/bust/idem.json。
  7. 把报告时间之后到达的通知收集起来,生成 /root/bust/rereport.csv。
  8. 把每一处变更的来源写入 /root/bust/trace.csv,把整体摘要写入 /root/bust/report.json。

参考

生成成交账本、撤销与更正通知、持仓报告

用 python3 在 /root/bust/data 中生成 fills.jsonl、notices.jsonl、position_report.csv 和 rules.json。请原样使用不使用随机数的生成脚本。

不能直接拿来客户的成交账本,所以要做出形态相同的合成数据。不使用随机数,是为了无论谁运行多少次都得到同样的数据,才能互相对照判定。评分器会把数据转换成标准形式来核对指纹,所以如果手工修改,后面的步骤就会全部被堵住。

把通知与原成交连起来作判定

在 /root/bust/notice_match.csv 中,首行写 seq,notice_id,type,target_fill_id,verdict,按到达顺序读取通知,写入 적용、대상없음、이미취소됨、중복통지 之中的一个(韩文判定名依次意为“适用”“无对象”“已被撤销”“重复通知”)。每条通知写一行。

按这个顺序看四件事。前面是不是已经见过同样的通知标识符,所指向的成交在账本里有没有,那笔成交前面是不是已经被撤销,其余的就是应用。每次应用撤销时,都要记住这个成交标识符,第三项检查才能进行。通知标识符不论判定如何,全部都要记住。

把撤销作为冲销记录追加,做出新账簿

在 /root/bust/ledger_bust.jsonl 中,把十八行原成交作为 kind 为 fill 的记录原样搬过来,并为每个要应用的撤销,追加数量和金额符号相反的 reversal 记录。不要修改原记录。

不擦除,而是追加。冲销记录的数量,是原成交数量加上负号,单价与原成交相同。这样金额也会自然变成相反的符号。entry_id 是在通知标识符后面加 -rv,并在 source_notice 里留下那条通知,日后就能追溯来源。原成交记录的 source_notice 是空字符串。

反映更正并重新得出平均单价

/root/bust/ledger_final.jsonl 是在第 3 步的账簿上,为每个更正追加 reversal 和 rebook 两行。在 /root/bust/order_avg.csv 中,首行写 order_id,net_qty,net_notional,avg_px,每个订单写一行。

更正是先冲销原记录,再以修正后的值重新写一行。通知中没有的值,请原样使用原成交的值。只改价格的更正,数量相同,只有金额不同。平均单价是账簿的金额之和除以数量之和,被全部撤销的订单,数量之和为 0,所以置为 0。除之前先看是不是 0。

重新计算持仓并与已有报告对照

在 /root/bust/position_diff.csv 中,首行写 symbol,reported_qty,recomputed_qty,diff,只写用最终账簿重新计算的持仓与 position_report.csv 不同的标的。

持仓是买入相加、卖出相减来计算的。冲销记录的数量是负数,符号会自动颠倒,所以不需要另外分支。diff 是用重新计算的值减去报告的值。值相同的标的不写。差别并不全都能用迟到的通知来解释,所以即使有解释不了的标的,也请保持原样。

测试两次收到同一条通知时账簿是否相同

在通知数据流之后,再原样接上一遍同样的通知(第二批的 seq 加 1000),生成 /root/bust/ledger_twice.jsonl,并在 /root/bust/idem.json 中写入 entries、same_as_final 和 ignored_duplicates。

重发是正常的事。如果不记住通知标识符,已经被撤销过一次的成交就会被冲销两次,持仓会翻到反方向。第二批的标识符全部都是前面见过的,所以一条都不能被应用,这样账簿就会与第 4 步的完全相同。ignored_duplicates 是在接起来的整个数据流中,被判定为重复通知的通知数,same_as_final 是真或假。

把报告之后到达的通知收集成重新报告对象

在 /root/bust/rereport.csv 中,首行写 notice_id,type,target_fill_id,symbol,position_delta,写入已应用的通知中,通知时间晚于 rules.json 的持仓报告时间的那些。

在持仓报告发出之后到达的通知,只修改账簿是不够的,它会让已经发出的报告变成错的。基准时间在 rules.json 里,所以不要用今天的日期。position_delta 是这条通知使持仓变动了多少,卖出的符号相反。只改价格的更正不触碰数量,所以是 0,但不要把它从重新报告对象中去掉。

撰写更正报告和变更追溯表

在 /root/bust/trace.csv 中,首行写 entry_id,kind,fill_id,source_notice,reason,qty,px,notional,写入最终账簿中 kind 不是 fill 的全部记录,并在 /root/bust/report.json 中写入整体摘要。

接收的人必须能决定下一步做什么,报告才有用。给每个变更附上它来自哪条通知,以及该通知的原因,几个月之后也能追溯。reason 从通知数据中取,但必须是实际被应用的通知的。用同一个标识符重发的副本原因不同,就是在这里出现分歧。要放进摘要的键有 fills、notices、적용、대상없음、이미취소됨、중복통지、bust_applied、adjust_applied、entries_before、entries_after、position_mismatch 和 rereport(其中四个韩文键就是判定名称)。