取消通知が二度届き、ポジションが反対に振れた
目標
すでに出ていった約定に対する取消・訂正の通知を、元の約定につなげ、元の帳簿を消す代わりに、反対仕訳を加えて新しい帳簿を作ります。ポジションを再計算して、すでに出た報告と突き合わせ、同じ通知を2回受け取っても帳簿が同じかを確認したうえで、再報告の対象と訂正レポートを出します。
なぜ重要なのか
約定元帳は、すでに複数の場所に流れ出たデータです。その1行を黙って書き換えると、昨日出た報告と今日見る元帳がずれ、ずれた理由はどこにも残りません。そのため、金融の帳簿はあとに書きます。取消は、符号が反対の反対仕訳を加えることで、訂正は、相殺したあと、直した値でもう一度書くことです。難しいのは、この規則自体ではなく、端の部分です。通知が存在しない約定を指すこともあり、同じ通知が再送で2回来ることもあり、すでに取り消された約定に訂正が来ることもあります。1つでも見逃すと、ポジションが反対に傾き、その事実は、たいてい翌日の報告が間違ってから、ようやく表に出ます。
ステップ
python3で/root/bust/dataに、fills.jsonl・notices.jsonl・position_report.csv・rules.jsonを作成してください。- 通知を到着順に読んで、判定を
/root/bust/notice_match.csvに書いてください。 - 適用する取消を、反対仕訳として加えて、
/root/bust/ledger_bust.jsonlを作ってください。 - 訂正を、相殺と再記帳として加えて
/root/bust/ledger_final.jsonlを作り、注文別の平均約定価格を/root/bust/order_avg.csvに出してください。 - ポジションを再計算して、ずれた銘柄だけを
/root/bust/position_diff.csvに書いてください。 - 同じ通知ストリームを2回流し込んで、
/root/bust/ledger_twice.jsonlと/root/bust/idem.jsonを作ってください。 - 報告時刻のあとに届いた通知を集めて、
/root/bust/rereport.csvを作ってください。 - 変更1つ1つの出どころを
/root/bust/trace.csvに、全体の要約を/root/bust/report.jsonに書いてください。
参考
- 通知は、
seqが到着順です。判定はこの順序で行い、適用した取消を記憶しておかなければ、再取消を分けられません。 - 判定名は4つです。同じ通知IDを前ですでに見たものは
중복통지、指す約定が元帳になければ대상없음、指す約定が前ですでに取り消されていれば이미취소됨、残りは적용です。この順序で見ます(韓国語の4つの語は、順に「重複通知」「対象なし」「取消済み」「適用」を意味します)。 - 帳簿の記録は11の欄です。
entry_id・kind・fill_id・order_id・symbol・side・qty・px・notional・source_notice・entry_time。kindはfill・reversal・rebookの3つです。 - 反対仕訳の
entry_idは、通知IDに-rvを付けたもの、再記帳は-rbを付けたものです。entry_timeは通知の時刻です。 - 訂正通知の
new_qty・new_pxがnullなら、その値は元の約定の値をそのまま使います。 - 金額は
decimalで計算し、小数第4位でROUND_HALF_UPで丸めます。文字列で書いてください。 - ポジションは、買いを足して売りを引いて数えます。反対仕訳は数量が負の数なので、符号が自然に反転します。
- データファイル
rules.jsonに、ポジション報告時刻が入っています。dateで今日を使わないでください。 - よくある間違い1: 元の記録を直して訂正してしまいます。適用前のデータが残っていなければ、前後を比べられません。
- よくある間違い2: 通知IDを記憶せず、再送された取消を2回相殺してしまいます。
- 公開ドキュメント: FIX Standards、Fiximate、decimal。約定18件と通知14件は、このラボの合成データです。
約定元帳と取消・訂正の通知、ポジション報告を作る
python3で/root/bust/dataに、fills.jsonl・notices.jsonl・position_report.csv・rules.jsonを作成してください。乱数を使わない生成スクリプトを、そのまま使ってください。
顧客の約定元帳をそのまま持ってこられないので、同じ形の合成データを作ります。乱数を使わなければ、誰が何回回しても同じデータが出て、お互いの判定を突き合わせられます。採点ツールは、データを標準形に変換してフィンガープリントを突き合わせるので、手で直すと、あとのステップがすべて行き詰まります。
通知と元の約定をつなげて判定する
/root/bust/notice_match.csvに、1行目にseq,notice_id,type,target_fill_id,verdictを置いて、通知を到着順に読み、적용・대상없음・이미취소됨・중복통지のうち1つを書いてください(韓国語の4つの語は、順に「適用」「対象なし」「取消済み」「重複通知」を意味します)。すべての通知を1行ずつ書きます。
4つをこの順序で見ます。同じ通知IDを前ですでに見たか、指す約定が元帳にあるか、その約定が前ですでに取り消されているか、そして残りが適用です。取消を適用するたびに、その約定IDを記憶しておく必要があり、そうして初めて3つ目の検査ができます。通知IDは、判定と無関係に、すべて記憶します。
取消を反対仕訳として加えて新しい帳簿を作る
/root/bust/ledger_bust.jsonlに、元の約定18行を、kindがfillの記録としてそのまま移し、適用する取消ごとに、数量と金額の符号が反対のreversal記録を加えてください。元の記録は直しません。
消さずに加えます。反対仕訳の数量は、元の約定の数量にマイナスを付けた値で、単価は元の約定のままです。そうすれば、金額も自然に反対の符号になります。entry_idは通知IDに-rvを付け、source_noticeにその通知を残しておけば、あとで出どころをたどれます。元の約定の記録のsource_noticeは、空文字列です。
訂正を反映して平均約定価格を出し直す
/root/bust/ledger_final.jsonlは、ステップ3の帳簿に、訂正ごとにreversalとrebookの2行を加えたものです。/root/bust/order_avg.csvに、1行目にorder_id,net_qty,net_notional,avg_pxを置いて、注文ごとに1行ずつ書いてください。
訂正は、元の記録を相殺したあと、直した値でもう1行書きます。通知にない値は、元の約定の値をそのまま使ってください。価格だけが変わる訂正は、数量が同じで、金額だけが変わります。平均約定価格は、帳簿の金額の合計を数量の合計で割った値で、全部取り消された注文は、数量の合計が0なので、0にします。割る前に、0かどうかを先に見てください。
ポジションを再計算して既存の報告と突き合わせる
/root/bust/position_diff.csvに、1行目にsymbol,reported_qty,recomputed_qty,diffを置いて、最終的な帳簿で再計算したポジションが、position_report.csvと異なる銘柄だけを書いてください。
ポジションは、買いを足して売りを引いて数えます。反対仕訳は数量が負の数なので、符号が自然に反転し、別に分岐する必要はありません。diffは、再計算した値から、報告された値を引いたものです。値が同じ銘柄は書きません。差のすべてが遅れて来た通知で説明されるわけではないので、説明されない銘柄があっても、そのままにしてください。
同じ通知を2回受け取っても帳簿が同じかをテストする
通知ストリームのあとに、同じ通知をもう一度つなげて(2番目のまとまりは、seqに1000を足します)/root/bust/ledger_twice.jsonlを作り、/root/bust/idem.jsonにentries・same_as_final・ignored_duplicatesを書いてください。
再送は正常なことです。通知IDを記憶しなければ、一度取り消された約定が2回相殺され、ポジションが反対に傾きます。2番目のまとまりは、IDがすべて前に見たものなので、1つも適用されてはならず、そうすれば、帳簿はステップ4のものとまったく同じになります。ignored_duplicatesは、つなげたストリーム全体で、重複通知と判定された通知の数で、same_as_finalは、真か偽です。
報告のあとに届いた通知を再報告の対象として集める
/root/bust/rereport.csvに、1行目にnotice_id,type,target_fill_id,symbol,position_deltaを置いて、適用された通知のうち、通知時刻がrules.jsonのポジション報告時刻より後のものを書いてください。
ポジション報告が出たあとに届いた通知は、帳簿だけを直して終わりではなく、すでに出た報告を間違いにします。基準時刻はrules.jsonにあるので、今日の日付を使わないでください。position_deltaは、その通知がポジションをどれだけ動かすかで、売りは符号が反対です。価格だけが変わる訂正は、数量に触れないので0になりますが、再報告の対象から外さないでください。
訂正レポートと変更追跡表を書く
/root/bust/trace.csvに、1行目にentry_id,kind,fill_id,source_notice,reason,qty,px,notionalを置いて、最終的な帳簿でkindがfillでない記録をすべて書き、/root/bust/report.jsonに全体の要約を書いてください。
受け取った人が次に何をするかを決められて初めて、報告が役に立ちます。変更ごとに、どの通知から来たかと、その通知の理由を付ければ、数か月後にもたどれます。reasonは通知データから持ってきますが、実際に適用された通知のものでなければなりません。同じIDで再送されたコピーは、理由が違うので、ここで分かれます。要約に入れるキーは、fills・notices・적용・대상없음・이미취소됨・중복통지・bust_applied・adjust_applied・entries_before・entries_after・position_mismatch・rereportです(韓国語の4つの語は、順に「適用」「対象なし」「取消済み」「重複通知」を意味します)。