2026년 9월 1일 · 기업행위

분할 조정 데이터 해부: NVDA의 10대1 분할이 모든 행에 미치는 영향

분할 조정 데이터 해부: NVDA의 10대1 분할이 모든 행에 미치는 영향

주식 일봉 파일의 한 행을 보겠습니다. NVDA, 2024년 6월 7일 금요일, 10대1 분할이 적용되기 전 마지막 거래일입니다.

열 값
날짜 2024-06-07
종가 1208.88
거래량 42,800,000 (반올림)
분할_계수 1.0
배당금 0.00
조정_종가 120.8781

일부러 이 보기에서 OHLC 열은 뺐습니다. 글 후반부에 다시 다루는데, 그 열들이 조용히 문제를 일으킵니다.

이 행의 핵심은 2번째 열과 6번째 열 사이의 차이에 있습니다. 6월 7일 거래 테이프에 찍힌 가격은 1208.88이었습니다. 그 가격이 가리키던 주식 단위는 더 이상 존재하지 않으므로, 이제 누구도 그 가격으로 거래할 수 없습니다. 120.8781은 재구성한 값이며, 단순히 1208.88을 10으로 나눈 값이 아닙니다. 열별로 살펴보겠습니다.

10:1이전의 모든 행에 적용된 나눗수
0.99991789하루 뒤 적용된 배당 계수
$90왕복 거래당 허구의 수수료
5.6pp제수 때문에 인위적으로 생긴 연간 수익률 하락폭

날짜: 2024-06-07, 그리고 더 중요한 두 날짜

분할은 실적 발표와 함께 2024년 5월 22일 공지됐습니다. 기준일은 6월 6일이었습니다. 분할 조정 기준 거래는 6월 10일 월요일부터 시작됐습니다. 중요한 날짜는 3개이며, 데이터 공급업체의 split_factor 열은 이 날짜 중 정확히 하나에 맞춰집니다. 대개 분할 조정이 처음 적용된 거래일입니다. 여기서 하루 어긋나는 것은 제가 가장 흔히 보는 기업행위 관련 버그이며, 전체 데이터에서는 눈에 띄지 않습니다. 하루 만에 주식 곡선이 90% 급락하거나 900% 급등하지만, 2,000일을 대상으로 계산한 Sharpe에는 거의 반영되지 않는 반면 최대 낙폭이나 손절 규칙에는 큰 영향을 줍니다.

배당에도 날짜 문제가 따로 있고, 2024년에 모두가 모르는 사이 기준이 바뀌었습니다. 분할 후 NVDA의 분기 배당금 $0.01의 기준일은 6월 11일이었습니다. 미국 주식 결제 주기가 2024년 5월 28일 T+1로 바뀌면서 배당락일과 기준일이 이제 같은 날이 됐습니다. 수십 년간 맞았던 방식대로 '기준일에서 영업일 하루 전'을 배당락일로 계산하는 로더는 2024년 6월부터 배당 조정을 하루 일찍 조용히 적용하기 시작했습니다. 오류는 발생하지 않습니다. 계수가 그저 잘못된 행에 들어갑니다.

기업행위 코드에서 문제가 생겨도 예외가 발생하는 경우는 없습니다. 하루 어긋났지만 완전히 그럴듯해 보이는 숫자가 나올 뿐입니다.

종가: 1208.88 — 파일에 없는 가격

이 값은 원시 체결 가격이며, 대부분의 리서치 파이프라인에서는 아무도 읽지 않는 열에만 남아 있습니다. 시그널은 adj_close을 기준으로 계산됩니다. 달러 기준 주당 가격 수준을 참조하는 규칙도 이제 어떤 시장 참여자도 본 적 없는 숫자를 기준으로 삼습니다.

2024년 봄 NVDA가 $1,000에 다가간 과정은 실제 주문 흐름이 뒷받침된 현실이었습니다. 어림수 가격대에 주문이 몰리고, 옵션 행사가가 950과 1000에 집중됐으며, 가격이 근접할 때마다 뉴스 위험이 있었습니다. 조정 데이터에서는 이 모든 움직임이 $100에서 벌어진 것으로 나타납니다. 심리적 가격대 반응이나 어림수 근처의 갭 메우기 로직, 행사가 근접도 특성을 테스트한다면, 아직 발생하지도 않은 이벤트로 재조정된 가격 시계열을 대상으로 시험하는 셈입니다.

유니버스 필터도 마찬가지입니다. '주가가 $5 미만인 종목 제외'는 넓은 상대 스프레드, 증거금 적격성 규정, 호가 단위 체계처럼 실제 시장 구조상의 문제들을 대변하는 유효한 기준입니다. 조정된 과거 데이터에 적용하면 주가가 $30이었지만 나중에 역분할한 기간의 기업까지 제외합니다. '주가가 $500 초과'를 적용하면 2024년 6월 이전 매년 NVDA가 조용히 빠집니다. 가격 필터는 미조정 체결 가격에 적용해야 합니다. 끝입니다.

분할_계수: 1.0 — 그리고 다음 행의 0.1

계수는 오늘부터 과거 방향으로 거슬러 올라가며 누적 곱으로 계산됩니다. 2024년 6월 10일 이전의 모든 행에는 이번 분할의 0.1이 적용되고, 2021년 4대1 분할의 0.25와 그 이전의 계수도 곱해집니다. NVDA의 2021년 이전 기록에는 0.025가 적용되므로, 2019년에 $200에 거래된 봉이 $5.00으로 표시됩니다.

기억해 둘 결과는 2가지입니다. 첫째, 조정된 과거 데이터는 새 기업행위가 발생할 때마다 바뀝니다. 2024년 5월에 실행한 백테스트와 오늘 실행한 백테스트는 같은 날짜에 같은 코드를 돌려도 다른 결과를 냅니다. 심볼과 날짜만으로 특성을 캐시하고 데이터 버전을 기록하지 않았다면, 이제 서로 다른 가격 규모가 뒤섞인 캐시가 생긴 셈입니다. 바로 이런 문제 때문에 조정 기준 시점을 특성 키에 버전으로 기록합니다. 이 점을 깨닫기까지 혼란스러운 오후를 한 번 보내야 했습니다.

둘째, 0.025로 조정하면 $0.01 호가 단위로 거래되던 주식의 가격이 이제 $0.00025씩 움직입니다. 호가 반올림 로직, '신고가인가' 비교, 부동소수점 동등성 확인이 모두 시장의 실제 가격 해상도보다 훨씬 작은 단위로 작동합니다.

배당금: 0.01 — 그보다 앞선 모든 가격의 눈금을 흐트러뜨리는 숫자

1센트입니다. 잡음처럼 보이지만 adj_close에 120.888이 아닌 120.8781이 표시되는 이유입니다.

6월 10일 종가는 121.79였습니다. 배당락 계수는 (121.79 − 0.01) / 121.79 = 0.99991789입니다. 이 계수는 6월 11일 이전의 모든 가격에 곱해지므로, 분할 조정된 120.888은 120.878074가 됩니다. 차이는 작지만 영구적으로 남으며, NVDA의 과거를 거슬러 올라가는 60여 개의 배당락일마다 다시 적용됩니다. 중요한 것은 누적 효과입니다. 2015년 가격을 볼 때쯤이면 비정수에 가까운 계수가 수십 번 곱해진 가격을 보는 셈입니다. 조정된 과거 가격 중 페니 단위 눈금에 맞는 값은 하나도 없습니다.

따라서 어림수와 비교하는 모든 == 검사는 틀리고, '지정가에 닿았는가'를 확인하려면 허용 오차가 필요합니다. OHLC를 4자리 소수로 단순 반올림하면 저가 ≤ 시가 ≤ 고가라는 불변 조건도 깨집니다. 또한 adj_close는 총수익률 시계열인 반면 close는 가격수익률 시계열이므로, 한쪽에서 수익률을 계산하고 다른 쪽에서 낙폭을 그리면 서로 다른 사건 정의를 섞게 됩니다.

거래량: 42,800,000 — 일관성 없이 적용되는 나눗수

분할 후 거래일과 비교하려면 주식 거래량에 10을 곱해야 합니다. 어떤 공급업체는 그렇게 조정합니다. 어떤 곳은 조정하지 않습니다. OHLC는 조정하면서 거래량은 원시 값으로 두는 곳도 있는데, 가격과 거래량을 곱하기 전까지 파일이 내부적으로 일관된 것처럼 보이기 때문에 이 방식이 가장 나쁩니다.

가장 확실한 방법은 주식 거래량을 특성으로 쓰지 않고 달러 거래량을 사용하는 것입니다. 달러 거래량은 구조상 분할에 영향을 받지 않습니다. 20일 평균 달러 거래량 유동성 필터에는 조정 로직이 전혀 필요하지 않고, 기업행위 때문에 깨질 수도 없습니다. 정확한 조정 코드는 계속 정확하게 유지해야 하지만, 특성의 불변성은 그런 부담을 없애 줍니다.

데이터 공급업체 파일의 3가지 형태, 3가지 실패 방식.

제공되는 데이터 문제점
조정 종가만 있고 OHLC는 원시 값 갭 및 장중 로직이 서로 다른 가격 규모를 넘나들며 계산됨
조정 OHLC, 원시 거래량 달러 거래량이 분할 비율만큼 어긋나 ADV 필터가 잘못 작동함
원시 OHLCV와 계수 열 제대로 적용하면 문제 없음. 잘못된 행에 적용하면 모든 것이 문제

없는 열: 조정 시가, 조정 고가, 조정 저가

이제 OHLC를 다시 넣어 보겠습니다. 데이터 피드가 종가만 조정하고 전략이 익일 갭을 open / prev_adj_close − 1로 계산한다면, 2024년 6월 10일에는 120.37 / 120.8781 − 1을 계산합니다. 대략 −0.4%로 적절한 값입니다. 같은 코드를 2024년 6월 7일까지 거슬러 실행하면, 원시 파일의 시가(약 1207)를 과거 분할의 0.025로 조정된 종가와 비교해 수천 퍼센트에 달하는 갭을 계산합니다.

원시 열과 조정 열을 섞어 쓰면 서로 다른 좌표계의 값끼리 계산하게 됩니다. 이제 혼합 조정 상태의 데이터 참조는 연구자가 기억해야 할 사항이 아니라 로더 단계에서 검증하도록 했습니다. 연구자는 기억하지 못합니다. 저도 마찬가지입니다.

어떤 열에도 없는 정보: 실제로 매수했을 주식 수

백테스트 비용 모델에서 실제 비용이 발생하는 지점이며, 제가 주식 분할에 대해 글을 쓰는 이유이기도 합니다.

미국 주식 수수료는 주당 부과되는 경우가 많습니다. 흔한 개인 투자자용 고정 요금제처럼 주당 $0.005, 주문당 최소 $1.00이라고 해보겠습니다. 분할 1년 전, NVDA 원시 가격이 $400에 가깝고 조정 가격이 $40으로 표시될 때 $400,000 규모의 포지션을 백테스트해 봅시다.

주식 수 수수료
실제 상황 (원시 가격 $400) 1,000 $5.00
백테스트에 표시되는 값 (조정 가격 $40) 10,000 $50.00

같은 익스포저, 같은 거래인데 모델 비용은 10배입니다. 한쪽 거래마다 허구의 비용이 $45, 왕복 거래로는 $90입니다. 매일 거래하는 전략이라면 실제로 발생하지 않은 비용이 연간 약 $22,000 쌓입니다. $400k 포트폴리오 기준으로 연간 수익률이 5.6%포인트나 줄어드는데, 전부 나눗수로 만들어진 비용입니다. 이 사례에서는 실제보다 성과가 나빠 보이는 정도라 감당할 수 있습니다.

역분할은 반대 방향으로 작용하며, 그 방향이 위험합니다. 1대10 역분할이면 조정된 과거 데이터의 가격은 10배 높고 주식 수는 10분의 1로 표시됩니다. 비용 모델은 주당 수수료를 조용히 10분의 1로 계산합니다. 역분할이 흔한 종목군은 소형주, $5 미만 주식, 스프레드가 넓은 종목들입니다. 이곳에서는 주당 수수료가 비용 항목 중 가장 큰 비중을 차지합니다. 백테스트는 불이익을 줘야 할 종목의 성과를 오히려 부풀립니다.

따라서 해결책은 단순하고 구조적입니다. 포지션 규모는 달러 기준으로 정하고, 해당 날짜의 미조정 가격으로 주식 수를 환산한 뒤 그 수량에 주당 수수료를 부과합니다. 원시 가격 열은 감사용 기록이 아니라 체결 엔진의 실시간 입력으로 로더에 계속 남겨 둡니다.

  1. 시그널과 수익률: 조정 시계열.
  2. 주식 수, 주당 수수료, 호가 반올림, 가격 수준 필터: 미조정 시계열.
  3. 유동성과 거래 가능 규모: 조정이 필요 없는 달러 거래량.

열 6개, 행 1개, 3주 전에 공지돼 누구도 놀라지 않았던 평범한 기업행위 하나. 시장은 오전 중에 처리했습니다. 이를 리서치 파이프라인에서 충실하게 재구성하는 일은 훨씬 어렵습니다. 파이프라인이 제대로 처리하지 못했다는 신호는 오류 메시지인 경우가 거의 없습니다.

기업행위분할 조정미국 주식데이터 엔지니어링백테스팅
← 전체 글