注文イベントから最終状態を再構成する
한국어 원문으로 표시합니다.
목표
주문 이벤트 로그만 가지고 주문별 최종 상태를 재구성하고, OMS 상태 필드와 어긋난 주문을 찾아내고, 정렬 시계에 따라 결론이 뒤집히는 주문을 집어낸 뒤, 순서에 좌우되지 않는 규칙으로 그 흔들림을 없앨 수 있게 됩니다.
왜 중요한가
증권 시스템에서 "주문 상태" 는 저장된 값이 아니라 이벤트 여러 개를 접어 만든 결과입니다. 접는 규칙이 명시돼 있지 않으면 화면과 통보와 정산 배치가 각자 다른 규칙으로 접고, 그래서 서로 다른 답을 냅니다.
이 실습이 강제하는 네 가지는 전부 현장의 규칙입니다. 상태 필드를 믿지 않는다 — 처리기가 이벤트를 한 번 놓치면 그 주문의 상태 필드는 영원히 틀리고, 이벤트는 다시 흘러오지 않습니다. 취소 요청과 취소 확정을 구분한다 — 요청 시점에 상태를 바꾸면 요청 뒤에 붙은 체결이 통째로 사라집니다. 같은 체결이 두 번 오는 것을 정상으로 다룬다 — 재전송은 없어지지 않으므로 받는 쪽이 걸러야 하고, 거르지 않으면 수량이 조용히 부풉니다. 순서에 답이 좌우되지 않게 만든다 — 순서를 정확히 맞히는 것보다 순서와 무관한 규칙을 쓰는 편이 언제나 낫습니다.
이번 사건은 이렇습니다. 정산팀이 "체결 통보는 받았는데 OMS 화면에는 취소로 떠 있는 주문이 있다" 고 알려 왔습니다. 대상은 2026-08-27 정규장의 주문 900건이고, 우리가 가진 것은 이벤트 로그 한 파일과 OMS 상태 스냅샷 하나입니다.
재생 규칙은 이렇게 씁니다. 이벤트를 시각 오름차순(같으면 seq 오름차순)으로 읽으면서, new 는 상태를 received 로 하고 주문 수량을 정합니다. ack 는 open, reject 는 rejected, cancelled 는 cancelled 로 바꿉니다. replace 는 주문 수량만 바꾸고 상태는 건드리지 않습니다. cancel_req 는 아무것도 바꾸지 않습니다. fill 과 partial_fill 은 누적 체결에 자기 수량을 더한 뒤, 누적이 주문 수량 이상이면 filled, 아니면 partially_filled 로 합니다.
단계
/root/cap/order를 만들고 정답지의 생성기를 그대로 돌려/root/cap/order/events.jsonl과/root/cap/order/oms_status.csv를 만드세요. 난수 씨앗을 바꾸면 채점 값과 어긋납니다./root/cap/order/shape.txt에 열 줄을 적으세요.events=,orders=, 그리고 여덟 가지 이벤트 종류마다type_new=처럼type_<종류>=한 줄씩입니다.- 이벤트를
ts_exch오름차순(같으면seq)으로 재생해/root/cap/order/final_exch.csv를 만드세요. 머리글은order_id,state,cum_qty,order_qty이고 주문 하나에 한 줄씩order_id오름차순입니다. final_exch.csv와oms_status.csv를 대조하세요./root/cap/order/omsdiff.txt에status_mismatch=,qty_mismatch=,any_mismatch=,qty_only_mismatch=네 줄을,/root/cap/order/omsdiff.csv에 어긋난 주문 목록을order_id,replay_state,oms_status,replay_cum_qty,oms_filled_qty머리글과 함께 적습니다.- 같은 로그를
ts_recv로 정렬해/root/cap/order/final_recv.csv를 만들고,/root/cap/order/clock.txt에exch_filled=,recv_filled=,flipped=를,/root/cap/order/flipped.csv에order_id,exch_state,recv_state머리글로 뒤집힌 주문을 적으세요. - 한 주문 안에서 같은
exec_id가 두 번 나온 건을 찾아/root/cap/order/dup.csv에order_id,exec_id,dup_qty,dup_amount_krw로,/root/cap/order/dup.txt에dup_orders=,over_orders=,dup_qty_total=,dup_amount_total=로 적으세요. - 보정 규칙 두 가지를 넣어
/root/cap/order/final_fixed.csv를 만드세요 —exec_id로 중복 체결을 거르고, 재생이 끝난 뒤 누적이 주문 수량 이상이면 상태를filled로 못 박습니다./root/cap/order/fixed.txt에flip_before=,flip_after=,final_filled=,final_cancelled=를 적습니다. /root/cap/order/report.md에 보고서를 쓰세요.## 무슨 일이 있었나,## 근거,## 돈으로 얼마인가,## 왜 이런 일이 생기나,## 무엇을 고쳐야 하나다섯 절이 필요합니다.
참고
- 금액은 전부 정수 원 단위입니다. 실수로 다루면 합계가 미세하게 어긋나 채점에서 떨어집니다.
- 정렬 기준을 하나만 쓰면 같은 시각의 두 이벤트에서 매번 다른 답이 나옵니다. 항상
(시각, seq)두 개로 정렬하세요. - 흔한 실수 1: 4단계에서 상태 문자열만 비교하는 것. 그러면 27건에서 멈추고, 상태는 맞는데 수량이 빠진 40건을 통째로 놓칩니다.
- 흔한 실수 2: 6단계에서 누적이 주문 수량을 넘긴 것만 세는 것. 넘지 않은 중복이 더 위험합니다 — 아무 경보도 울리지 않기 때문입니다.
- 흔한 실수 3: 7단계에서 중복만 걸러 놓고 상태 판정 규칙을 그대로 두는 것. 그러면 뒤집히는 40건이 그대로 남습니다.
이벤트 로그와 OMS 스냅샷 만들기
/root/cap/order 를 만들고 정답지의 생성기를 그대로 돌려 /root/cap/order/events.jsonl 과 /root/cap/order/oms_status.csv 를 만드세요. 난수 씨앗을 바꾸면 채점 값과 어긋납니다.
python3 로 생성기를 그대로 돌리면 됩니다. 난수 씨앗을 바꾸면 채점 값과 어긋나니 그대로 두세요.
이벤트 스트림의 모양 세기
/root/cap/order/shape.txt 에 열 줄을 적으세요. events=, orders=, 그리고 여덟 가지 이벤트 종류마다 type_new= 처럼 type_<종류>= 한 줄씩입니다.
type 별로 세면 됩니다. ack 가 900이 아닌 이유를 설명할 수 있어야 다음 단계가 쉬워집니다.
거래소 시각으로 재생하기
이벤트를 ts_exch 오름차순(같으면 seq)으로 재생해 /root/cap/order/final_exch.csv 를 만드세요. 머리글은 order_id,state,cum_qty,order_qty 이고 주문 하나에 한 줄씩 order_id 오름차순입니다.
이벤트를 ts_exch 오름차순, 같으면 seq 오름차순으로 정렬해 순서대로 접습니다. cancel_req 는 상태를 바꾸지 않는다는 것만 기억하면 나머지는 안내에 적힌 그대로입니다.
OMS 상태 필드와 대조하기
final_exch.csv 와 oms_status.csv 를 대조하세요. /root/cap/order/omsdiff.txt 에 status_mismatch=, qty_mismatch=, any_mismatch=, qty_only_mismatch= 네 줄을, /root/cap/order/omsdiff.csv 에 어긋난 주문 목록을 order_id,replay_state,oms_status,replay_cum_qty,oms_filled_qty 머리글과 함께 적습니다.
두 번 비교하세요. 상태 문자열만 비교했을 때와 체결 수량까지 비교했을 때의 숫자가 다릅니다. 그 차이가 이 단계의 요점입니다.
수신 시각으로 다시 재생해 비교하기
같은 로그를 ts_recv 로 정렬해 /root/cap/order/final_recv.csv 를 만들고, /root/cap/order/clock.txt 에 exch_filled=, recv_filled=, flipped= 를, /root/cap/order/flipped.csv 에 order_id,exch_state,recv_state 머리글로 뒤집힌 주문을 적으세요.
3단계와 같은 함수에 정렬 기준만 ts_recv 로 바꿔 넣으면 됩니다. 두 결과의 state 를 주문별로 비교해 다른 것만 모으세요.
같은 체결이 두 번 들어온 건 찾기
한 주문 안에서 같은 exec_id 가 두 번 나온 건을 찾아 /root/cap/order/dup.csv 에 order_id,exec_id,dup_qty,dup_amount_krw 로, /root/cap/order/dup.txt 에 dup_orders=, over_orders=, dup_qty_total=, dup_amount_total= 로 적으세요.
한 주문 안에서 같은 exec_id 가 두 번 나오는지를 보세요. 누적이 주문 수량을 넘긴 것만 세면 절반도 못 찾습니다.
순서에 좌우되지 않는 규칙 넣기
보정 규칙 두 가지를 넣어 /root/cap/order/final_fixed.csv 를 만드세요 — exec_id 로 중복 체결을 거르고, 재생이 끝난 뒤 누적이 주문 수량 이상이면 상태를 filled 로 못 박습니다. /root/cap/order/fixed.txt 에 flip_before=, flip_after=, final_filled=, final_cancelled= 를 적습니다.
두 가지를 넣습니다. exec_id 로 중복 체결을 거르는 것과, 재생이 끝난 뒤 누적이 주문 수량 이상이면 상태를 체결로 못 박는 것. 그다음 두 시계로 각각 재생해 결과가 같은지 세세요.
조사 보고서 쓰기
/root/cap/order/report.md 에 보고서를 쓰세요. ## 무슨 일이 있었나, ## 근거, ## 돈으로 얼마인가, ## 왜 이런 일이 생기나, ## 무엇을 고쳐야 하나 다섯 절이 필요합니다.
다섯 절이 필요합니다. 원인 절에는 시계와 순서 이야기가, 조치 절에는 중복 제거 이야기가 들어가야 합니다. 숫자는 본문에 그대로 적으세요.