Skip to content
Published on

증권사 MTS/HTS 개발자: 거래소 프로토콜부터 마이크로초 latency까지

Authors

글 대상

증권사 IT, MTS(Mobile Trading System), HTS(Home Trading System), OMS(Order Management System), 거래소 게이트웨이 개발 직무에 진입하려는 신입/주니어 그리고 fintech/거래소 인접 도메인에서 증권사로 옮기려는 5-10년차 개발자를 대상으로 한다. JD에 적힌 "대용량 트래픽 처리 경험" "실시간 시세 처리"라는 추상적 표현이 실제로는 어떤 프로토콜, 어떤 latency 숫자, 어떤 장애 패턴을 의미하는지 풀어서 설명한다. 회사 이름과 직무명을 아는 것에서 멈추지 말고, 거래소 spec 한 페이지를 펼쳤을 때 어떤 단어를 검색해야 하는지 감각을 기르자.

왜 MTS/HTS 개발이 "다루는 일"인가

증권사 IT 개발자는 단순히 화면을 만드는 사람이 아니다. 실제로 다루는 대상은 세 층이다.

첫째, 시장이다. 매일 09:00 KRX 정규장이 열리는 순간 수만 건의 주문이 동시에 쏟아진다. 09:00:00.000부터 09:00:00.500까지 500ms 사이에 OMS는 호가 잔량, 가격 우선순위, 동시호가 매칭 로직을 거쳐 거래소로 주문을 전송해야 한다.

둘째, 프로토콜이다. KRX EXTURE+ 시스템은 자체 binary 프로토콜인 KRX UMS를 쓰고, 글로벌 시장은 FIX 4.4/5.0이 표준이다. Nasdaq은 ITCH(시세)/OUCH(주문), TSE는 Arrowhead의 자체 binary frame을 쓴다. 이 모든 프로토콜의 message frame layout, sequence number 처리, gap fill 로직을 다룬다.

셋째, 시스템이다. Front(MTS/HTS 앱) → API Gateway → Order Router → OMS → Exchange Gateway까지 6-7개 hop을 지나는 동안 latency를 50ms 이내로 유지해야 retail 고객 체감 속도가 나온다. HFT라면 tick-to-trade <100μs까지 내려가야 한다.

"다룬다"는 말은 곧 이 세 층 사이의 trade-off를 매일 결정한다는 뜻이다.

시스템 architecture 개요

전형적인 한국 증권사 트레이딩 시스템 architecture는 5-tier 구조다.

  1. Client tier: MTS(iOS/Android, React Native or 네이티브), HTS(Windows C++/.NET native), Web Trading(React/Vue)
  2. Gateway tier: API Gateway(Nginx/Envoy + 자체 인증), WebSocket Gateway(시세 push), MQTT broker(모바일 push)
  3. Middleware tier: Order Router, Risk Engine, Position Manager, Account Service - Java Spring Boot 또는 C++ low-latency
  4. Backend tier: OMS(Order Management System), EMS(Execution Management System), 시세 분배 엔진(Market Data Distribution), 청산/정산 시스템(Settlement)
  5. Exchange Gateway tier: KRX 게이트웨이, KOSCOM 백본, ATS 연결, 해외 거래소 FIX 게이트웨이

각 tier 사이에는 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-delimited 메시지. 글로벌 IB, 해외주식 주문 라우팅의 사실상 표준
  • FIX FAST: FIX의 binary 압축 버전. 시세 채널에서 bandwidth 절약용
  • ITCH/OUCH: Nasdaq 시세(ITCH)/주문(OUCH). Binary protocol, low-latency 최적화
  • Arrowhead: TSE(도쿄증권거래소) 자체 프로토콜. 2010년 도입 후 5세대(2024년 Arrowhead Renewal)까지 진화
  • KRX UMS: 한국거래소 표준 메시지 프로토콜. Binary frame, 자체 sequence number 관리
  • ISO 20022: 결제/청산/정산용 XML 메시지 표준. SWIFT 차세대, KSD(예탁결제원)도 채택 진행 중

FIX는 사람이 읽을 수 있다는 게 강점이고 디버깅이 쉽다. ITCH/OUCH는 binary라 wire format 명세를 들고 와이어샤크 dump를 까봐야 한다.

실제 하루

증권사 IT 운영팀의 하루는 시장 시간에 맞춰 흐른다.

  • 07:00 출근, 야간 batch 결과 확인(전일 정산, 권리 처리, 외화 환산), 거래소 시스템 공지 확인(KRX MDS, KOSCOM 정기 점검)
  • 07:30 시간외 단일가(07:30-08:30) 시작, 호가 시스템 워밍업
  • 08:30 정규장 동시호가(08:30-09:00) 진입. 이때 호가 잔량이 폭증한다
  • 09:00 정규장 개시. 첫 1분 trading volume이 하루의 5-10%까지 나오는 날도 있다. OMS, EMS의 throughput, latency 모니터링 집중
  • 10:00 일일 stand-up. 어제 장애 review, 오늘 release 일정 협의
  • 13:00 거래소 spec 리뷰. KRX 차세대 시스템 변경사항, 신규 상품(ETN, ETF, 토큰증권) 대응
  • 15:30 정규장 마감(KRX). 시간외 단일가(15:40-16:00), 시간외 종가(15:40-15:50) 처리
  • 16:00 미국 시장 pre-market 준비. 해외주식 주문 게이트웨이 점검
  • 18:00 한국 release window. MTS 앱 배포는 보통 화/목 저녁 또는 토요일 새벽
  • 21:30 미국 정규장 개시(서머타임 기준 22:30). 야간팀 인계
  • 05:00 미국 정규장 마감. batch 시작

장 중에는 release를 절대 안 한다. 변경 동결(Change Freeze) 정책이 엄격하다.

Smart Order Router 구조

Smart Order Router(SOR)는 하나의 주문을 여러 시장으로 쪼개 보내는 엔진이다. 한국은 KRX 단독 시장이라 SOR 필요성이 낮았지만, 2025년 ATS(대체거래소) 도입 이후 본격화됐다.

SOR가 판단하는 기준:

  • 가격(Best Bid/Offer): 어느 시장이 더 유리한 호가를 갖고 있는가
  • 잔량(Available Quantity): 한 번에 체결 가능한 수량
  • 수수료(Fee): 시장별 수수료 차이
  • Latency: 어느 시장이 더 빠르게 응답하는가
  • 시장 영향(Market Impact): 큰 주문을 분할해 가격 영향을 최소화

SOR는 보통 C++ 또는 Java Aeron 기반으로 만든다. Decision logic은 마이크로초 단위로 동작하므로 GC pause를 허용하지 않는다.

한국 거래소 연결: KRX KOSPI/KOSDAQ, ATS, 대체매매시설

한국 시장은 KRX(한국거래소)가 KOSPI, KOSDAQ, KONEX를 운영하는 단일 거래소 체제였다. 2025년 넥스트레이드(Nextrade) ATS가 출범하면서 변화가 시작됐다.

  • KRX EXTURE+: 현재 KRX 매매체결 시스템. 2014년 도입, 응답시간 70μs 수준
  • KOSCOM: KRX 자회사, 증권사 백본망 운영. EXTURE+ 접속 게이트웨이 제공
  • Nextrade: 2025년 출범한 한국 첫 ATS(Alternative Trading System). 정규시장 외 시간(주간/야간) 거래 가능

증권사 게이트웨이는 KOSCOM 회선을 통해 KRX에 접속한다. 회선은 보통 이중화하고, KOSCOM 부산 백업센터까지 회선이 빠져 있다.

일본 거래소: TSE Arrowhead, JPX, PTS

일본 시장은 도쿄증권거래소(TSE, Tokyo Stock Exchange)와 오사카증권거래소(OSE)를 통합한 JPX(Japan Exchange Group) 산하 체제다.

  • TSE Arrowhead: 2010년 도입한 차세대 매매 시스템. 응답시간 5세대(2024년 Arrowhead Renewal) 기준 200μs 수준
  • JPX: 도쿄, 오사카, JPX청산소를 묶은 지주회사. TOPIX, Nikkei 225 산하
  • PTS(Proprietary Trading System): 일본의 ATS. SBI Japannext, ODX(Cboe Japan, 구 Chi-X Japan)가 대표
  • ToSTNeT: TSE의 장외 거래 시스템. 블록딜, 단일가 거래용

일본 증권사는 TSE FLEX 프로토콜(자체 binary)을 다루고, 글로벌 IB는 FIX 4.4 + FIX FAST 조합을 쓴다.

Latency 요구사항: tick-to-trade <100μs HFT vs <10ms retail

증권 IT의 latency는 서비스 segment마다 다르다.

  • HFT(High Frequency Trading): tick-to-trade <100μs. 시세 수신부터 주문 전송까지 100마이크로초 이내. 자체 거래소 colocation, FPGA 가속, kernel bypass(DPDK, Solarflare OpenOnload)
  • Algo Trading(증권사 자체 알고): 1-10ms. Java Aeron, Chronicle Queue, off-heap 메모리
  • Retail MTS: 50-200ms. 모바일 네트워크 latency가 큰 비중. 백엔드 자체는 <10ms 목표
  • Retail HTS: 30-100ms. 데스크톱 직접 연결이라 모바일보다 빠름

HFT는 GC pause(Java) 5ms도 용납 안 한다. Zing JVM, Azul Platform Prime 같은 pauseless GC 또는 C++/Rust로 작성한다.

Tech stack 한국: Java/Spring Boot, Kafka, Redis, Cassandra, kdb+, C++

한국 증권사 IT의 tech stack은 다음 조합이 흔하다.

  • 언어: Java 17/21(Spring Boot 3.x), C++(low-latency 코어), 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++ low-latency 코어는 일부 OMS/EMS에서만 사용한다.

Tech stack 일본/글로벌: C++/Java, Aeron, Chronicle, Solace, Tibco RV

글로벌 IB(Goldman, JPM, MS, Citi)와 일본 대형 증권사(Nomura, Daiwa, SBI)의 tech stack은 한국과 차이가 있다.

  • 언어: C++17/20(EMS/OMS 코어), Java(LMAX Disruptor, Aeron, Chronicle), Rust(신규 프로젝트)
  • 저지연 라이브러리: Aeron(UDP 기반 메시징), Chronicle Queue(off-heap persistent queue), LMAX Disruptor(lock-free ring buffer)
  • 메시징: Solace PubSub+(글로벌 IB 표준), Tibco Rendezvous(레거시), Kafka(전사 데이터 파이프라인)
  • 시계열: kdb+(거의 모든 글로벌 IB), Onetick
  • OS: Linux(RHEL/Rocky), 일부 Solaris(레거시)
  • 네트워크: Solarflare/Mellanox NIC, kernel bypass(OpenOnload, DPDK), Arista 스위치

일본 대형 증권사도 글로벌 IB와 유사한 stack을 쓴다. 다만 사내 표준이 보수적이라 Java가 주력이고, C++는 일부 트레이딩 데스크에서만 사용한다.

보안: 공인인증서/금융인증서, PKI, 생체인증, OTP, 2FA, FIDO2, 망분리, ISMS-P, FISC

증권 IT 보안은 사용자 인증과 망 보안 두 축이다.

  • 공인인증서/금융인증서: 한국 PKI 기반 인증. 2020년 공인인증서 폐지 후 금융인증서, 공동인증서로 분화
  • 생체인증: 지문(Touch ID), Face ID, 음성 인증. 모바일 디바이스 키체인 연동
  • OTP/2FA: HOTP/TOTP 기반 OTP, SMS 인증, KAKAO 인증, PASS 앱
  • FIDO2: WebAuthn 기반, 글로벌 표준 진입. 한국도 2023년부터 도입 확대
  • 망분리: 금융권 의무. 업무망/인터넷망 물리적 분리. 개발자 노트북 2대 운영
  • 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 강세. 한국 최대 retail 점유율, 영웅문 HTS/MTS 자체 개발

신입 채용은 미래에셋, 한투, 삼성, KB가 매년 두 자릿수 규모로 뽑는다. 외주 SI는 LG CNS, 삼성SDS, 코스콤, 한투ICT, 신한DS가 주력.

일본 증권사 IT: SBI, Rakuten, Matsui, Nomura, Daiwa + 토스증권 STARTRADE, 카카오페이증권 KakaoStock

일본 증권사 IT는 노포(老舗)와 신흥의 이원화 구조다.

  • 野村證券(Nomura): 일본 최대. 글로벌 IB 동급의 trading platform 운영. 도쿄/홍콩/런던/뉴욕 분산
  • 大和証券(Daiwa): in-house 강세. Daiwa Securities Group ICT 자회사
  • SBI証券: 인터넷 증권 1위. SBI Holdings 산하. 자체 ATS인 SBI Japannext 운영
  • 楽天証券(Rakuten): Rakuten 그룹 시너지. 모바일 트레이딩 강세
  • 松井証券(Matsui): 일본 인터넷 증권 효시(1998년 온라인 전환)
  • マネックス証券(Monex): 미국 시장 강세. TradeStation 미국 인수

한국 신흥은 토스증권(STARTRADE 시스템), 카카오페이증권(KakaoStock 앱)이 대표적이다. 토스증권은 자체 개발 OMS를 운영하고, 카카오페이증권은 한투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 매매체결 시스템 장애: 코스닥 시세 분배 시스템 장애. 약 1시간 시세 중단. 백업 시스템 자동 절체 실패
  • 2010년 Flash Crash(미국): 단일 mutual fund의 대량 매도로 다우 약 1000 포인트 9분간 폭락. 알고리즘 거래 cascade
  • 2020년 Robinhood 장애: 미국 retail 트레이딩 앱, 시장 변동성 급증 시 수 시간 다운. 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 pause <5ms을 보장하려면 어떤 GC와 설정을 쓸 것인가?
  7. Kafka 파티셔닝 키를 종목 코드로 했을 때 hot partition 문제 해결 방법
  8. Redis로 호가 캐시 만들 때 메모리 사용량 추정과 eviction 정책
  9. Low-latency 환경에서 lock-free 큐 구현 방법(SPSC, MPMC)
  10. 망분리 환경에서 외부 OSS 라이브러리는 어떻게 도입하는가?
  11. 장 시작 09:00:00 동시호가 매칭의 가격 우선/시간 우선 원칙
  12. 신용거래 융자/대주 차이와 IT 시스템에서 추적해야 할 데이터
  13. 미수금 발생 시 반대매매 알고리즘
  14. 미국 주식 24시간 거래(pre-market, after-market) 환율 처리
  15. WebSocket으로 시세 push할 때 backpressure 처리 방법
  16. 권리락 처리: 액면분할, 무상증자, 배당 발생 시 잔고 자동 조정
  17. 시장 가격(Market Order) vs 지정가(Limit Order) 주문의 거래소 message 차이
  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, Rakuten): 500-700만엔
  • 일본 5년차: 700-1,000만엔
  • 일본 시니어(Nomura, Daiwa): 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년차): 모듈 단위 설계, 신규 기능 리드. 거래소 spec 직접 리뷰 가능
  • Senior(7-10년차): 시스템 전체 설계, 장애 대응 owner. 신입/주니어 멘토링
  • Tech Lead(10-13년차): 팀 단위 기술 의사결정, code review 책임, hiring
  • Principal/Staff Engineer: 전사 기술 방향, architecture 의사결정. 직급은 회사마다 다름
  • Architect: tier 전반 설계, 신규 시스템 도입(Kafka→Pulsar 같은 의사결정)
  • CTO/CDO: 임원. 사업 의사결정 동참

수평 이동도 흔하다. 증권사→fintech(토스, 카카오페이), 증권사→거래소(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는 마이크로초 단위 latency 요구로 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 or SELL
    qty: int
    limit_price: float

def route_order(order: Order, venues: List[Venue]) -> List[dict]:
    """
    주문을 여러 venue로 분할 라우팅
    우선순위: 가격 > 수수료 포함 net price > latency
    """
    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 gateway 연결 설정 예제
# 실제 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