이 실험은 채점 기준 시점과 제출 시점의 격차를 사후 관측값으로 보정하면 방향 적중률이 오르는지를 검증했다. 결과는 가설과 반대였고, 검증 과정에서 학습하지 않은 상수 예측이 학습한 모형을 앞선다는 사실이 함께 드러났다.
가설과 결론
- 가설
- 채점 기준가
P_ref는 제출 시각(15:34) 이후에 확정되지만 사후에는 정확히 관측된다. 따라서 모델 예측에서 그 관측값 (드리프트d)을 차감하면 제출 시점과 채점 기준 시점의 격차가 제거되어 방향 적중률이 상승한다. - 결론
- 기각. 보정한 예측의 적중률은 56.51% 로, 보정하지 않은 예측(56.77%)에도 학습이 없는 규칙(58.61%)에도 미치지 못했다. 원인은 모델 예측오차의 표준편차(2.99틱)가 차감 대상인 드리프트의 크기(중앙값 1.0틱)의 약 세 배라는 데 있다 — 보정은 신호를 정제하는 대신 부호 경계 부근을 뒤집는 잡음으로 작용했다.
- 부수 결론
- 같은 평가 구간에서 “항상 하락”이라는 상수 예측만으로 56.09% 가 나온다. 학습한 두 갈래는 이 기준선을 각각 +0.68%p, +0.42%p 넘었을 뿐이다. 이 발견은 후속 실험의 설계(상수 기준선 사전 등록)에 반영했다.
용어 사전
대상은 한국거래소에 상장된 3년 국채선물이다. 아래 기호는 이 문서 안에서만 통용되는 약속이며, 다른 자료를 찾아볼 필요가 없도록 전부 여기에 정의한다.
- 동시호가
- 장 마지막에 주문을 모아 한 번에 하나의 가격으로 체결하는 방식. 3년 국채선물은 15:45 에 이 방식으로 당일 종가가 확정된다.
- 틱(tick)
- 가격의 최소 변동 단위. 이 상품은 0.01 포인트가 1틱이다. 이 문서의 가격 차이는 전부 틱 정수로 표기한다.
- P34
- 제출 시각(15:34) 기준 가격.
- P_ref
- 채점 기준가. 대회가 채점의 출발점으로 삼는 값으로, 15:35 직전 마지막 체결가다.
- P45
- 정답 가격. 15:45 동시호가로 확정된 당일 종가.
- d (드리프트)
- 제출 이후 1분 동안의 가격 변화,
P_ref − P34. 제출 시점에는 알 수 없으나 사후에 정확히 관측된다. - y
- 모델의 예측 대상,
P45 − P34. - ref_tick
- 채점 대상,
P45 − P_ref를 틱으로 센 값. 이 값의 부호가 정답이다. - ŷ (y-hat)
- 모델이 예측한
y. 문자 위의 삿갓(^)은 “실측값이 아니라 추정값”을 뜻하는 통계학 표기다. - 0틱 무효일
ref_tick이 0인 날. 상승도 하락도 아니어서 방향이 정의되지 않으므로 학습·채점에서 제외한다(건수는 항상 함께 보고한다).- 적중률
- 방향을 맞힌 날의 비율. 이 대회에는 비용·수수료 개념이 없으므로 손익이 아니라 적중률이 성과 지표다.
- 누적틱
- 맞힌 날은 +, 틀린 날은 − 부호로
ref_tick의 크기를 합산한 값. 적중률이 같아도 변동이 큰 날을 맞혔는지 구분하기 위해 함께 보고한다. - 워크포워드 검증
- 과거 구간으로 학습하고 그 다음 해로 시험하기를 해마다 반복하는 평가 방식. 미래 정보가 학습에 유입되는 것을 막는다.
- 이항검정 p값
- “무작위(적중률 50%)였더라도 이 정도 성적이 우연히 나올 확률”. 작을수록 우연으로 설명하기 어렵다. 이 문서의 p값은 전부 단측이다(“더 나은가”만 검정한다).
문제 정의
참가자는 매일 15:34 까지 당일 종가가 채점 기준가보다 오를지 내릴지를 제출한다. 순위는 적중률로 매기며, 미제출은 오답으로 처리되므로 모든 날에 답해야 한다(이하 “커버리지 100%”).
핵심 난점은 제출 시각과 채점 기준 시점이 어긋난다는 데 있다. 기준가는 15:35 직전 마지막 체결가인데 제출은 그보다 앞서므로, 참가자는 채점의 출발점을 모르는 상태에서 방향을 제출한다.
기준시점 격차의 실측
먼저 격차의 크기를 실측했다. “근월물”(현재 거래가 가장 활발한 만기)을 발행정보 표의 규칙대로 선택해 9년치를 재계산했다.
| 항목 | 값 |
|---|---|
| 0틱 무효 — 방향이 정의되지 않는 날 | 22.47% |
| 남은 유효일 | 1,846일 |
| 15:34 기준 방향과 실제 정답 부호가 다른 날 | 16.41% |
| └ 15:34 기준으로는 0틱이라 방향을 낼 수 없는 날 | 258일 |
| └ 부호가 실제로 반대인 날 | 45일 |
| 제출 이후 1분이 1틱 이상 움직인 날 | 56.8% |
| 정답 크기가 정확히 1틱인 날 | 47.1% |
대상일 2,381(봉 누락일 제외). 출처
results/20260909T162843_flip/.
정답 크기의 절반가량이 1틱인데 제출 이후 1분이 그만큼 움직인다. 따라서 15:34 가격만으로 답하는 예측기는 완벽하더라도 적중률 상한이 83.6%다. 이 실험은 그 상한을 걷어내려는 시도다.
ref_tick, 오른쪽이 제출 이후 1분
드리프트 d. 가로축은 둘 다 틱이다. 두 분포의 폭이 같은
자릿수라는 점이 이 문제의 본질이다 — 오른쪽이 0 부근에 몰려 있었다면
격차 자체가 문제가 되지 않았다.
데이터 요약
| 표 | 내용 | 기간 · 규모 | 해상도 | 쓰임 |
|---|---|---|---|---|
price_data_f3y_1m_raw |
3년 국채선물 1분봉 (인포맥스 단말, 연도별 CSV 11개) | 2016-12-14 ~ 2026-09-07 대상일 2,385 · 약 90만 행 |
1분 일 약 420봉 (08:46~15:45) |
라벨과 피처 모두 |
futures_issuance_info |
선물 종목별 거래개시일·최종거래일 | 상장 전 종목 | 종목 단위 | 당일 근월물 선택 |
코스콤 실시간이 아니라 단말 저장분이다. 종가 축은 코스콤과 별도로 대조해 두었다(피처 모듈 독스트링).
표본 선정 절차
| 단계 | 잔여 일수 | 제외 사유 |
|---|---|---|
| 1분봉이 존재하는 모든 날 | 2,385 | — |
| − 봉 누락 | 2,381 | 세 시각(15:34·15:35·15:45) 중 하나라도 없는 날 4일 |
| − 0틱 무효 | 1,846 | 정답이 0틱이라 방향이 정의되지 않는 날 535일 (22.4%) |
| = 평가 표본 (2020–2025) | 1,175 | 2017–2019 는 학습에만 사용 |
동일 일자에 두 계약이 혼재하는 문제를 먼저 차단했다. 만기 전환(롤) 시기에는 하루에 두 종목의 봉이 함께 존재한다 (전체의 30.8%, 연도별 12.8%~72.0%). 종목을 고정하지 않고 날짜로만 집계하면 서로 다른 계약의 가격이 섞여 연도별 비교가 정확히 무효화된다. 피처 생성 단계에서 당일 근월물 코드로 먼저 필터링하며, 코드가 둘 이상인데 선택 근거가 없으면 임의로 하나를 택하지 않고 오류를 발생시킨다.
피처 구성
가격의 종가 축만 사용한다 — 거래량은 포함하지 않았다. 일중 다섯 시각(14:00 · 15:00 · 15:20 · 15:30 · 15:34)에서 각각 아래 여섯 개를 생성한다.
| 이름 | 정의 |
|---|---|
ret_5 / ret_10 / ret_20 / ret_60 |
해당 시각까지 5·10·20·60분 동안의 가격 변화(틱) |
rng_20 | 최근 20분의 고가−저가(틱) — 해당 구간의 변동 폭 |
pos_20 | 최근 20분 범위 내 현재가의 상대 위치(0=최저, 1=최고) |
드리프트 d 는 피처에 포함하지
않는다. 제출 시점에 알 수 없는 값이므로 학습에 넣으면 미래 정보 누설이
된다. 노트북이 실행 중에 피처 목록에 d 가 없음을 확인하고,
포함돼 있으면 그 지점에서 중단한다.
rng_20·
pos_20 은 거의 독립이다. 정보가 중복돼 무의미해진 집합은
아니다 — 따라서 이후의 실패를 “관측할 정보가 없었다”로 설명할 수
없다.모델과 학습 설정
결정트리를 순차적으로 이어 붙여 예측을 보정하는 그래디언트 부스팅
(LightGBM 구현)을 사용했다. 분류가 아니라 회귀다 — 상승·하락이 아니라
y 가 몇 틱인지를 예측하고, 방향은 그 결과의 부호로 읽는다.
ŷ 를 두고 부호를 그대로 읽느냐(c) 관측된 드리프트 d 를 뺀 뒤 읽느냐(d)만 다르다.y_tick 자체를 맞추는 첫 트리라 구조가 가장 크다. 뿌리에서 rng_20 ≤ 16.5 로 갈리고(왼쪽이 참), 각 상자의 n 은 학습 표본 7,564행 중 그 노드에 떨어진 수다. 잎값은 이 트리가 예측에 더하는 틱 수로 학습률 0.03 이 곱해진 뒤의 값이다. 오른쪽 눈금이 max_depth = 4 가 가리키는 구간 — 뿌리 아래 첫 분기부터 잎까지 분기 4번이다.| 분기 위치 \ 피처 | ret_60 | rng_20 | ret_20 | ret_10 | pos_20 | ret_5 | 합 |
|---|---|---|---|---|---|---|---|
| 깊이 0 (뿌리) | 170 | 66 | 85 | 27 | 15 | 37 | 400 |
| 깊이 1 | 206 | 99 | 83 | 115 | 20 | 95 | 618 |
| 깊이 2 | 157 | 165 | 129 | 138 | 122 | 84 | 795 |
| 깊이 3 | 226 | 174 | 122 | 124 | 176 | 94 | 916 |
| 분기 합 | 759 | 504 | 419 | 404 | 333 | 310 | 2,729 |
| 손실 감소(gain) 몫 | 25.4% | 21.3% | 18.1% | 14.1% | 11.1% | 10.0% | 100% |
위 표는 시험 2025 모델 400그루의 분기 전부를 깊이별·피처별로 센 것이다. 뿌리(깊이 0) 행이 각 트리가 가장 먼저 보는 피처고, 마지막 행은 분기가 손실을 줄인 몫(gain)의 피처별 비율이다. feature_fraction = 0.8 때문에 트리마다 후보 피처가 달라 분기가 한 피처에 몰리지 않는다. 아래 표는 폴드 여섯 개 모델 각각의 첫 트리 뿌리 분기 — 학습창이 길어지며 뿌리 조건이 어떻게 바뀌는지다.
| 시험연도 | 학습 행 | 시험 행 | 재현 | f₁ 뿌리 분기 | 깊이 | 잎 수 |
|---|---|---|---|---|---|---|
| 2020 | 2,652 | 912 | 183 | ret_20 ≤ 0 | 4 | 5~14 |
| 2021 | 3,564 | 975 | 195 | rng_20 ≤ 7.5 | 4 | 5~14 |
| 2022 | 4,539 | 1,050 | 210 | ret_5 ≤ 2.5 | 4 | 5~15 |
| 2023 | 5,589 | 990 | 198 | ret_20 ≤ 1.5 | 4 | 5~15 |
| 2024 | 6,579 | 985 | 197 | rng_20 ≤ 13.5 | 4 | 5~15 |
| 2025 | 7,564 | 960 | 192 | rng_20 ≤ 16.5 | 4 | 5~15 |
| 항목 | 값 | 설명 |
|---|---|---|
| 구현 · 버전 | LightGBM 4.7.0 회귀 | CPU 전용 |
| 예측 대상 | y (틱 정수) | P45 − P34 |
max_depth | 4 | 트리 한 그루의 최대 깊이 |
num_leaves | 15 | 트리 한 그루의 최대 잎 수 |
min_data_in_leaf | 50 | 잎 하나에 필요한 최소 표본 수 |
learning_rate | 0.03 | 트리 하나가 예측을 보정하는 보폭 |
n_estimators | 400 | 이어 붙이는 트리 개수 |
feature_fraction | 0.8 | 트리마다 피처의 80%만 사용 |
| 학습·평가 분할 | 연도 확장창 | 2017~Y−1 로 학습하고 Y 를 시험, Y=2020…2025 |
| 제출 시각 | 15:34 | 다섯 결정시각 중 채점에 사용하는 시각 |
| 난수 시드 | 단일 | 이 설정에는 무작위 요소가 없어 결과가 재현된다 |
위 값은 실행 전에 config.yaml 에 고정했으며
결과를 확인한 뒤 변경하지 않았다. 사전 고정 항목은 protocol.md
에 있다.
비교 대상 설계
| 갈래 | 방향 결정 방식 |
|---|---|
| (a) 무작위 | 동전 던지기(고정 시드) — 하한 확인용 |
| (b) 규칙 | 최근 20분이 상승이면 상승, 하락이면 하락. 학습이 없는 고정 규칙 |
| (c) 보정 없음 | 모델 예측의 부호 그대로: ŷ > 0 → 상승 |
| (d) 보정 | 이 실험의 가설. 관측된 드리프트를 차감한 뒤 부호를 읽는다: ŷ − d > 0 → 상승 |
가설의 근거는 단순한 항등식이다. 정답은
P45 − P_ref = (P45 − P34) − (P_ref − P34) 로 분해되는데, 앞항은
모델이 예측하고 뒷항은 사후에 봉 두 개의 차이로 정확히 관측된다.
따라서 뒷항을 차감하면 제출 시점이 만든 격차가 제거되어야 한다.
결과
| 갈래 | 평가일 | 적중률 | 이항 p(단측) | 누적틱 |
|---|---|---|---|---|
| (a) 무작위 | 1,175 | 51.06% | 0.242 | 3 |
| (b) 규칙 20분 | 947 | 58.61% | 6.6e-08 | 390 |
| (c) 보정 없음 | 1,175 | 56.77% | 2.0e-06 | 315 |
| (d) 보정 | 1,175 | 56.51% | 4.5e-06 | 277 |
| 아래 세 행은 결과를 확인한 뒤 추가한 사후 비교다 — 위 판정을 변경하지 않는다 | ||||
| (c) 를 (b) 와 같은 날만 | 947 | 57.02% | 8.7e-06 | 264 |
| (d) 를 (b) 와 같은 날만 | 947 | 56.49% | 3.6e-05 | 214 |
| 규칙 우선 + 규칙 미제출 228일만 모델 | 1,175 | 58.21% | 9.9e-09 | 453 |
출처 results/20260909_184746_nb/. (b) 의 평가일이
적은 이유는 최근 20분 변화가 정확히 0일 때 방향을 내지 않기 때문이다
(1,175일 중 947일 제출 = 커버리지 80.6%).
가설은 기각됐다. 보정한 (d) 가 보정하지 않은 (c) 에도, 규칙 (b) 에도 미치지 못했다. 평가일 수를 맞춰 재비교해도 결과는 같다(56.49% < 57.02%) — 두 비교 방식 모두에서 보정이 손해다.
보정이 적중률을 낮춘 원인
두 가지 설명이 가능하며, 수치로 판별했다.
- 모델 오차가 차감 대상보다 훨씬 크다 — 이쪽이 원인이다.
예측과 실측의 차이(잔차)의 표준편차가 2.99틱인데, 차감하려는
d는 평균 0.768틱·중앙값 1.0틱이다. 3틱 규모의 변동 위에서 1틱을 차감하는 조작은 신호를 정제하기보다 부호 경계 부근을 뒤집는 잡음으로 작용한다. - 모델이 드리프트를 이미 학습해 이중 차감이 됐다 — 기각. 예측값과 드리프트의 상관계수가 0.034이고, 피처 네 개와 드리프트의 상관도 모두 0.02~0.07이다. 사실상 무관하다.
확률 환산과 확신도 선별
대회는 방향만 제출하지만, 예측의 확신도를 알 수 있다면 활용 여지가 있다.
그래서 예측을 상승 확률로 환산했다 — 잔차가 정규분포를 따른다고 보고
Φ((ŷ − d) / σ̂) 로 변환했다(Φ 는 표준정규
누적분포함수, σ̂ 는 잔차 표준편차의 추정값). σ̂
는 시험 연도를 참조하지 않는다 — 연도 Y 의 값은 Y−1 의 잔차로 산출하며 그
모델은 Y−1 이전만 학습한다.
| 확률 | 로그손실 ↓ | Brier ↓ | AUC ↑ |
|---|---|---|---|
| 보정한 확률 | 0.7305 | 0.2604 | 0.567 |
| 보정하지 않은 확률 | 0.6917 | 0.2490 | 0.567 |
| 무정보(항상 0.5) | 0.6931 | 0.2500 | 0.500 |
로그손실과 Brier 점수는 확률 예측의 정확도를
재는 지표로 작을수록 좋다. AUC 는 확률로 상승일과 하락일을
분리하는 능력이며 0.5 가 무작위 수준이다. 출처
results/20260910_163659_nb/ · 평가 1,175일.
보정한 확률이 무정보 예측보다 나쁘다(0.7305 > 0.6931). 아무 정보 없이 50%를 답하는 편이 이 모델의 확률보다 낫다는 뜻이다.
- 확신도와 정오의 순위상관 (규칙 미제출 228일)0.061 · p=0.363 → 무관
- 확신도 상위 30%의 적중률 (전체 56.51%)59.09%
- 0틱일을 사전에 선별할 수 있는가 (AUC)0.523
- 확신도 하위 10%의 0틱 비율 vs 전체17.0% vs 20.2%
마지막 항목이 특히 명확하다. “예측이 0에 가까운 날이 0틱일과 겹칠 것”이라는 기대와 반대로, 그런 날에 0틱이 오히려 덜 발생한다. 모델은 방향을 모를 뿐 아니라 자신이 언제 확신할 수 있는지도 모른다.