코스피 오버나이트 수익률 — 장중은 12년간 -36%
KODEX 200(069500)의 2015-01-05~2026-10-30, 2,901거래일을 나눠 보면 종가→다음날 시가(오버나이트)가 누적 +625.2%, 시가→종가(장중)가 -36.2%, 계속 보유가 +362.3%입니다. 12년 모두 오버나이트가 장중을 이겼습니다. 그러나 매일 사고팔면 왕복 비용 0.03%에서 연복리 18.78%가 10.14%로 줄어 보유(14.23%)보다 낮아지고, 0.0683%에서 0이 됩니다. 이 숫자는 매매 신호가 아니라 내 백테스트와 당일청산 봇을 점검하는 잣대로 쓰는 편이 맞습니다. 과거 수치이며 미래를 보장하지 않습니다.
"주가는 밤에 오른다"는 말을 들어 본 분이 많을 겁니다. 코스피에서도 그런지, 그렇다면 봇으로 그 구간만 들고 있으면 되는지 FinanceDataReader와 pandas로 확인했습니다. 앞의 질문은 "그렇다"이고 뒤의 질문은 "비용을 넣으면 대부분 아니다"입니다.
목차
- 하루를 두 구간으로 나누는 코드
- 결과 — 12년, 12승 0패
- 코스피 지수 시가로 계산하면 안 되는 이유
- 왕복 비용별 — 0.07%에서 끝난다
- 수익은 며칠에 몰려 있다
- 이 숫자를 어디에 쓰나
- 봇으로 옮기면 — 키움·KIS·토스 주문값
- 이 실험의 한계
1. 하루를 두 구간으로 나누는 코드
일봉의 Open과 Close만 있으면 됩니다. 어제 종가에서 오늘 시가까지가 밤, 오늘 시가에서 오늘 종가까지가 낮입니다. 두 구간을 곱하면 보유 수익률과 정확히 같습니다.
import FinanceDataReader as fdr
df = fdr.DataReader("069500", "2015-01-01", "2026-10-30")
night = df["Open"] / df["Close"].shift(1) - 1 # 어제 종가 → 오늘 시가
day = df["Close"] / df["Open"] - 1 # 오늘 시가 → 오늘 종가
hold = df["Close"] / df["Close"].shift(1) - 1 # (1+night)*(1+day)-1 과 같다
전체 코드는 overnight_intraday_backtest.py입니다. 빈 폴더에서 처음 받아 실행한 결과와 캐시로 다시 실행한 결과가 글자까지 같은지 cmp로 확인했습니다. 글과 같은 숫자가 나오도록 ASOF = "2026-10-30"으로 기준일을 고정했고, 최신 데이터를 보려면 ASOF = None으로 바꾸면 됩니다.
2. 결과 — 12년, 12승 0패
=== KODEX 200 (069500) 2015-01-05 ~ 2026-10-30 2901거래일
보유 누적 362.3% CAGR 14.23% MDD -41.9% 샤프 0.66 상승일 54.3%
오버나이트 누적 625.2% CAGR 18.78% MDD -22.0% 샤프 1.14 상승일 55.8%
장중 누적 -36.2% CAGR -3.83% MDD -52.9% 샤프 -0.14 상승일 49.7%
오버나이트가 장중을 이긴 해: 12/12 (진 해: [])
| 구간 | 보유 | 오버나이트 | 장중 |
|---|---|---|---|
| 2015~2019 | +32.0% | +55.3% | -15.0% |
| 2020~2022 | +5.9% | +45.8% | -27.3% |
| 2023~2025 | +119.8% | +89.2% | +16.2% |
| 2026 (10월까지) | +50.4% | +69.3% | -11.1% |
다른 운용사 상품도 방향이 같습니다. TIGER 200(102110)은 오버나이트 CAGR 20.35%, 장중 -4.96%, 12승 0패입니다. 같은 지수를 추종하니 독립된 증거는 아니고, 한 상품의 데이터 오류일 가능성을 줄여 주는 정도입니다.
미국 SPY는 모양이 다릅니다. 같은 기간 오버나이트 6.96%, 장중 4.40%로 둘 다 플러스이고 오버나이트 승은 12년 중 7년입니다(SPY는 분배금 미반영 가격으로 봐야 합니다). "낮에 잃는다"는 코스피 200 ETF에서 나온 관찰이지 주식시장 전체의 법칙이 아닙니다. 왜 이런 차이가 나는지 이 실험으로는 알 수 없습니다. 학술 쪽에는 한국 주식시장 1998~2018년 오버나이트 수익률 연구나 Lou·Polk·Skouras(2019)처럼 주간과 야간의 투자자 구성 차이로 설명하는 논의가 있지만, 이 글이 그 설명을 검증한 것은 아닙니다.
3. 코스피 지수 시가로 계산하면 안 되는 이유
처음 시도하면 대부분 KS11로 계산합니다. 그러면 오버나이트 CAGR이 24.76%로 나옵니다. KODEX 200보다 6%포인트 높습니다.
=== 지수 시가 점검 (KS11 vs KODEX 200)
오버나이트 CAGR 지수 24.76% ETF 18.78% 상관 0.930
2026-03-05 지수 +3.09% ETF +10.69%
2026-06-08 지수 -1.38% ETF -9.17%
2026-07-31 지수 +1.15% ETF +11.72%
갭이 큰 날일수록 지수 시가와 ETF 시가가 크게 갈립니다. 2026-07-31에는 ETF가 +11.72%로 시작했는데 지수 시가는 +1.15%입니다. 지수 시가는 그 값에 사고팔 수 있는 호가가 아니므로 체결 가정으로 쓰면 안 됩니다. 어떤 방식으로 산출돼 이런 차이가 나는지는 데이터 제공처 설명을 확인하지 못했습니다. 실제로 살 수 있는 상품의 시가로 계산하십시오.
4. 왕복 비용별 — 0.07%에서 끝난다
오버나이트 전략은 1년에 약 245번 왕복합니다. 일평균 수익이 작아서 비용이 그대로 결과를 바꿉니다. 아래 값은 매일 왕복마다 비용을 뺀 것입니다. 1bp는 0.01%입니다.
| 왕복 비용 | 오버나이트 CAGR | 오버나이트 MDD | 장중 CAGR |
|---|---|---|---|
| 0bp | 18.78% | -22.0% | -3.83% |
| 3bp (수수료 0.015%×2 가정) | 10.14% | -25.4% | -10.84% |
| 5bp | 4.72% | -35.8% | -15.22% |
| 6.83bp (손익분기) | 0% | ||
| 10bp | -7.68% | -78.3% | -25.27% |
| 20bp | -28.26% | -98.3% | -41.94% |
비교 대상인 보유는 CAGR 14.23%, MDD -41.9%입니다. 수수료 0.015%를 양쪽에 내는 3bp만 넣어도 수익률은 보유보다 낮아지고 낙폭(-25.4%)만 작습니다. 5bp면 CAGR 4.72%로 보유의 3분의 1 수준이 되고 낙폭 차이도 -35.8% 대 -41.9%로 좁아집니다.
수수료는 계좌마다 다르니 본인 고지값을 넣으십시오. 국내 주식형 ETF 매도에는 증권거래세가 붙지 않는 것으로 계산했지만 상품별 과세는 공식 자료로 확인하십시오. 개별 주식이라면 매도마다 거래세가 붙어 위 표의 10~20bp 줄보다 나빠질 수 있습니다. 구성 요소는 백테스트 수수료·세금 반영에 정리했습니다.
5. 수익은 며칠에 몰려 있다
2,901거래일 중 오버나이트 수익이 가장 큰 날을 빼 봤습니다. 비용 0 기준입니다.
| 조건 | 오버나이트 CAGR | 누적 |
|---|---|---|
| 전체 | 18.78% | +625.2% |
| 상위 10일 제외 | 12.08% | +270.2% |
| 상위 30일 제외 (전체의 약 1%) | 4.75% | +69.7% |
| 2025년까지만 | 14.55% | +328.4% |
좋은 날만 뺀 값이라 한쪽으로 치우친 계산입니다. 그래도 수익이 고르게 쌓인 게 아니라는 점은 분명합니다. 시가 갭이 ±2%를 넘은 날은 143일이고 그중 89일이 2026년입니다. 최악의 밤은 2026-06-08의 -9.17%였습니다. 밤에만 들고 있어도 손절을 걸 수 없는 시간에 이만큼 맞을 수 있습니다. 2026년의 극단적인 변동을 빼도(2025년까지) 오버나이트 14.55%, 보유 11.05%, 장중 -3.05%로 순서는 같습니다.
2026년 값은 한 번 의심했습니다. 2026-07-31 KODEX 200 종가가 전일 대비 +24.2%로 이례적이어서 FinanceDataReader 값과 네이버 일봉 원본(siseJson)을 대조했고 같았습니다. 거래소 원천 자료까지 대조하지는 않았으니 중요한 판단에 쓰려면 직접 확인하십시오.
6. 이 숫자를 어디에 쓰나
매일 왕복을 권하려는 글이 아닙니다. 쓸모는 세 가지입니다.
① 당일청산 봇의 비교 기준을 바꾼다
장 마감 전에 전부 청산하는 봇은 위 표의 '장중' 구간에서만 돈을 법니다. 이 ETF 기준으로 그 구간은 12년간 -36.2%였습니다. 그러니 당일청산 전략의 백테스트를 코스피 보유 수익률과 나란히 놓으면 비교가 어긋납니다. 비교 기준을 장중 수익률로 놓고 그보다 얼마나 나았는지를 보아야 합니다. 개별 종목이나 다른 기간에서는 값이 다릅니다.
② 내 백테스트의 체결 가정을 점검한다
"오늘 종가로 신호를 계산해 오늘 종가에 산다"는 코드는 밤 수익을 그대로 가져갑니다. 신호를 종가 전에 알 수 없는데도 말입니다. 진입을 다음날 시가로 미루면 그 밤을 놓칩니다. 같은 전략이 3.209배에서 0.609배로 떨어진 사례를 미래참조 편향 탐지에 적어 뒀습니다. 전략 수익을 night와 day로 나눠 보면 어느 쪽에서 나온 수익인지 바로 드러납니다. 밤에서 대부분이 나왔는데 내 봇이 다음날 시가에 들어간다면 그 수익은 실제로 받을 수 없습니다. 다른 괴리 원인은 백테스트와 실거래의 차이를 보십시오.
③ 밤을 들고 갈지 규칙으로 정한다
오버나이트 포지션은 보상과 함께 대응할 수 없는 갭을 가져옵니다. -9.17% 같은 밤을 감수할지, 비중을 줄일지, 청산할지를 의뢰서나 전략 규칙에 먼저 적어 두십시오. 봇에게는 "알아서"가 없습니다.
7. 봇으로 옮기면 — 키움·KIS·토스 주문값
이 전략을 실제로 돌리려면 시가·종가 단일가에 맞춰 주문을 넣어야 합니다. KRX 종가 단일가는 15:20~15:30이고, 시가 단일가는 09:00 체결입니다. 증권사 API별 값은 다음과 같습니다. 2026-11-06에 공식 자료로 확인한 값이며, 이 글에서 실제 주문을 내 체결을 확인하지는 않았습니다. 반드시 모의 또는 소액으로 먼저 확인하십시오.
| 증권사 | TR·경로 | 쓸 수 있는 값 |
|---|---|---|
| 키움 REST | kt10000 매수 · kt10001 매도/api/dostk/ordr | trde_tp 3 시장가 · 5 조건부지정가, dmst_stex_tp KRX |
| KIS | TTTC0012U 매수 · TTTC0011U 매도 | ORD_DVSN 01 시장가 · 02 조건부지정가, EXCG_ID_DVSN_CD KRX |
| 토스증권 | POST /api/v1/orders | timeInForce OPG가 국내 시가단일가. 스펙 v1.2.28의 CLS는 미국 주식 + LIMIT만이라 국내 종가용 값이 아님 |
키움 쪽은 필드 이름에 주의하십시오. 가격 필드가 ord_uprc가 아니라 ord_uv입니다. 시장가면 비웁니다. 자세한 내용은 kt10000과 trde_tp에 있고, KIS는 TTTC0012U 신구 TR 비교, 토스는 파이썬 첫 주문에 있습니다.
# 키움 kt10000: 15:20 이후 종가 단일가 시간에 낼 시장가 매수 본문
{"dmst_stex_tp": "KRX", "stk_cd": "069500", "ord_qty": "10", "ord_uv": "", "trde_tp": "3", "cond_uv": ""}
# 토스 POST /api/v1/orders: 장전에 접수할 국내 시가단일가 매도
{"symbol": "069500", "side": "SELL", "orderType": "MARKET", "timeInForce": "OPG",
"quantity": "10", "clientOrderId": "night-exit-20261106"}
토스 스펙은 OPG를 세션 시간(장전 사전접수) 밖에 내면 거절될 수 있다고 적고 있습니다. 시각을 코드에 고정하면 깨지는 날도 있습니다. 2026-11-19 수능일처럼 개장이 늦춰지는 날이 있어서, 키움이라면 0s 장운영구분의 2(장마감 알림)와 3(장시작)을 함께 봅니다. 사례는 수능일 10시 개장에 있습니다. dmst_stex_tp를 KRX로 고정하는 이유는 KRX·NXT 주문 라우팅에 있습니다.
8. 이 실험의 한계
- 가격이 원본 체결가가 아닙니다. KODEX 200은 5원 단위로 거래되는데 데이터 종가의 80.8%가 5원 배수가 아닙니다. 분배금 등을 반영한 수정 가격으로 보이지만 제공처 설명으로 확인하지 못했습니다.
- 체결 시장을 단정하지 못합니다. 시가·종가가 KRX 단일가 값이라는 전제로 해석했으나 데이터에 명시돼 있지 않습니다.
- 체결량 영향이 없습니다. 단일가 시장가 주문이 표시 가격에 전량 체결된다고 가정했습니다. 슬리피지는 표의 비용 칸으로만 반영했습니다.
- 세금과 복리 가정. 분배금 과세와 매매차익 과세를 뺐고, 매일 전액 재투자했습니다. 현금 잔고 이자와 호가 단위 수량 절사도 없습니다.
- 기간. ETF 데이터가 2014년 8월부터 받아져 시작을 2015년으로 잘랐고, 12년 표본은 2026년의 큰 변동에 영향을 받습니다. 시작일이 결과를 어떻게 바꾸는지는 시작일 민감도를 보십시오.
- 거래 대상. KODEX 200과 TIGER 200은 방법을 보여 주는 예시이며 특정 상품을 사라는 뜻이 아닙니다. 이 전략이 앞으로도 같은 결과를 낸다는 근거는 없습니다.
알고랩은 프로그램 제작 도구를 제공하며 투자자문업·투자일임업을 영위하지 않습니다. 이 글의 수치는 과거 데이터에 위 가정을 적용한 결과이고 수익을 보장하지 않습니다. 투자 판단과 책임은 본인에게 있습니다.
자주 묻는 질문
오버나이트 수익률은 어떻게 계산하나요?
당일 시가를 전일 종가로 나눈 뒤 1을 뺍니다. 장중 수익률은 당일 종가를 당일 시가로 나눈 뒤 1을 뺍니다. 두 값을 복리로 곱하면 보유 수익률과 같습니다. 지수의 시가보다 실제로 살 수 있는 ETF의 시가로 계산하십시오.
그럼 밤에만 보유하는 봇을 만들면 되나요?
비용이 관건입니다. 이 실측에서 왕복 비용 0.03%면 연복리가 10.14%로 보유 14.23%보다 낮았고 0.0683%면 0이 됐습니다. 낙폭은 줄 수 있지만 수익 면에서 보유보다 낫다고 보기 어렵고, 과거 결과가 반복된다는 보장도 없습니다.
미국 주식도 같은가요?
모양이 다릅니다. 같은 기간 SPY는 오버나이트 CAGR 6.96%, 장중 4.40%로 둘 다 플러스였고 오버나이트 승은 12년 중 7년이었습니다. 다만 SPY 값은 분배금을 뺀 가격 기준입니다.
당일청산 봇에 어떤 의미가 있나요?
당일청산 봇은 밤 구간에 참여하지 않으므로 코스피 보유 수익률과 바로 비교하면 어긋납니다. 비교 기준을 같은 상품의 장중 수익률로 놓고 얼마나 나았는지를 보십시오. 이 글의 KODEX 200 장중 누적은 -36.2%였습니다.
내 전략을 밤과 낮으로 나눠 보고 싶다면
보유한 규칙을 백테스트로 분해하고, 종가·시가 단일가 주문까지 키움·KIS 봇으로 맞춤 제작합니다. 24시간 빠른 답변 가능합니다.
무료 상담 시작하기