TT Lab
はじめる
学ぶ 学習パス コース

資本市場と決済

画面の板は、ずっと静かに間違っていた

TT Labで続きを見る

目標

スナップショット1枚と増分更新で板を作り直し、順序番号が途切れた箇所と遅れて届いた行が作る差を、価格レベル数で数えます。最後に、再同期の規則を入れた実装が、基準のスナップショットと1レベルもずれないことを確認します。

なぜ重要なのか

相場画面は、間違っていても何の音も立てません。値が空になったり例外が出たりするのではなく、少し違う値が回り続けるので、数日後に注文がおかしく出てから、ようやくさかのぼることになります。スナップショットに埋め込まれた順序番号と増分の順序番号をどうつなぐか、順序番号が途切れたときに止まるか重ね続けるかという、2行の規則が、その差を生みます。そして、このラボの計算はすべて価格を扱います。価格を2進浮動小数点数で引いた瞬間、1呼値を測る判定が静かに0になるので、値ではなくデータ型で最初に負けてしまう場合がどんなものかも、あわせて見ます。

ステップ

  1. python3で/root/cap/book/dataに4つのデータファイルを作成してください。生成スクリプトをそのまま使います。
  2. 増分ストリームの形を数えて、/root/cap/book/shape.txtに9行で書いてください。
  3. 開始スナップショットで板を立ち上げ、重なる増分を数えて、/root/cap/book/init.jsonに書いてください。
  4. 増分を順序番号の順に重ねて、/root/cap/book/naive.jsonに板と動作別の件数を書いてください。
  5. 再生中に不変条件が崩れた箇所を探して、/root/cap/book/invariant.txtに7行で書いてください。
  6. 途切れた区間と、立て直した結果の差を、/root/cap/book/gap.jsonに書いてください。
  7. 遅れて届いた行と、それが作った差を、/root/cap/book/late.jsonに書いてください。
  8. 再同期の規則を入れた最終的な板を/root/cap/book/final/book.jsonに、品質レポートを/root/cap/book/final/report.jsonに残してください。

参考

スナップショットと増分ストリームを作る

python3で/root/cap/book/dataに、snapshots.jsonl・updates.jsonl・session.json・feed_spec.txtの4つを作成してください。乱数を使わない生成スクリプトを、そのまま使ってください。

エアギャップ環境には、ダウンロードできる相場キャプチャがないので、データから自分で作ります。乱数を使わなければ、誰が何回回しても同じデータが出て、お互いの再構成結果を突き合わせられます。採点ツールは、データを標準形に変換してフィンガープリントを突き合わせるので、データを手で直すと、あとのステップがすべて行き詰まります。

増分ストリームの形を数える

/root/cap/book/shape.txtに、updates=、snapshots=、symbols=、seq_min=、seq_max=、seq_missing=、delete_ops=、upsert_ops=、out_of_order=の9行を書いてください。

seq_missingは、seq_minからseq_maxまでの整数のうち、ファイルにないものの個数です。delete_opsは数量が0の行、upsert_opsは0でない行です。追加と変更をここで分けようとしないでください。その2つは、板を持っていなければ区別できません。out_of_orderは、前の行より順序番号が小さい行の数です。

スナップショットで板を立ち上げ、重なる増分を捨てる

session.jsonのstart_checkpointのチェックポイントのスナップショットで、銘柄ごとに板を立ち上げ、/root/cap/book/init.jsonに、銘柄別にsnap_id・last_seq・bid_levels・ask_levels・best_bid・best_ask・discarded・applicable・first_applied_seqの9つの値を書いてください。

スナップショットは、撮られている間も増分が出続けるので、last_seqを一緒に載せています。その値以下の増分は、すでにスナップショットに入っているので、捨てる必要があります。discardedはそうして捨てる行の数、applicableは残る行の数で、どちらもその銘柄のものだけを数えます。best_bidは最も高い買い値、best_askは最も低い売り値です。

増分を重ねて板を再構成する

ステップ3の板に、順序番号がstart_checkpointより大きい増分を、順序番号の昇順ですべて重ね、/root/cap/book/naive.jsonにbookとopsの2つのキーを書いてください。opsには、add・change・delete・delete_missing・appliedの5つの数を入れます。

動作はメッセージではなく、今持っている板が決めます。数量が0なら削除ですが、消そうとする価格が板にない場合もあります。それをエラーとして処理せず、delete_missingとして数えておいてください。その数字自体が、受け取れなかった増分があるというサインです。途切れた順序番号は、このステップではそのまま通り過ぎます。

クロスした板が出る瞬間を探す

ステップ4と同じ再生をしながら、更新1件ごとに、その銘柄の不変条件を見て、/root/cap/book/invariant.txtにfirst_cross_seq=、first_cross_symbol=、first_cross_bid=、first_cross_ask=、crossed_states=、tick_spread_states=、zero_qty_levels=の7行を書いてください。

クロスとは、最良買い気配値が最良売り気配値以上の状態です。crossed_statesは、適用直後にその銘柄がクロスしていた回数、tick_spread_statesは、クロスしておらず、スプレッドがちょうど1呼値だった回数です。2つ目の値が0で出るなら、計算ではなくデータ型を疑ってください。10進の小数を2進浮動小数点数で引くと、1呼値がちょうどになりません。

途切れた箇所で重ね続けたものと、立て直したものを比べる

/root/cap/book/gap.jsonに、gaps(途切れた区間の一覧)、resync(立て直した箇所の一覧)、level_mismatch(銘柄別のずれた価格レベル数)、level_mismatch_totalの4つのキーを書いてください。gapsの項目はfrom_seq・to_seq・count、resyncの項目はdetected_after_seq・next_seq・checkpointです。

順序番号が途切れたということは、受け取れなかった変更があるという意味で、それが何だったかを知る方法はありません。そのため、増分をそれ以上重ねず、次のスナップショットから立て直します。立て直すチェックポイントは、途切れる直前までに適用した順序番号以上のもののうち、最も早いもので、そのスナップショットのlast_seq以下の増分は、また捨てる必要があります。2つの一覧は、順序番号が小さいほうから書きます。

遅れて届いた行をそのまま重ねるとどうなるか

/root/cap/book/late.jsonに、late_seqs(遅れて載った行の順序番号の一覧)、harmful_seqs(そのうち結果を変えるもの)、level_mismatch(銘柄別のずれた価格レベル数)、level_mismatch_totalの4つのキーを書いてください。比較は、ステップ4の順序番号順の再生と、同じ条件でファイルに載った順序のまま重ねた再生の間で行います。

遅れて載った行のすべてが有害なわけではありません。同じ銘柄・方向・価格を、より大きな順序番号が先に上書きした場合にだけ、古い値がよみがえります。そうでない行は、順序が入れ替わっても結果が同じです。2つの再生とも、途切れた箇所はそのまま通り過ぎ、開始チェックポイント以下の行は捨てるところまで、同じにしておいてください。そうすれば、差が到着順だけから生じます。

再同期の規則を入れた最終実装で基準と突き合わせる

2つの規則(順序番号の順に重ねる、途切れたら次のスナップショットから立て直す)をどちらも入れた実装で全ストリームを回し、/root/cap/book/final/book.jsonに最終的な板を、/root/cap/book/final/report.jsonにapplied・discarded・resync_count・resync_checkpoints・gap_count・lost_seqs・late_seqs・naive_vs_reference・final_vs_reference・crossed_symbols_final・reference_checkpointの11の値を書いてください。

基準の板は、session.jsonのreference_checkpointのチェックポイントのスナップショットです。naive_vs_referenceはステップ4の板と基準の間、final_vs_referenceは今回の板と基準の間の、ずれた価格レベル数で、後者は0でなければなりません。discardedは、順序番号がすでに過ぎているために捨てた行のすべてです。最初に重なった区間と、立て直したあとに重なった区間を、あわせて数えます。前のステップの出力物は消さずに、新しいディレクトリに残してください。