見出し画像

注文伝票(とりあえず生🍺)

某居酒屋でもよく聞く、こちらのセリフが証券会社でも聞かれるとか聞かれないとか

それ、なんぞ

証券会社で受注を受けた際に必ず作らなくてはならないのが注文伝票。英語だとOrder Ticketと呼ばれる、日本特有な要求項目があります。
要件としてはお上金融庁のサイトに書かれています。

外資が日本でブローカレッジ業務を行うにあたって、このシステムを作ることが早い段階で顕在化します。んで、リソースをグローバルに要求すると、「え、なにそれ、なんでそんなん作らないといけないの」とそもそも論で突っ込まれる、日本法人のコンプラ+オペレーション+エンジニア泣かせの代物です。
その際の魔法の言葉が、「投資家保護の観点からです」、です笑
ただその説明がうまく伝わらず、マニュアルで本番に突入してしまい、後日取引量が多くなって、「お。。。コレはあかんやつ」となり始めてくることも考えれられます。
このページではそういった、注文伝票作成がマニュアルで、にっちもさっちも行かなくなってきて「やばい、帰れま10」の方々向けにお送りいたします😂

95%ぐらい自動化できるようになる手口

さて、無事グローバルからの首を傾げながらのリソースアロケーションに成功した皆様、おめでとうございます。
多分注文伝票作成の自動化という話になっている以上、既に注文を発注できるターミナル、もしくは直結の取引システムが稼働しているのではと思われます。

ターミナルは知らんのでここでは割愛します😅 直結だと

  • TSE:東京証券取引所

  • OSE:大阪証券取引所

  • PTSな色々:Chi-XとかJapannextとか

辺りが株系のドメスティックマーケットになります。それぞれプロトコルが違い、TSEはArrowhead、OSEはNasdaqのOMXベースの妙なやつ、PTSの2社は業界スタンダードなプロトコルだったかと思います。

当然取引を行うにあたり、お客さんからの注文をそのまま流すか、なんらかのアルゴにぶっ込んでVWAPやらIcebergやらでこねくり回してから注文をします。

そうすると新規注文として電文に載せる必要がある項目は、劇的にシンプルに書くとこのあたりになります。

  • Order 🆔 (注文🆔)

  • Connection 🆔 / login 🆔 (接続🆔)

  • Principal/Agency (自己か委託かの別)

  • Order timestamp (発注時刻)⏰

  • ISIN (銘柄)

  • Buy/Sell (売り買い) 🍓

  • Qty (数量)

  • Validity (板を叩いたタイミングで約定しなければ自動的にキャンセル、マーケットクローズしたタイミングでExpire、など)

コレを証券取引所のMatching Engineと呼ばれる取引システムの接続先に投げるわけですが、同時に自前で注文伝票が作られるシステムにも並行して投げておく必要があります。ここで、それぞれのプロトコルの特性、特にオーダーの投げ方に色々と種類があります。
例えば、Two-sided orderと呼ばれる、スプレッドを入れ込んだ売り買いのオーダーを一つの電文として送れるプロトコルもあったりします。
こやつは注文伝票として記入する時には、売り買いが同じOrder🆔で、全くの同時刻に発注されているという事実を2つのエントリーとして入力する必要があります。
ほら、もうエンジニア涙目。手口としては、その接続システムのシステム内+伝票システム内で理解出来る内部の🆔を持って対応したりということになります。

で、ここから変更、取消、もしくは取引所で約定、部分約定、Expireなどのイベントが行われるわけです。その度に注文伝票にはそのイベント毎の情報を記載することになります。
変更・取消においては、お客さんからのリクエストによるものなので、どのOrder 🆔に対しての変更・取消かという情報があるハズなので、その情報を証券取引所に投げると同時に、伝票システムにも投げればいいわけです。これは素朴極まりないリクエストなのであんまり問題になることはないです。

「とりあえずオープンしてるオーダー全部キャンセルしておいて」コレですよ、お前…となるのは。これでブローカー側のエンジニア同士で揉めるのが:

  • このお客さんに紐づいている全てのOrder 🆔を引っ張る、これはまあいいよねってなる。

  • それぞれのOrder 🆔に一つづつ取消を送る、が、Connectivity 🆔を持ってMass Cancelという電文が使える取引所にはそれを使いたがるフロント側のエンジニアと、それしたらOrder 🆔わかんなくなんじゃんと涙目になるオペレーション側のエンジニアのせめぎ合いが始まる。

この辺りは本当にOrder 🆔とConnectivity 🆔、Connectivity 🆔とそれぞれのお客さん、という切り分けが出来ていないと、本当に地獄を見ます。
伝票楽する代わりにMass Cancel使えるのに使わないと、一つ一つOrder 🆔 で変更やら取消をすることになります。大抵1秒間に取引所側に送れる件数が決まっているので、コレやると(例えばマーケットが動いて)素早く取消したかったのに、思わぬ価格で約定してしまった、などのクレームの元になります。

この価格で約定した理由を教えていただけますか?って言われる🥺

逆に約定やらExpireの取引所側でのイベントが起こった際ですが、こいつらも厄介です。当然こういった電文はそれぞれの取引所のプロトコルで送られてくるので、Transaction 🆔が入っていても、Order 🆔が入っていなかったりするので、逆に今までに送っていたOrder 🆔がまだオープンオーダーとして残っているかなどのチェックが必要になったりします。
で、Order 🆔は約定の際にも伝票に記載する必要があるので、こいつを引っ張れないと終わります。

さて、時刻の要件もありました。今現在どうなっているかはわかりませんが、私が業務にあたっていた2019年時点ではμsまでの要求がありました。
このμsの妥当性はどう担保すればええのん?とエンジニアちゃんたちまた困ります。デフォルトのNTPの設定だと余裕でズレますし、そもそもStratumが大きいところから取ると取引所のタイムスタンプとμs単位では余裕でズレます。
約定時刻を取引所のタイムスタンプ、新規注文の時刻を自社のシステムクロックのタイムスタンプを使うと、下手すると約定時刻が注文時刻より早いというミラクルが起きるので、そんな事態が起きるとお祭りが始まります。

あなたは未来人ですか?ドラえもんなんですか?って言われる😅

となると、証券会社のエンジニアはどうするか。取引所のMatching Engineの横に置けばいいんじゃね?そんで取引所が提供してるNTP使えばいいんじゃね?天才じゃね?となります。
そうです、これがお金持ちの証券会社が実装するコロケーション(場所を共存させる)という手口手法です。
#大体 `/etc/ntpd.conf` に `iburst minpoll 4 maxpoll 4` でめっちゃくちゃ頻繁に同期をかけてズレ(drift)が起こらないようにするか、PTPというプロトコルを使います。

この辺りまで検討すると、95%程度の取引パターンに対応が出来る伝票システムが実装可能になってきます😃でもね。。。

残りの5%は確実に泣く

はい、大体こういった事象が本番稼働後に出て、泣きを見ます。是非本番前のテスト項目に入れてください‼️

接続が切れるパターン

システムは壊れます。これエンジニアなら暗黙的な共通認識なのですが、まだまだ壊れてるから早くなおせGrrrと猛獣化してしまうトレーダー・営業方々も中にはいらっしゃいます。
で、壊れるパターンとして取引所との接続が切れるパターンがあります。コレどうなるか。取引所の接続方式、および今まで送っていた注文のパターンにもよりますが、Cancel on disconnect (COD):切断時に全ての注文をキャンセルする、という仕様が実装されている可能性によって対応が変わります。ざっくりとカテゴリ分けすると、

  1. Cancel on disconnectが取引所側でデフォルトで実装されている

  2. Cancel on disconnectが使用できるオプションが用意されている

  3. 放置プレイ

のパターンがあり、それぞれに対して伝票の作り方が違います。

①の場合、接続が切れたら約定していない注文は全て自動的にキャンセルになるので、キャンセルイベントが発火した時刻などの情報を再接続後に取ってくるか、もしくは自前で注文は全てキャンセルされた、というエントリーを伝票に追加します。前者のやり口であれば時刻が取引所のものになるので正確なのですが、後者のやり口で行くとなると、時刻の妥当性ですんごい詰められるので、エンジニアの方々ご注意を。

②の場合は、注文を送る際に「この注文はCOD効かせてね★」という無邪気なお願いをすることにより、接続が切れた際には①の対応と同じになります。ただ、CODを効かせないと、再接続後にもまだ約定されていない注文が残っています。これそのままマーケットクローズして、約定せずにExpireすれば伝票作成は比較的問題ないのですが、大体マーケット動いて知らぬ間に超不利な価格で約定する→トレーダー激おこぷんぷん丸になります。というかそもそもそんなNaked open orderあるとコンプラ先生に呼ばれますので、これは伝票云々よりも、再接続時には全てのOrder情報を読み込む+可能なら全キャンセルという機能を入れておかないと、証券会社のエンジニアとしてのキャリアがやばみです。
# コレを防ぐためにDrop copyという別コネクションを取るという手法もあります。今度詳しく書こうかな。

だからなんでこの注文こんな価格で約定してるんだよ、って凄まれる😭

③は②の後者パターンと一緒です。そっち読め下さい。

自社から出している自己同士で約定してしまった

コレは、伝票で同じTransaction 🆔を持った複数のエントリーが出来るので、やばいです。というか自己同士とかやるとMarket manipulation、価格操作というあらぬ疑いをかけられるので、伝票側の問題というよりは新規注文をかける際に「同じConnection 🆔で約定しないように」指定する必要があります。これ各取引所でデフォルト設定にならなかったのはなんでなんだろう…
コンプラ先生に呼ばれる、その2です。

すいません、ご趣味は価格操作ですか?って言われる😇

そもそも量が多すぎて処理し切れなかった

高速取引とかやっている業者さんにありがちですが、日に100万とか注文するエンジンがあると、注文伝票側のシステムが追いつかなくてパンクすることがあります。注文伝票に係る全てのパイプラインにあるシステムのキャパシティの過去1年のピークを見て、5倍ぐらいの取引量に耐えられるだけは少なくとも設計するのと、すぐにスケールアップできるような体制も整えておかないと、コレでおうち帰れなくなりますYO!
コンプラ先生に呼ばれる、その3でした。

これ120万件分、朝3:00の締め切りまでに目を通しておいてね✨って無邪気に言われる😉

まとめ

注文伝票は法定帳簿扱いになるので、考えられるテストケースは出来るだけ噛ませた方がいいです。出来れば過去1年間の取引データを読ませてみて、おうちに帰れる時間ぐらいで終わるかどうか。処理がアブノーマルに終わった際にデバッグしやすくログが吐かれてるか。伝票は作れてもその先、アップロード先へのパイプラインも同程度の量処理が出来るか、など。後で、あ、やばい、となる前に丁寧な設計を心がけましょう😁

この記事が気に入ったらサポートをしてみませんか?