코스닥 종목을 코스피 지수로 재고 있었다 — 벤치마크를 잘못 고르면 생기는 일

벤치마크초과수익측정오류검증방법론

어떤 종목이 5일 동안 3% 올랐다고 합시다. 잘한 걸까요?

같은 기간 시장 전체가 8% 올랐다면 3%는 뒤처진 것입니다. 반대로 시장이 5% 빠졌다면 3% 상승은 대단한 성과입니다. 그래서 수익률을 평가할 때는 시장 수익률을 빼고 봅니다. 이 차이를 초과수익이라고 부릅니다.

초과수익 = 종목 수익률 − 벤치마크 수익률

식은 이렇게 단순합니다. 그런데 저는 이 단순한 식에서 벤치마크를 잘못 골라 14개월치 측정을 통째로 왜곡시켰습니다. 이 글은 그 오류가 어떻게 생겼고, 어떻게 발견했고, 교정하면서 무엇이 드러났는지에 대한 기록입니다.

유니버스는 섞여 있는데 자는 하나였다

제가 관측하는 종목 목록은 이렇게 구성돼 있습니다.

시장 종목 수
코스피 201
코스닥 150

코스닥이 43%입니다. 처음부터 두 시장이 섞여 있었습니다.

그런데 초과수익을 계산하는 코드에는 벤치마크가 이렇게 박혀 있었습니다.

BENCHMARK_TICKER = '069500'   // KODEX 200 — 코스피200 추종 ETF

하드코딩된 한 줄. 코스닥 종목의 수익률에서도 코스피200 지수의 수익률을 뺐다는 뜻입니다.

더 나빴던 건 애초에 대안이 없었다는 점입니다. 가격 데이터베이스에 코스닥150 ETF(229200)가 아예 존재하지 않았습니다. 코스피 지수만 수집하고 있었으니, 시장별로 나누고 싶어도 나눌 재료가 없었습니다.

얼마나 잘못됐는가

이런 오류의 크기는 두 지수가 얼마나 다르게 움직였는지에 달려 있습니다. 두 시장이 나란히 갔다면 벤치마크를 잘못 골라도 티가 안 납니다.

문제의 기간에는 나란히 가지 않았습니다.

지수 ETF 2026-03-24 2026-07-06 수익률
코스피200 (069500) 83,505원 130,125원 +55.8%
코스닥150 (229200) 19,410원 14,730원 −24.1%

같은 3개월 반 동안 한쪽은 56% 오르고 다른 쪽은 24% 빠졌습니다. 격차가 79.9%p입니다.

이 기간 코스피는 소수 대형주가 끄는 급등장이었고 코스닥은 그 반대였습니다. 하필 두 시장이 역사적으로 크게 갈라진 구간에서, 저는 코스닥 종목을 코스피 자로 재고 있었습니다.

결과를 예측할 수 있습니다. 코스닥 종목은 무슨 짓을 해도 초과수익이 나쁘게 나옵니다. 폭등하는 지수를 빼고 있으니까요.

증상 — “코스닥 종목이 유독 나쁘다”

발견은 결과를 보다가 이상해서였습니다. 시장별로 이벤트 평균 초과수익을 나눠보니 이랬습니다.

시장 5일 평균 초과수익
코스피 −2.26%
코스닥 −6.20%

코스닥이 코스피보다 4%p 가까이 나빴습니다.

여기서 틀린 결론으로 갈 수 있는 갈림길이 있었습니다. 이 숫자를 그대로 믿으면 “코스닥 종목은 뉴스 반응이 나쁘니 유니버스에서 빼자”는 결론이 자연스럽습니다. 데이터도 있고, 통계도 있고, 그럴듯한 설명(코스닥은 유동성이 낮아 정보 반영이 비효율적이다)도 붙습니다.

그리고 그 결론은 완전히 틀렸을 겁니다. 차이의 상당 부분은 종목의 성질이 아니라 자가 틀렸다는 사실에서 나왔으니까요.

측정 도구의 결함은 이렇게 나타납니다. 오류 메시지도, 크래시도 없습니다. 그냥 그럴듯하게 틀린 숫자가 나오고, 그 숫자에 붙일 설명은 항상 만들어낼 수 있습니다.

교정 — 그리고 그것이 통제된 실험이 된 이유

고치는 일 자체는 세 단계였습니다.

  1. 코스닥150 ETF 가격을 소급 수집 — 코스피200 ETF와 같은 기간, 같은 날짜로 채웠습니다. 채운 뒤 두 벤치마크의 데이터 행 수가 정확히 일치하는지 확인했습니다(현재도 일치합니다). 겹치는 구간에서는 서로 다른 두 출처의 값이 같은지 교차검증했습니다.
  2. 종목의 시장에 따라 벤치마크를 분기 — 코스닥 종목이면 코스닥150, 그 외는 코스피200.
  3. 과거 전건 재계산.

재계산 결과에서 가장 중요했던 건 교정된 값이 아니라 교정되지 않은 값이었습니다.

코스피 종목의 초과수익은 단 한 행도 바뀌지 않았습니다.

당연합니다. 코스피 종목의 벤치마크는 원래도 코스피200이었으니까요. 하지만 이 “당연함”이 검증에서는 결정적입니다.

이건 통제된 실험과 같은 구조입니다. 처치군(코스닥)만 움직이고 대조군(코스피)은 완전히 정지했습니다. 만약 코스피 쪽도 조금이라도 움직였다면 재계산 코드에 의도치 않은 부작용이 있다는 뜻이고, 그러면 교정 결과 전체를 믿을 수 없습니다.

교정 후 코스닥 수치는 이렇게 이동했습니다.

지표 교정 전 교정 후
5일 평균 초과수익 −4.95% −0.92%
20일 평균 초과수익 −19.78% −2.07%

20일 기준으로 17.7%p가 순전히 측정 오류였습니다. 기간이 길수록 두 지수의 격차가 누적되므로 20일 왜곡이 5일보다 훨씬 큰 것도 앞뒤가 맞습니다.

다 해결됐는가 — 아니다

정직하게 쓰면, 교정 후에도 두 시장의 차이가 0이 되지는 않았습니다. 갭은 2.98%p에서 1.05%p로 줄었고, 부호가 뒤집혔습니다. 이제는 코스피 쪽이 근소하게 낮습니다.

남은 갭에 대한 제 해석은 이렇습니다. 지수는 시가총액 가중이라 소수의 대형주가 지수를 끕니다. 반면 제가 재는 건 개별 종목 하나하나입니다. 지수가 몇몇 리더 덕에 오르는 국면에서는 중간쯤 되는 종목은 지수를 못 따라갑니다. 지수를 이기는 종목의 비율이 절반보다 훨씬 적은 상태죠.

이건 벤치마크를 바꿔서 해결되는 문제가 아니라, 시총가중 지수를 개별 종목의 기준선으로 쓰는 한 남는 구조적 편향입니다. 그래서 저는 초과수익의 절대값을 그대로 믿지 않고, 같은 기간 미분류 이벤트의 평균을 한 번 더 빼서 상대 비교를 합니다. 편향이 모든 이벤트에 공통으로 걸린다면 차감으로 상쇄되니까요.

중요한 건 이게 해결이 아니라 완화라는 점입니다. 그리고 그 사실을 알고 쓰는 것과 모르고 쓰는 것은 다릅니다.

부수적으로 밟은 함정 두 개

교정 과정에서 예상 못 한 함정이 두 개 있었습니다. 둘 다 같은 부류입니다 — “당연히 그럴 것”이라고 가정한 게 아니었던 경우.

① 데이터 출처는 종목의 시장을 모른다

시장별로 벤치마크를 나누려면 종목이 코스피인지 코스닥인지 알아야 합니다. 저는 가격 데이터 API의 종목 코드 접미사(.KS / .KQ)로 판별하면 될 거라 생각했습니다.

안 됩니다. 그 접미사는 데이터 제공처의 내부 규칙일 뿐이라 실제 상장 시장과 일치한다는 보장이 없습니다. 결국 별도의 국내 출처에서 시장 라벨을 따로 받아와야 했습니다.

② 벤치마크를 종목 목록에 등록하면 안 된다

가격을 수집하려면 수집 대상에 넣어야 합니다. 가장 쉬운 방법은 종목 마스터 테이블에 코스닥150 ETF를 추가하는 것이었습니다.

그러면 그 ETF가 포트폴리오 매수 후보가 됩니다. 리밸런싱 로직이 “활성 종목 전체”를 후보로 삼기 때문입니다. 실제로 코스피200 ETF가 같은 이유로 이미 포트폴리오에 편입돼 있었다는 걸 이때 발견했습니다.

그래서 벤치마크는 종목 마스터에 등록하지 않고 수집 목록에만 별도로 추가했습니다. “측정 도구”와 “측정 대상”을 같은 테이블에 넣으면 도구가 대상이 됩니다.

정리

마지막으로 하나 더. 이 오류는 몇 달간 아무 문제 없이 작동하는 것처럼 보였습니다. 코드는 정상이었고, 숫자는 나왔고, 대시보드도 잘 그려졌습니다.

틀린 자로 재도 눈금은 읽힙니다. 재는 대상이 아니라 자를 의심해야 하는 순간이 언제인지가, 결국 측정의 핵심입니다.


교정 시점(2026년 7월)의 재계산 수치는 당시 기록을 인용했습니다. 벤치마크 가격·유니버스 구성 등 현재 확인 가능한 수치는 발행 전 원본 데이터베이스와 자동 대조했습니다.