FIX 接続の流量制限と再接続── 切断のあとに注文を二重に出さない設計
インフラ

FIX 接続の流量制限と再接続── 切断のあとに注文を二重に出さない設計

FTL編集部

FIX の接続が平常時に安定して動いていても、本当に試されるのは回線が切れた直後です。切断の瞬間に送っていた注文は相手に届いたのか、板に残っている注文は取り消されたのか、再接続したら何を送り直せばよいのか。ここで判断を誤ると、同じ注文を二重に出すか、取り消したつもりの注文が板に残ります。

本稿では、セッション層の基本を扱った前稿の続きとして、流量の上限・切断時の自動取消・再接続での番号の合わせ方・重複の見分け方を整理します。これらの多くは FIX の規格ではなく、対向ごとの接続仕様で決まります。具体例には、公開されている Cboe と Coinbase の FIX 仕様を使います。

流量の上限は規格ではなく対向が決める

FIX のセッション層には、毎秒何件まで送ってよいかという決まりはありません。上限は取引所や証券会社が、それぞれの仕様で定めています。

Cboe Futures Exchange の FIX 仕様では、接続口(ポート)ごとの上限と銘柄ごとの上限が、どちらも既定で毎秒 3,000 件です。上限を超えたときの扱いも書かれており、その時間枠の新規注文はすべて拒否され、訂正は取消として扱われ、取消はそのまま処理されます。

この扱いには、設計上の示唆が 2 つあります。

  • 取消は止めずに通す — 混雑時に取消まで送信待ちの列に並べると、取引所側では通るはずの取消を自分で遅らせることになる。送信側の流量制御は、新規と訂正を絞り、取消を優先する形にする
  • 訂正が取消に化ける — 上限を超えた訂正は、値を変えた注文ではなく取消として処理される。訂正の応答を待たずに「訂正済み」とみなす実装は、板から注文が消えたことに気づかない

同じ仕様には、検証用の銘柄では上限が毎秒 1 件になるとも書かれています。本番と同じ速度で負荷試験をしようとすると、検証環境で拒否が続きます。検証の計画を立てる前に、対向の検証環境の上限を確認しておきます。

切断の瞬間に注文はどうなるか

回線が切れたとき、板に残っている注文をどうするかも対向ごとに違います。多くの取引所は、切断を検知して注文を自動で取り消す機能(Cancel on Disconnect)を持っていますが、設定の場所と範囲がそろっていません。

  • Cboe Futures Exchange — ポートの属性として設定する。既定は「All」で、当日限りの注文に加えて期限付きの注文も取り消す。「Day」なら当日限りだけ、「None」なら取り消さない。正常な切断でも異常な切断でも動く
  • Cboe の米国株 — 会員から心拍 2 回分の間メッセージが届かなければ、未約定の注文をすべて取り消す。心拍の間隔は最短 5 秒
  • Coinbase Exchange — Logon の CancelOrdersOnDisconnect(8013) で接続ごとに指定する。S ならそのセッションの注文、Y ならプロファイル全体の注文が対象

Coinbase の仕様には、取引所がまだ受付を返していない注文は、取り消される保証がないとも明記されています。切断の直前に送った注文は、届いて残っているかもしれないし、届いていないかもしれません。自動取消があっても「切断したら板は空」とは言い切れないということです。再接続したあとは、次の節以降で述べる番号の照合と注文状態の照会を、必ず行う前提で組みます。

FIX 接続が切れてから業務を再開するまでの手順を示した図。切断時の自動取消の範囲を確認し、再接続で番号を合わせ、注文状態を照会して手元の記録と突き合わせてから、新規注文を再開する。送り直す注文は同じ ClOrdID で PossResend を付ける
番号を合わせただけでは、注文が板にあるかは分からない

再接続では番号の合わせ方を先に決める

FIX のシーケンス番号は接続をまたいで続きます。再接続のときに、その番号をどう合わせるかには主に 2 つのやり方があります。

1 つは、Logon で ResetSeqNumFlag(141) を立てて、双方の番号を 1 に戻すやり方です。単純ですが、切断の前後に送られたメッセージの再送は受けられません。Coinbase Exchange はこちらを既定にしており、クライアントから取引所への番号は切断のたびに必ず戻ります。取引所からクライアントへの番号を引き継ぎたい場合は、141=N で Logon し、取引所が返す番号まで再送を要求します。抜けが大きいときは 1,000 件ずつに分けて要求します。

もう 1 つは、FIX 4.4 から Logon に加わった NextExpectedMsgSeqNum(789) を使うやり方です。各自が「相手から次に受け取るはずの番号」を Logon に入れて送り、受け取った側は自分が次に振る番号と比べます。

  • 同じ — その番号から新しいメッセージを送る
  • 相手の値のほうが小さい — 相手が受け取れていない分を順に再送してから、新しいメッセージを送る
  • 相手の値のほうが大きい — 自分が送ったことのない番号を相手が待っている。整合しないので Logout してセッションを打ち切る

このやり方では、Logon に付いた番号を見て再送要求(Resend Request)を出してはいけない決まりになっています。再送要求の往復を待たずに抜けを埋められるのが利点ですが、使うかどうかは対向との合意が前提です。片方だけが対応していると、Logon の直後に番号がずれます。

どちらのやり方でも、再接続を即座に繰り返す実装は避けます。番号の不整合で打ち切られた接続は、何度つなぎ直しても同じ理由で切られます。待ち時間を少しずつ延ばし、一定回数で運用担当へ知らせる形にしておきます。

重複を見分ける印は 2 つある

送り直したメッセージには、重複かもしれないことを示す印を付けます。FIX にはこの印が 2 つあり、意味が違います。

  • PossDupFlag(43) — 同じシーケンス番号のまま送り直したことを示す。再送要求に応えるときなど、セッション層の都合で使う。受け取った側は番号で重複を判定できる
  • PossResend(97) — 以前に別の番号で送った内容を、新しい番号で送り直したことを示す。番号が違うので、セッション層では重複と分からない。判定は業務層が注文 ID などで行う

切断の直前に送った注文に応答が無かったとき、業務として送り直すなら使うのは後者です。そのとき注文 ID の ClOrdID(11) は元と同じ値を使います。新しい ID で送れば、取引所から見れば別の注文で、届いていた場合は二重の発注になります。FIX 4.1 以降には、重複した注文を拒否する理由として OrdRejReason(103)=6(Duplicate Order)も用意されています。

ただし、PossResend への対応も対向ごとに違います。Cboe Futures Exchange は PossResend=Y の新規注文に対応しておらず、受け取っても黙って無視します。ClOrdID の重複を判定するのは、その時点で板に残っている注文の範囲だけです。Coinbase Exchange は、ClOrdID を UUID 形式で付け、未約定の注文と重ならないことを求めています。送り直しの印に頼れない対向では、送り直す前に次の節の照会で、届いていたかを確かめるしかありません。

再接続のあとは注文の状態を突き合わせる

番号が合っても、それはメッセージの抜けが埋まったというだけです。手元の記録と取引所の板が一致しているかは、別に確かめる必要があります。FIX 4.4 には、そのためのメッセージがあります。

  • Order Status Request(35=H) — 注文を 1 件ずつ照会する
  • Order Mass Status Request(35=AF) — 条件に合う注文をまとめて照会する。MassStatusReqType(585)=7 ならその接続で出した注文すべて。結果は注文ごとに、ExecType(150) が Order Status の Execution Report で返る

再接続後の手順は、番号を合わせる → 応答待ちだった注文と板に残っているはずの注文を照会する → 手元の記録と突き合わせる → 食い違いを解消する → 新規注文を再開する、の順にします。突き合わせが終わるまで新規注文を止めておくのが要点です。先に新規を流すと、食い違いの原因が切断前のものか再開後のものか区別できなくなります。

照会用のメッセージに対応していない対向もあります。その場合は、約定の写しを別の接続で配信するドロップコピーや、取引所の管理画面での確認を手順に組み込みます。どの手段が使えるかは、接続仕様書で事前に確認しておきます。

複数の対向をまとめるときの台帳

ここまでの項目は、どれも対向ごとに値が違います。複数の取引所や証券会社に接続する基盤では、対向ごとに次の項目を台帳にまとめ、実装の分岐ではなく設定として持たせます。

  • 流量の上限 — 単位(ポート・銘柄・セッション)、超過時の扱い、検証環境の上限
  • 切断時の自動取消 — 有無、対象の範囲、設定の場所(ポートの属性か Logon か)
  • 番号の合わせ方 — 毎回 1 に戻すか、引き継ぐか、NextExpectedMsgSeqNum に対応しているか
  • 重複の扱い — PossResend に対応しているか、ClOrdID の形式と一意性の範囲
  • 状態の照会手段 — 35=H・35=AF・ドロップコピーのどれが使えるか

この台帳は、接続検証の確認項目にもなります。対向の検証環境で、上限を超えたとき・切断したとき・送り直したときに、仕様書のとおりの応答が返るかを 1 項目ずつ確かめます。

まとめ

FIX 接続の流量の上限、切断時の自動取消、再接続での番号の合わせ方、送り直した注文の重複の扱いは、規格ではなく対向の仕様で決まります。Cboe Futures Exchange は毎秒 3,000 件を超えた新規を拒否して取消は通し、PossResend の新規注文は無視します。Coinbase Exchange は切断のたびに番号を戻し、受付前の注文の取消は保証しません。送り直すときは同じ ClOrdID を使い、再接続後は注文の状態を照会して突き合わせるまで新規を止めます。対向ごとの差は台帳にまとめ、設定として扱います。

金融テクノロジー総合研究所では、FIX 接続の設計・実装・接続検証の支援を受託しています。複数の対向をまとめる発注基盤の設計や、既存接続の切断時の挙動の点検からご相談いただけます。FIX 対応の詳細もあわせてご覧ください。ご相談はお問い合わせよりご連絡ください。

参考資料

記事一覧に戻る