Skip to content
Published on

証券会社MTS/HTS開発者:取引所プロトコルからマイクロ秒レイテンシまで

Authors

対象者

証券会社IT、MTS(Mobile Trading System)、HTS(Home Trading System)、OMS(Order Management System)、取引所ゲートウェイ開発職に進む新卒・ジュニア、そしてfintechや取引所隣接ドメインから証券会社へ転職を考える5-10年目のエンジニアが対象です。求人票の「大量トラフィック処理経験」「リアルタイム市場データ処理」といった抽象的な表現が、実際にはどのプロトコル・どのレイテンシ数字・どの障害パターンを意味するかを噛み砕いて説明します。会社名や職種名を覚えるだけでなく、取引所仕様書を1ページ開いた時にどの単語を検索すべきかという感覚を身につけましょう。

なぜMTS/HTS開発が「扱う仕事」なのか

証券会社ITエンジニアは単に画面を作る人ではありません。実際に扱う対象は3層あります。

第一に、市場です。毎日09:00にKRX(韓国取引所)・東証の前場が開く瞬間、数万件の注文が同時に殺到します。09:00:00.000から09:00:00.500までの500ms以内に、OMSは板残量、価格優先順位、寄付板寄せのマッチングロジックを経て取引所へ注文を送らなければなりません。

第二に、プロトコルです。KRX EXTURE+システムは独自バイナリプロトコルKRX UMSを使い、グローバル市場はFIX 4.4/5.0が標準です。NasdaqはITCH(市場データ)/OUCH(注文)、東証はArrowheadの独自バイナリフレームを使います。これらすべてのメッセージフレームレイアウト、シーケンス番号処理、ギャップフィルロジックを扱います。

第三に、システムです。フロント(MTS/HTSアプリ)→APIゲートウェイ→Order Router→OMS→取引所ゲートウェイまで6-7ホップを通る間、レイテンシを50ms以内に保たないとリテール顧客の体感速度は出ません。HFTならtick-to-trade <100μsまで落とす必要があります。

「扱う」とは、この3層間のトレードオフを毎日決定することを意味します。

システムアーキテクチャ概要

典型的な韓国証券会社トレーディングシステムは5階層アーキテクチャです。

  1. クライアント層: MTS(iOS/Android、React Nativeまたはネイティブ)、HTS(Windows C++/.NETネイティブ)、Webトレーディング(React/Vue)
  2. ゲートウェイ層: APIゲートウェイ(Nginx/Envoy + 独自認証)、WebSocketゲートウェイ(市場データプッシュ)、MQTTブローカー(モバイルプッシュ)
  3. ミドルウェア層: Order Router、Risk Engine、Position Manager、Account Service - Java Spring BootまたはC++低レイテンシ
  4. バックエンド層: OMS、EMS(Execution Management System)、市場データ配信エンジン、清算/決済システム
  5. 取引所ゲートウェイ層: KRXゲートウェイ、KOSCOMバックボーン、ATS接続、海外取引所FIXゲートウェイ

各層の間にはKafka、Solace、Tibco RV、Aeronなどのメッセージングミドルウェアが入ります。韓国証券会社はKafka + Redis組合せが多く、グローバルIBはSolaceまたはTibcoを使います。

コアプロトコル: FIX 4.4/5.0、FAST、ITCH/OUCH、Arrowhead、KRX UMS、ISO 20022

証券IT面接で「FIXプロトコル触ったことある?」は本気の質問です。標準プロトコルをまとめると次の通りです。

  • FIX 4.4/5.0: Financial Information eXchange。ASCII tag=value SOH区切りメッセージ。グローバルIB、海外株式注文ルーティングの事実上の標準
  • FIX FAST: FIXのバイナリ圧縮版。市場データチャネルで帯域節約用
  • ITCH/OUCH: Nasdaq市場データ(ITCH)/注文(OUCH)。バイナリプロトコル、低レイテンシ最適化
  • Arrowhead: 東証独自プロトコル。2010年導入後、第5世代(2024年Arrowhead Renewal)まで進化
  • KRX UMS: 韓国取引所標準メッセージプロトコル。バイナリフレーム、独自シーケンス番号管理
  • ISO 20022: 決済/清算用XMLメッセージ標準。SWIFT次世代、韓国KSD(預託決済院)も採用進行中

FIXは人間が読めるのが強みでデバッグが楽です。ITCH/OUCHはバイナリなのでwire format仕様書を持ち、Wiresharkダンプを開く必要があります。

実際の一日

証券会社IT運用チームの一日は市場時間に合わせて流れます。

  • 07:00 出社、夜間バッチ結果確認(前日決済、コーポレートアクション、外貨換算)、取引所システム告知確認(KRX MDS、KOSCOM定期メンテ、東証 arrownet)
  • 07:30 立会外単一価格(07:30-08:30)開始、板システム暖機
  • 08:30 前場寄付板寄せ(08:30-09:00)突入。この時板残量が爆発
  • 09:00 前場開始。最初の1分の取引量が1日の5-10%出る日も。OMS、EMSのスループット、レイテンシ集中監視
  • 10:00 デイリースタンドアップ。昨日の障害レビュー、本日のリリーススケジュール協議
  • 13:00 取引所仕様レビュー。Arrowhead Renewal変更、新商品(ETN、ETF、セキュリティトークン)対応
  • 15:30 後場大引け(東証)。立会外取引へ
  • 16:00 米国プレマーケット準備。海外株式注文ゲートウェイ点検
  • 18:00 リリースウィンドウ。MTSアプリ展開は通常火/木夕方または土曜未明
  • 21:30 米国前場開始(夏時間基準22:30)。夜間チームへ引継ぎ
  • 05:00 米国大引け。バッチ開始

立会時間中は絶対にリリースしません。変更凍結(Change Freeze)ポリシーが厳格です。

Smart Order Router構造

Smart Order Router(SOR)は1つの注文を複数市場へ分割送信するエンジンです。韓国は長らくKRX単独市場でSOR需要が低かったのですが、2025年Nextrade ATS出帆以降本格化しました。日本ではすでにPTS存在で本格運用されています。

SORが判断する基準は以下の通りです。

  • 価格(Best Bid/Offer): どの市場がより有利な気配を持っているか
  • 数量(Available Quantity): 一度に約定可能な数量
  • 手数料(Fee): 市場別手数料差
  • レイテンシ: どの市場がより速く応答するか
  • 市場インパクト(Market Impact): 大口注文を分割して価格影響を最小化

SORは通常C++またはJava Aeronで実装されます。意思決定ロジックはマイクロ秒単位で動作するため、GCポーズを許しません。

韓国取引所接続: KRX KOSPI/KOSDAQ、ATS、Nextrade

韓国市場はKRX(韓国取引所)がKOSPI、KOSDAQ、KONEXを運営する単一取引所体制でした。2025年Nextrade ATS出帆で変化が始まりました。

  • KRX EXTURE+: 現KRX売買執行システム。2014年導入、応答時間70μsレベル
  • KOSCOM: KRX子会社、証券会社バックボーン網運営。EXTURE+接続ゲートウェイ提供
  • Nextrade: 2025年出帆した韓国初のATS。立会時間外(日中/夜間)取引可能

証券会社ゲートウェイはKOSCOM回線を通じてKRXに接続します。回線は通常二重化し、KOSCOM釜山バックアップセンターまで回線が引かれています。

日本取引所: TSE Arrowhead、JPX、PTS

日本市場は東京証券取引所(TSE)と大阪証券取引所(OSE)を統合したJPX(Japan Exchange Group)傘下体制です。

  • TSE Arrowhead: 2010年導入の次世代売買システム。第5世代(2024年Arrowhead Renewal)で応答時間200μsレベル
  • JPX: 東証、大証、JPX清算機関を束ねた持株会社。TOPIX、日経225傘下
  • PTS(Proprietary Trading System): 日本のATS。SBI Japannext、ODX(Cboe Japan、旧Chi-X Japan)が代表
  • ToSTNeT: 東証の立会外取引システム。バスケット取引、ToSTNeT-1/2/3用途別

日本の証券会社は東証FLEXプロトコル(独自バイナリ)を扱い、グローバルIBはFIX 4.4 + FIX FAST組合せを使います。

レイテンシ要件: tick-to-trade <100μs HFT vs <10ms retail

証券ITのレイテンシはサービスセグメントごとに異なります。

  • HFT(High Frequency Trading): tick-to-trade <100μs。市場データ受信から注文送信まで100マイクロ秒以内。取引所コロケーション、FPGA加速、kernel bypass(DPDK、Solarflare OpenOnload)
  • アルゴリズム取引(証券会社自社アルゴ): 1-10ms。Java Aeron、Chronicle Queue、off-heapメモリ
  • リテールMTS: 50-200ms。モバイルネットワークレイテンシが大きい比重。バックエンド自体は<10ms目標
  • リテールHTS: 30-100ms。デスクトップ直接接続でモバイルより速い

HFTはGCポーズ(Java)5msも許容しません。Zing JVM、Azul Platform Primeのようなpauseless GCまたはC++/Rustで書きます。

テックスタック韓国: Java/Spring Boot、Kafka、Redis、Cassandra、kdb+、C++

韓国証券会社ITのテックスタックは次の組合せが多いです。

  • 言語: Java 17/21(Spring Boot 3.x)、C++(低レイテンシコア)、Python(データ分析/ML)
  • フレームワーク: Spring Boot、Spring Cloud、Netty(WebSocket)、Akka(稀)
  • メッセージング: Apache Kafka(主力)、Redis Pub/Sub、RabbitMQ(レガシー)
  • キャッシュ: Redis(注文状態、板キャッシュ)、Hazelcast(分散キャッシュ)
  • DB: Oracle(レガシー元帳)、PostgreSQL(新規)、MySQL、MariaDB
  • 時系列DB: kdb+(市場データ標準)、InfluxDB、TimescaleDB
  • NoSQL: Cassandra(注文ログ)、MongoDB(顧客行動)
  • インフラ: VMware → Kubernetes移行中、内部網(網分離規制)
  • モニタリング: Grafana + Prometheus、ELK、Datadog

未来アセット、韓国投資、サムスン、KBはJava/Spring中心。C++低レイテンシコアは一部OMS/EMSのみ使用します。

テックスタック日本/グローバル: C++/Java、Aeron、Chronicle、Solace、Tibco RV

グローバルIB(Goldman、JPM、MS、Citi)と日本大手証券(野村、大和、SBI)のテックスタックは韓国と差があります。

  • 言語: C++17/20(EMS/OMSコア)、Java(LMAX Disruptor、Aeron、Chronicle)、Rust(新規プロジェクト)
  • 低レイテンシライブラリ: Aeron(UDPベースメッセージング)、Chronicle Queue(off-heap永続キュー)、LMAX Disruptor(lock-freeリングバッファ)
  • メッセージング: Solace PubSub+(グローバルIB標準)、Tibco Rendezvous(レガシー)、Kafka(全社データパイプライン)
  • 時系列: kdb+(ほぼすべてのグローバルIB)、Onetick
  • OS: Linux(RHEL/Rocky)、一部Solaris(レガシー)
  • ネットワーク: Solarflare/Mellanox NIC、kernel bypass(OpenOnload、DPDK)、Aristaスイッチ

日本大手証券もグローバルIBと類似スタックを使います。ただし社内標準が保守的でJavaが主力、C++は一部トレーディングデスクのみで使用します。

セキュリティ: 公的認証書/金融認証書、PKI、生体認証、OTP、2FA、FIDO2、網分離、ISMS-P、FISC

証券ITセキュリティはユーザー認証と網セキュリティ二軸です。

  • 韓国PKI証明書: 2020年公認認証書廃止後、金融認証書、共同認証書に分化
  • 生体認証: 指紋(Touch ID)、Face ID、音声認証。モバイルデバイスKeychain連携
  • OTP/2FA: HOTP/TOTPベースOTP、SMS認証、KAKAO認証、PASSアプリ
  • FIDO2: WebAuthnベース、グローバル標準進入。韓国も2023年から導入拡大
  • 網分離: 金融圏義務。業務網/インターネット網物理分離。開発者ノートPC2台運用
  • ISMS-P: 韓国情報保護認証。毎年更新
  • FISC安全対策基準: 日本金融情報システムセンター標準。日本金融機関義務

網分離のため韓国証券会社開発者はGitHub.com直接アクセスが困難です。内部GitLab/Bitbucketを使い、外部OSSダウンロードはnexusのようなプロキシを経由します。

韓国証券会社IT: 未来アセット、韓投、サムスン、KB、新韓投資

韓国証券会社IT組織はin-house vs SI外注モデルに分かれます。

  • 未来アセット証券: in-house強勢。M-STOCKアプリ自社開発。CIO傘下デジタル革新本部
  • 韓国投資証券: in-house + 外注混合。韓投ICT子会社運営
  • サムスン証券: in-house。サムスンSDS一部協業。mPOPアプリ
  • KB証券: 外注比重高い。KBデータシステム一部協業。M-ableアプリ
  • 新韓投資証券: in-house + 外注混合。新韓金融グループIT子会社新韓DS協業
  • NH投資証券: 農協IT子会社NongHyup IT協業
  • キウム証券: in-house強勢。韓国最大リテールシェア、英雄門HTS/MTS自社開発

新卒採用は未来アセット、韓投、サムスン、KBが毎年2桁規模で採用。外注SIはLG CNS、サムスンSDS、KOSCOM、韓投ICT、新韓DSが主力。

日本証券会社IT: SBI、楽天、松井、野村、大和 + Toss STARTRADE、Kakao Pay Securities KakaoStock

日本証券会社ITは老舗と新興の二元化構造です。

  • 野村證券: 日本最大。グローバルIB同等のトレーディングプラットフォーム運営。東京/香港/ロンドン/ニューヨーク分散
  • 大和証券: in-house強勢。Daiwa Securities Group ICT子会社
  • SBI証券: インターネット証券1位。SBI Holdings傘下。独自ATSであるSBI Japannext運営
  • 楽天証券: 楽天グループシナジー。モバイルトレーディング強勢
  • 松井証券: 日本インターネット証券嚆矢(1998年オンライン転換)
  • マネックス証券: 米国市場強勢。TradeStation米国買収

韓国新興はToss証券(STARTRADEシステム)、Kakao Pay証券(KakaoStockアプリ)が代表的です。Toss証券は自社開発OMSを運営し、Kakao Pay証券は韓投ICTバックエンドの上に自社フロントを載せています。

AI/ML適用: 不正取引検知、KYC OCR、チャットボット、推奨銘柄

証券会社AI/ML活用領域は大きく5つです。

  1. 不正取引検知(FDS、Fraud Detection System): 借名口座、自己取引、相場操縦、pump-and-dump検知。Graph Neural Network、anomaly detection
  2. KYC(Know Your Customer): 身分証OCR、顔認識、ライブネスチェック。AWS Textract、GCP Vision API
  3. チャットボット: 残高照会、注文履歴、市場情報案内。LLMベース(GPT-4o、Claude、HyperCLOVA X)
  4. 推奨銘柄: 顧客ポートフォリオ分析、類似顧客買付銘柄推奨。Collaborative Filtering、Matrix Factorization
  5. アルゴリズム取引シグナル: 価格パターン、出来高、ファンダメンタル結合。XGBoost、LSTM、Transformer

AI領域は別チームに分離されたところが多いです(未来アセットデジタル革新本部傘下AI Lab、韓投AI推進TF)。トレーディングシステム開発者が直接モデルを作るより、AIチーム成果物をシステムに統合する仕事が多いです。

失敗事例: サムスン証券2018社員株配当事故、Knight Capital 2012、KOSCOM 2008

証券ITの失敗事例はシステム開発者が必ず暗記すべきです。

  • 2018年サムスン証券社員株配当事故: 社員株28億ウォン現金配当を28億株株式配当に誤入力。一部社員が実際に売却し市場ショック。入力検証、限度チェック不在
  • 2012年Knight Capital(米国): 新規デプロイコードのdeprecated flag再使用で45分間誤注文殺到、4.6億ドル損失、会社破綻。SDLCデプロイプロセス不在
  • 2008年KOSCOM売買執行システム障害: KOSDAQ市場データ配信システム障害。約1時間市場データ中断。バックアップシステム自動切替失敗
  • 2010年Flash Crash(米国): 単一mutual fundの大量売付でダウ約1000ポイント9分間暴落。アルゴリズム取引cascade
  • 2020年Robinhood障害: 米国リテールトレーディングアプリ、市場変動性急増時に数時間ダウン。capacity planning失敗

これら事例の共通点は入力検証、限度チェック、デプロイプロセス、バックアップ手順のどこかが崩壊したことです。

面接質問20個

証券IT面接でよく出る質問20個を領域別にまとめました。

  1. FIX 4.4のMsgType=D(NewOrderSingle)とMsgType=8(ExecutionReport)の違いは?
  2. OMSとEMSの責任分離を説明せよ
  3. Sequence number gap発生時の復旧手順は?
  4. 板情報(Order Book)をメモリにどう表現するか?データ構造と時間計算量
  5. 注文重複防止のためのidempotency key設計
  6. Java GCポーズ<5msを保証するならどのGCと設定を使うか?
  7. KafkaパーティショニングキーをティッカーコードにしたときのHot Partition問題解決法
  8. Redisで板キャッシュを作るときのメモリ使用量推定とeviction policy
  9. 低レイテンシ環境でlock-freeキュー実装方法(SPSC、MPMC)
  10. 網分離環境で外部OSSライブラリはどう導入するか?
  11. 寄付09:00:00の板寄せマッチングの価格優先/時間優先原則
  12. 信用取引融資/貸株差とITシステムで追跡すべきデータ
  13. 追証発生時の強制決済アルゴリズム
  14. 米国株24時間取引(プレ、アフター)の為替処理
  15. WebSocketで市場データプッシュ時のバックプレッシャー処理方法
  16. 権利落ち処理: 株式分割、無償増資、配当発生時の残高自動調整
  17. 成行(Market Order)vs指値(Limit Order)注文の取引所メッセージ差
  18. オプション満期日の株価指数SQ(Special Quotation)算出方式
  19. ETF市場メイカー(LP)気配義務システム実装
  20. アルゴリズム取引のTWAP、VWAP、IS、POV戦略差

面接官は答えに詰まったときどう思考を展開するかを見ています。分からないと終わらず、「この部分は分かりませんが、Xという原則で推論すると...」のように説明しましょう。

年収

おおよその年収水準(2025年基準、ベース + インセンティブ)です。

  • 韓国新卒(主要証券会社): 5,000-6,500万ウォンベース。インセンティブ300-1,000万ウォン
  • 韓国5年目: 7,000-9,000万ウォン。インセンティブ500-2,000万ウォン
  • 韓国10年目シニア: 1億-1.3億ウォン。賞与大幅変動
  • 韓国チーム長/リード: 1.3-1.8億ウォン。一部1.5億+
  • 韓国役員(CTO級): 2-5億ウォン+
  • 日本新卒(SBI、楽天): 500-700万円
  • 日本5年目: 700-1,000万円
  • 日本シニア(野村、大和): 1,000-1,300万円
  • 米国first-year(IB tech): $120K-150Kベース、bonus 30-50%
  • 米国シニア(VP級): $300K-500K total comp

HFT/アルゴ取引quant devは別市場です。米国Citadel/Two Sigma/Jane Street新卒パッケージは$400K+、シニアは$1M+も出ます。

キャリアパス: Junior Dev→Senior→Tech Lead→Architect→CTO

典型的な証券会社ITキャリアパスです。

  • Junior Developer(1-3年目): 画面/API開発、バグフィックス、ユニットテスト。メンターシニアと密着ペア
  • Mid-level(4-6年目): モジュール単位設計、新規機能リード。取引所仕様直接レビュー可能
  • Senior(7-10年目): システム全体設計、障害対応owner。新卒/ジュニアメンタリング
  • Tech Lead(10-13年目): チーム単位技術意思決定、code review責任、hiring
  • Principal/Staff Engineer: 全社技術方向、architecture意思決定。職位は会社ごとに違う
  • Architect: tier全般設計、新規システム導入(Kafka→Pulsar型意思決定)
  • CTO/CDO: 役員。事業意思決定参加

水平移動も頻繁です。証券会社→fintech(Toss、Kakao Pay)、証券会社→取引所(KRX/KOSCOM)、証券会社→グローバルIB(GS、JPM、MS韓国支店)に転職。

References

本文で引用された資料です。実際の学習はこれらのURLをブックマークし、毎週新しい発表/スペックを追う形が良いです。

# FIX 4.4 ExecutionReport handler例
# 実production環境ではQuickFIX/Jやonixsなど検証済みライブラリを使用

import quickfix as fix
import quickfix44 as fix44

class TradingApp(fix.Application):
    def onMessage(self, message, sessionID):
        msg_type = fix.MsgType()
        message.getHeader().getField(msg_type)

        if msg_type.getValue() == fix.MsgType_ExecutionReport:
            self.handle_execution_report(message, sessionID)

    def handle_execution_report(self, message, sessionID):
        exec_type = fix.ExecType()
        ord_status = fix.OrdStatus()
        order_id = fix.OrderID()
        cl_ord_id = fix.ClOrdID()
        symbol = fix.Symbol()
        side = fix.Side()
        last_qty = fix.LastQty()
        last_px = fix.LastPx()
        cum_qty = fix.CumQty()
        avg_px = fix.AvgPx()

        message.getField(exec_type)
        message.getField(ord_status)
        message.getField(order_id)
        message.getField(cl_ord_id)
        message.getField(symbol)
        message.getField(side)

        # ExecType=F(Trade) -> 約定
        if exec_type.getValue() == fix.ExecType_TRADE:
            message.getField(last_qty)
            message.getField(last_px)
            message.getField(cum_qty)
            message.getField(avg_px)

            print(f"[FILL] Order={order_id.getValue()} "
                  f"ClOrdID={cl_ord_id.getValue()} "
                  f"Symbol={symbol.getValue()} "
                  f"Side={side.getValue()} "
                  f"LastQty={last_qty.getValue()} "
                  f"LastPx={last_px.getValue()} "
                  f"CumQty={cum_qty.getValue()} "
                  f"AvgPx={avg_px.getValue()}")

            # 約定データをOMS、Position Manager、Risk Engineへ伝播
            self.publish_to_kafka("fills.equity.kospi", {
                "order_id": order_id.getValue(),
                "symbol": symbol.getValue(),
                "qty": last_qty.getValue(),
                "px": last_px.getValue(),
            })

        # OrdStatus=8(Rejected) -> 取引所拒否
        elif ord_status.getValue() == fix.OrdStatus_REJECTED:
            ord_rej_reason = fix.OrdRejReason()
            message.getField(ord_rej_reason)
            print(f"[REJECT] Order={order_id.getValue()} "
                  f"Reason={ord_rej_reason.getValue()}")
            self.alert_oms_reject(order_id.getValue(), ord_rej_reason.getValue())
# Smart Order Router意思決定ロジック(簡略化)
# 実SORはマイクロ秒単位レイテンシ要求でC++またはJava Aeron使用

from dataclasses import dataclass
from typing import List

@dataclass
class Venue:
    name: str          # KRX、Nextrade、NYSEなど
    best_bid: float
    best_ask: float
    bid_qty: int
    ask_qty: int
    latency_us: int    # マイクロ秒
    fee_bps: float     # basis points

@dataclass
class Order:
    symbol: str
    side: str          # BUYまたはSELL
    qty: int
    limit_price: float

def route_order(order: Order, venues: List[Venue]) -> List[dict]:
    """
    注文を複数venueへ分割ルーティング
    優先順位: 価格 > 手数料込みnet price > レイテンシ
    """
    routes = []
    remaining_qty = order.qty

    # BUYはask基準、SELLはbid基準
    if order.side == "BUY":
        candidates = [v for v in venues if v.best_ask <= order.limit_price and v.ask_qty > 0]
        # net price = 気配 + 手数料
        candidates.sort(key=lambda v: (
            v.best_ask * (1 + v.fee_bps / 10000),
            v.latency_us,
        ))

        for venue in candidates:
            if remaining_qty <= 0:
                break
            fill_qty = min(remaining_qty, venue.ask_qty)
            routes.append({
                "venue": venue.name,
                "qty": fill_qty,
                "price": venue.best_ask,
            })
            remaining_qty -= fill_qty
    else:  # SELL
        candidates = [v for v in venues if v.best_bid >= order.limit_price and v.bid_qty > 0]
        candidates.sort(key=lambda v: (
            -v.best_bid * (1 - v.fee_bps / 10000),
            v.latency_us,
        ))
        for venue in candidates:
            if remaining_qty <= 0:
                break
            fill_qty = min(remaining_qty, venue.bid_qty)
            routes.append({
                "venue": venue.name,
                "qty": fill_qty,
                "price": venue.best_bid,
            })
            remaining_qty -= fill_qty

    if remaining_qty > 0:
        # 残量はlimit orderで最も有利なvenueに待機
        routes.append({
            "venue": candidates[0].name if candidates else "KRX",
            "qty": remaining_qty,
            "price": order.limit_price,
            "type": "LIMIT_RESTING",
        })

    return routes
# KRXゲートウェイ接続設定例
# 実production環境ではパスワードvault、証明書PKCS#12に分離

krx_gateway:
  environment: production
  member_code: "001"          # 証券会社会員番号
  participant_id: "PROD001"

  primary:
    host: ums-primary.koscom.co.kr
    port: 30443
    ssl: true
    cert_path: /opt/secrets/krx-prod.p12
  backup:
    host: ums-backup.koscom.co.kr
    port: 30443
    ssl: true
    cert_path: /opt/secrets/krx-prod.p12

  session:
    heartbeat_interval_sec: 30
    logon_timeout_sec: 10
    sequence_reset_on_logon: false
    max_messages_per_sec: 5000
    reconnect_attempts: 5
    reconnect_delay_sec: 2

  order_limits:
    max_order_qty: 1000000
    max_order_value_krw: 10000000000  # 100億ウォン
    max_orders_per_second: 1000

  market:
    kospi_open: "09:00:00"
    kospi_close: "15:30:00"
    pre_market_open: "08:30:00"      # 寄付板寄せ
    after_market_close: "16:00:00"   # 立会外単一価格
    timezone: Asia/Seoul

  monitoring:
    metrics_endpoint: http://prometheus.internal:9090
    alert_channel: "#trading-prod-alerts"
    latency_alert_threshold_ms: 50
    rejected_orders_threshold_per_min: 100