국내 대형주 · 물렸을 때 · 코스피200 ETF · 실측 재현 페이지
2007년 12월 28일 코스피 시가총액 상위 40종목(보통주 · 나중에 상장폐지·합병된 6종목 포함)을 2002년부터 매달 첫 거래일에 산다고 보고, 산 뒤 3년 안에 종가가 산 값의 70% 이하가 된 첫날(= 30% 물린 날)을 모두 모았습니다 — 1,797건(물린 날 2007~2023). 물린 날 계좌 700만원(산 값 1,000만원)에서 3년 뒤 금액을 ① 그냥 버티기 ② 그날 종가에 절반을 KODEX 200 으로 옮기기 ③ 전부 옮기기로 견줬습니다(옮길 때 비용 0.4% 한 번).
| 상황 | 기준 |
|---|---|
| 국내 대형주가 산 값보다 30% 떨어졌다(종가 기준) | 그날 적어도 절반은 코스피200 ETF 로 옮긴다 |
| 지키는 법 | 살 때 산 값을 적어 두고, 종가가 산 값의 70% 아래로 내려온 날 절반을 팔아 코스피200 ETF 를 산다(이 페이지의 계산이 바로 이 규칙입니다) |
| 전부 옮기면 | 숫자로는 더 안전했습니다 — 반토막 0.0% · 3년 뒤 가운데 917만원(버티기 843만원 · 절반 894만원). 그 회사가 크게 돌아오는 몫은 통째로 놓칩니다 |
| 대표 사례(가운데쯤) | LG디스플레이 2018-08-01 매수 → 2019-07-31 물림 → 3년 뒤 그냥 버티기 819만원 · 절반 868만원 · 전부 917만원 |
| 2016년 이후만 | 그냥 버티기 8.8% · 절반 옮기기 0.5% — 같은 방향 |
| 왜 | 물렸다는 사실 때문이 아니라 한 종목 대 200종목의 차이입니다 — 물리지 않은 아무 달에 산 한 종목도 3년 뒤 KODEX 200 보다 더 남은 비율이 35.7%뿐이었습니다 |
돌리는 법: zip 을 풀고 pip install numpy 뒤 python run_stuckbig.py
기준일 2026-10-02 · 대형주 40종목 · 30% 물린 날 700만원 → 3년 뒤 · KODEX 200 · 옮길 때 비용 0.4% [전체 (물린 날 2007~2023)] 물린 경우 1,797건 · 종목 40개 그냥 버티기 3년 뒤 500만원 아래(넣은 돈의 절반도 못 지킴) 13.0% (233건) · 가운데 843만원 · 열 번 중 가장 나쁜 한 번 446만원 · 1,000만원 이상으로 회복 35.8% 절반 옮기기 3년 뒤 500만원 아래(넣은 돈의 절반도 못 지킴) 2.3% (41건) · 가운데 894만원 · 열 번 중 가장 나쁜 한 번 636만원 · 1,000만원 이상으로 회복 33.8% 전부 옮기기 3년 뒤 500만원 아래(넣은 돈의 절반도 못 지킴) 0.0% (0건) · 가운데 917만원 · 열 번 중 가장 나쁜 한 번 728만원 · 1,000만원 이상으로 회복 30.4% [2007-02 ~ 2015 에 물린 경우] 물린 경우 1,059건 · 종목 39개 그냥 버티기 3년 뒤 500만원 아래(넣은 돈의 절반도 못 지킴) 15.9% (168건) · 가운데 777만원 · 열 번 중 가장 나쁜 한 번 388만원 · 1,000만원 이상으로 회복 31.7% 절반 옮기기 3년 뒤 500만원 아래(넣은 돈의 절반도 못 지킴) 3.5% (37건) · 가운데 841만원 · 열 번 중 가장 나쁜 한 번 605만원 · 1,000만원 이상으로 회복 26.9% 전부 옮기기 3년 뒤 500만원 아래(넣은 돈의 절반도 못 지킴) 0.0% (0건) · 가운데 878만원 · 열 번 중 가장 나쁜 한 번 724만원 · 1,000만원 이상으로 회복 18.8% [2016 이후에 물린 경우] 물린 경우 738건 · 종목 40개 그냥 버티기 3년 뒤 500만원 아래(넣은 돈의 절반도 못 지킴) 8.8% (65건) · 가운데 915만원 · 열 번 중 가장 나쁜 한 번 520만원 · 1,000만원 이상으로 회복 41.6% 절반 옮기기 3년 뒤 500만원 아래(넣은 돈의 절반도 못 지킴) 0.5% (4건) · 가운데 954만원 · 열 번 중 가장 나쁜 한 번 713만원 · 1,000만원 이상으로 회복 43.6% 전부 옮기기 3년 뒤 500만원 아래(넣은 돈의 절반도 못 지킴) 0.0% (0건) · 가운데 973만원 · 열 번 중 가장 나쁜 한 번 780만원 · 1,000만원 이상으로 회복 47.2% [쉬운 말로] 3년 뒤 넣은 돈의 절반도 못 지킨 경우 그냥 버티기 13.0% → 7.7번 중 한 번꼴 절반 옮기기 2.3% → 43.8번 중 한 번꼴 전부 옮기기 0.0% → 한 번도 없음 전부 옮기기가 그냥 버티기보다 더 남은 경우 58.3% [대표 사례] LG디스플레이 2018-08-01 매수 → 물린 날 → 3년 뒤 물린 날 2019-07-31 · 끝 2022-08-17 · 그냥 버티기 819만원 · 절반 옮기기 868만원 · 전부 옮기기 917만원 [넣은 돈의 절반도 못 지킨 경우 — 종목별] 그냥 버티기: STX팬오션 38 · 현대산업개발 29 · 두산중공업 22 · 대우조선해양 20 · GS건설 19 · 삼성중공업 17 · 현대중공업 12 · 미래에셋증권(옛) 11 · LG화학 8 · SK에너지 7 · 한국전력 6 · LG디스플레이 6 · LG전자 6 · POSCO 5 · 롯데쇼핑 5 · 현대제철 4 · 대림산업 3 · 신세계 3 · S-Oil 3 · 대우건설 3 · 현대건설 2 · 삼성물산(옛) 2 · 외환은행 2 절반 옮기기: STX팬오션 29 · GS건설 4 · 대우조선해양 4 · LG화학 4 물린 해별 건수: 2007 15 · 2008 325 · 2009 17 · 2010 33 · 2011 197 · 2012 94 · 2013 55 · 2014 134 · 2015 189 · 2016 52 · 2017 28 · 2018 111 · 2019 117 · 2020 222 · 2021 30 · 2022 138 · 2023 40 [더 깊게 물렸을 때] 그냥 버티기가 전부 옮기기보다 더 남은 비율 · 3년 뒤 가운데 배수(버티기 대 전부) 30% 물림 1,797건 · 버티기가 더 남음 41.7% · 가운데 1.20배 대 1.31배 40% 물림 1,123건 · 버티기가 더 남음 44.4% · 가운데 1.28배 대 1.36배 50% 물림 662건 · 버티기가 더 남음 48.3% · 가운데 1.37배 대 1.39배 [STX팬오션을 뺀 판] 물린 경우 1,732건 · 넣은 돈의 절반도 못 지킴: 그냥 버티기 11.3% · 절반 옮기기 0.7% · 전부 옮기기 0.0% [물리지 않은 아무 달] 한 종목을 사서 3년 든 쪽이 KODEX 200 보다 더 남은 비율 35.7% (7,719번) · 물린 날 버티기 41.7% 끝.
# -*- coding: utf-8 -*-
"""물린 대형주 — 그냥 버틸까, 절반을 코스피200 ETF 로 옮길까 (AlgoLab 재현 코드 · 2026-10-17)
무엇을 재나
2007년 12월 28일 코스피 시가총액 상위 40종목(보통주). 나중에 상장폐지·합병된 6종목도 넣었다
(네이버 종가 + 합병 뒤 존속 회사 수익률로 이어 붙임 · 이 6종목 구간은 배당 미반영).
2002년부터 매달 첫 거래일에 그 종목을 산다고 본다. 산 뒤 3년 안에 종가가 산 값의 70% 이하가 된 첫날 = 물린 날
(물린 날이 2007-02-01 이후 · 같은 종목·같은 물린 날은 한 번만 센다).
물린 날 계좌 700만원(산 값 1,000만원)에서 3년(750거래일) 뒤 금액을 세 가지로 본다.
그냥 버티기 = 그대로 든다
절반 옮기기 = 물린 날 종가에 절반을 팔아 KODEX 200 을 산다
전부 옮기기 = 물린 날 종가에 전부 팔아 KODEX 200 을 산다
옮기는 몫에는 매도 수수료 0.1% + 거래세 0.2% + 매수 수수료 0.1% = 0.4% 를 한 번 뺀다.
양도세·배당 세금·호가 차이는 넣지 않았다. 종가에 사고판다고 쳤다.
자료(data_stuckbig/ · 2026-10-02 까지로 얼림)
<종목코드>.csv 야후 수정 종가(상폐·합병 6종은 네이버 종가 이음) · KODEX200.csv (2002~ 이음) · KS11.csv (코스피 · 거래일 대조용)
하루 등락이 ±31% 를 넘는 날은 자료 오류로 보고 0 으로 둔다.
인적분할 날(야후 수정 종가가 떨어져 나간 회사 몫을 못 담는 날) 넷도 0 으로 둔다 — 아래 SPINOFF.
돌리는 법: pip install numpy → python run_stuckbig.py
"""
import collections
import csv
import os
import numpy as np
HERE = os.path.dirname(os.path.abspath(__file__))
D = os.path.join(HERE, "data_stuckbig")
ASOF = "2026-10-02"
LOSS = 0.70 # 산 값의 70% = 30% 물림
H = 750 # 3년(거래일)
COST = 0.004 # 옮길 때 팔고 사는 비용(한 번)
DEV_END = "2015-12-31"
SPINOFF = {"023530": ["2017-10-30"], "003550": ["2021-05-27"], "017670": ["2021-11-29"], "012630": ["2018-06-12"]}
NAME = {"000210": "대림산업", "000660": "SK하이닉스", "000720": "현대건설", "000810": "삼성화재", "000830": "삼성물산(옛)",
"003550": "LG", "003600": "SK(옛)", "004020": "현대제철", "004170": "신세계", "004940": "외환은행",
"005380": "현대차", "005490": "POSCO", "005930": "삼성전자", "006360": "GS건설", "009540": "현대중공업",
"010140": "삼성중공업", "010950": "S-Oil", "012330": "현대모비스", "012630": "현대산업개발", "015760": "한국전력",
"016360": "삼성증권", "017670": "SK텔레콤", "023530": "롯데쇼핑", "024110": "기업은행", "028670": "STX팬오션",
"029780": "삼성카드", "030200": "KT", "033780": "KT&G", "034020": "두산중공업", "034220": "LG디스플레이",
"037620": "미래에셋증권(옛)", "042660": "대우조선해양", "047040": "대우건설", "051910": "LG화학", "053000": "우리금융(옛)",
"060000": "국민은행", "066570": "LG전자", "086790": "하나금융지주", "096770": "SK에너지"}
def load(path, clean=False, code=None):
rows = [r for r in csv.reader(open(path, encoding="utf-8")) if r and r[0][:1].isdigit()]
d = np.array([r[0] for r in rows]); c = np.array([float(r[4]) for r in rows])
k = d <= ASOF
d, c = d[k], c[k]
if clean:
k = c > 0
d, c = d[k], c[k]
r = c[1:] / c[:-1] - 1
r[np.abs(r) > 0.31] = 0.0
for day in SPINOFF.get(code, []):
j = np.where(d[1:] == day)[0]
assert len(j) == 1, (code, day)
r[j[0]] = 0.0
c = c[0] * np.concatenate([[1.0], np.cumprod(1 + r)])
return d, c
kd, kc = load(os.path.join(D, "KODEX200.csv"))
xd, _ = load(os.path.join(D, "KS11.csv"))
kmap = {d: i for i, d in enumerate(kd)}
xset = set(xd)
codes = sorted(f[:-4] for f in os.listdir(D) if f[:1].isdigit() and f.endswith(".csv"))
assert len(codes) == 40, len(codes)
SER = {c: load(os.path.join(D, c + ".csv"), clean=True, code=c) for c in codes}
def events(loss=LOSS):
out = []
for code in codes:
d, c = SER[code]
seen, months = set(), {}
for i, di in enumerate(d):
if di >= "2002-01-01" and di[:7] not in months:
months[di[:7]] = i
for b in months.values():
hit = np.where(c[b + 1:min(len(c), b + 750)] <= loss * c[b])[0]
if not len(hit):
continue
t = b + 1 + hit[0]
if d[t] < "2007-02-01" or (code, t) in seen:
continue
seen.add((code, t))
if d[b] not in xset or d[t] not in xset or d[t] not in kmap:
continue
ki = kmap[d[t]]
if not (t + H < len(c) and ki + H < len(kc)):
continue
if d[t + H] == kd[ki + H]:
kj = ki + H
elif d[t + H] in kmap:
kj = kmap[d[t + H]]
else:
continue
out.append({"code": code, "buy": d[b], "t": d[t], "end": d[t + H], "h": c[t + H] / c[t],
"s": kc[kj] / kc[ki] * (1 - COST)})
return out
def won(x):
return f"{round(x):,}만원"
def block(e, title):
h = np.array([x["h"] for x in e]); s = np.array([x["s"] for x in e]); m = 0.5 * h + 0.5 * s
print(f"\n[{title}] 물린 경우 {len(e):,}건 · 종목 {len({x['code'] for x in e})}개")
for nm, x in (("그냥 버티기", h), ("절반 옮기기", m), ("전부 옮기기", s)):
v = 700 * x
print(f" {nm} 3년 뒤 500만원 아래(넣은 돈의 절반도 못 지킴) {np.mean(v < 500) * 100:.1f}% ({int((v < 500).sum())}건)"
f" · 가운데 {won(np.median(v))} · 열 번 중 가장 나쁜 한 번 {won(np.quantile(v, 0.1))}"
f" · 1,000만원 이상으로 회복 {np.mean(v >= 1000) * 100:.1f}%")
return h, s, m
ev = events()
print(f"기준일 {ASOF} · 대형주 {len(codes)}종목 · 30% 물린 날 700만원 → 3년 뒤 · KODEX 200 · 옮길 때 비용 {COST * 100:.1f}%")
h, s, m = block(ev, "전체 (물린 날 2007~2023)")
block([x for x in ev if x["t"] <= DEV_END], "2007-02 ~ 2015 에 물린 경우")
block([x for x in ev if x["t"] > DEV_END], "2016 이후에 물린 경우")
print("\n[쉬운 말로] 3년 뒤 넣은 돈의 절반도 못 지킨 경우")
for nm, x in (("그냥 버티기", h), ("절반 옮기기", m), ("전부 옮기기", s)):
p = float(np.mean(700 * x < 500))
print(f" {nm} {p * 100:.1f}% → " + ("한 번도 없음" if p == 0 else f"{1 / p:.1f}번 중 한 번꼴"))
print(f" 전부 옮기기가 그냥 버티기보다 더 남은 경우 {np.mean(s > h) * 100:.1f}%")
print("\n[대표 사례] LG디스플레이 2018-08-01 매수 → 물린 날 → 3년 뒤")
for x in ev:
if x["code"] == "034220" and x["buy"] == "2018-08-01":
print(f" 물린 날 {x['t']} · 끝 {x['end']} · 그냥 버티기 {won(700 * x['h'])} · 절반 옮기기 {won(700 * (x['h'] + x['s']) / 2)}"
f" · 전부 옮기기 {won(700 * x['s'])}")
hb = collections.Counter(NAME[x["code"]] for x in ev if 700 * x["h"] < 500)
mb = collections.Counter(NAME[x["code"]] for x in ev if 700 * (x["h"] + x["s"]) / 2 < 500)
print("\n[넣은 돈의 절반도 못 지킨 경우 — 종목별]")
print(" 그냥 버티기: " + " · ".join(f"{k} {v}" for k, v in hb.most_common()))
print(" 절반 옮기기: " + " · ".join(f"{k} {v}" for k, v in mb.most_common()))
print(" 물린 해별 건수: " + " · ".join(f"{k} {v}" for k, v in sorted(collections.Counter(x["t"][:4] for x in ev).items())))
print("\n[더 깊게 물렸을 때] 그냥 버티기가 전부 옮기기보다 더 남은 비율 · 3년 뒤 가운데 배수(버티기 대 전부)")
for loss in (0.70, 0.60, 0.50):
e = events(loss)
hh = np.array([x["h"] for x in e]); ss = np.array([x["s"] for x in e])
print(f" {round((1 - loss) * 100)}% 물림 {len(e):,}건 · 버티기가 더 남음 {np.mean(hh > ss) * 100:.1f}% · 가운데 {np.median(hh):.2f}배 대 {np.median(ss):.2f}배")
e2 = [x for x in ev if x["code"] != "028670"]
h2 = np.array([x["h"] for x in e2]); s2 = np.array([x["s"] for x in e2])
print(f"\n[STX팬오션을 뺀 판] 물린 경우 {len(e2):,}건 · 넣은 돈의 절반도 못 지킴: 그냥 버티기 {np.mean(700 * h2 < 500) * 100:.1f}%"
f" · 절반 옮기기 {np.mean(700 * (h2 + s2) / 2 < 500) * 100:.1f}% · 전부 옮기기 {np.mean(700 * s2 < 500) * 100:.1f}%")
anym = []
for code in codes:
d, c = SER[code]
seen = set()
for i, di in enumerate(d):
if di < "2007-02-01" or di[:7] in seen:
continue
seen.add(di[:7])
if di in kmap and i + H < len(c) and kmap[di] + H < len(kc):
anym.append(c[i + H] / c[i] > kc[kmap[di] + H] / kc[kmap[di]])
print(f"\n[물리지 않은 아무 달] 한 종목을 사서 3년 든 쪽이 KODEX 200 보다 더 남은 비율 {np.mean(anym) * 100:.1f}% ({len(anym):,}번)"
f" · 물린 날 버티기 {np.mean(h > s) * 100:.1f}%")
print("\n끝.")
알고랩 Strategy Lab — 전략을 검증하고, 검증한 것만 자동매매로 옮깁니다. 손해를 확정하는 날 망설이지 않는 일은 사람보다 봇이 잘합니다. 알고랩 자동매매 살펴보기 · 전략 검증 전체 보기
과거 데이터를 돌려 본 결과이며 미래 수익을 보장하지 않습니다. 투자 판단과 책임은 본인에게 있습니다.