나스닥 레버리지 · QLD · TQQQ · 실측 재현 페이지
1,000만원을 한 번에 넣고 10년을 묻어 둡니다. 나스닥100 총수익(1999년 3월부터 QQQ 수정종가 · 그 전은 나스닥100 지수 + 배당 추정 연 0.7%)에 실제 레버리지 ETF처럼 매일 배수를 다시 맞추는 2배·3배를 씌웠습니다(빌린 돈 이자 = 미국 3개월 국채 + 0.5% · 보수 연 0.95%). 시작 달 1985-10 ~ 2016-10, 373번을 전부 견줬습니다.
| 상황 | 할 일 |
|---|---|
| 나스닥 레버리지 ETF에 한 번에 넣고 10년 묻어 둘 때 | 3배 말고 2배 — 3배는 더 버는 때도 있지만 원금이 깨지는 10년이 두 배쯤 많았다 |
| 참고 — 레버리지 없는 1배 | 원금이 깨진 10년은 1배가 가장 적었다(27번) |
| 시작 → 10년 뒤 | 1배 | 2배 | 3배 | 3배가 가장 낮았던 날 |
|---|---|---|---|---|
| 1993-11 → 2003-11 (3배가 진 때) | 3,752만원 | 2,252만원 | 409만원 | 98만원 |
| 2014-07 → 2024-07 (3배가 이긴 때) | 5,502만원 | 14,058만원 | 24,394만원 | 891만원 |
사례 고르는 법: 3배가 진 179번·이긴 194번 각각에서 「3배 ÷ 2배」가 그 가운데 값(0.18 · 1.74)에 가장 가까운 달 — 가장 나쁜 달·가장 좋은 달을 고른 것이 아닙니다. 3배가 이긴 194번 중 2배의 두 배 넘게 남긴 것은 68번, 3배가 진 179번 중 2배의 절반도 못 남긴 것은 129번입니다.
| 시작 | 10년 수 | 3배가 이긴 것 |
|---|---|---|
| 1985~1994년 | 111번 | 61번 |
| 1995~2002년 | 96번 | 0번 |
| 2003~2009년 | 84번 | 51번 |
| 2010~2016년 | 82번 | 82번 |
실제 TQQQ 는 2010년 2월에 상장했습니다. 그 뒤 시작한 81번은 3배가 81번 이겼고, 실제 상장일부터 지금까지 TQQQ 는 323배 · QLD 는 105배입니다. 실물 기록으로 돌린 백테스트는 3배가 한 번도 지지 않은 시기만 담습니다.
| ETF | 구간 | 계산 연 수익 | 실제 연 수익 |
|---|---|---|---|
| QLD (2배) | 2006-06-21 ~ 2026-10-23 | 24.81% | 24.65% |
| TQQQ (3배) | 2010-02-11 ~ 2026-10-23 | 41.53% | 41.44% |
| SSO (2배) | 2006-06-21 ~ 2026-10-23 | 15.82% | 15.56% |
| UPRO (3배) | 2009-06-25 ~ 2026-10-23 | 32.83% | 32.36% |
계산 쪽이 해마다 0.1~0.5% 후합니다(레버리지 쪽에 유리한 방향).
돌리는 법: zip 을 풀고 python run_nasdaqlev.py
기준일 2026-10-23 실제 레버리지 ETF 와 계산 대조(같은 구간): QLD(2배) 2006-06-21 ~ 2026-10-23: 계산 연 24.81% / 실제 연 24.65% TQQQ(3배) 2010-02-11 ~ 2026-10-23: 계산 연 41.53% / 실제 연 41.44% SSO(2배) 2006-06-21 ~ 2026-10-23: 계산 연 15.82% / 실제 연 15.56% UPRO(3배) 2009-06-25 ~ 2026-10-23: 계산 연 32.83% / 실제 연 32.36% 실제 TQQQ 상장일 2010-02-11 ~ 2026-10-23: TQQQ 323배 · QLD 105배 == 나스닥100 · 1,000만원 한 번에 · 10년 · 시작 달 1985-10 ~ 2016-10 · 373번 3배가 2배보다 많이 남은 10년 194번 · 2배가 많거나 같았던 10년 179번 3배가 이긴 194번: 3배÷2배 가운데 값 1.74 · 2배의 두 배 넘게 남긴 것 68번 3배가 진 179번: 3배÷2배 가운데 값 0.18 · 2배의 절반도 못 남긴 것 129번 원금(1,000만원)보다 적게 끝난 10년: 1배 27번 · 2배 64번 · 3배 124번 2배라면 원금을 지켰는데 3배라서 원금 아래로 끝난 10년 60번 · 그 반대 0번 2배가 1배보다 많이 남은 10년 244번 시작 1985~1994년 111번 중 3배가 이긴 것 61번 시작 1995~2002년 96번 중 3배가 이긴 것 0번 시작 2003~2009년 84번 중 3배가 이긴 것 51번 시작 2010~2016년 82번 중 3배가 이긴 것 82번 매달 100만원씩 10년 나눠 산 경우: 3배가 2배보다 많이 남은 10년 227번 · 원금(1억 2천만원) 아래 2배 87번 · 3배 105번 [사례 · 3배가 진 10년 중 3배÷2배가 가운데 값에 가장 가까운 달] 1993-11 시작 → 2003-11: 1배 3,752만원 · 2배 2,252만원 · 3배 409만원 · 10년 중 가장 낮았던 날 3배 98만원 [사례 · 3배가 이긴 10년 중 3배÷2배가 가운데 값에 가장 가까운 달] 2014-07 시작 → 2024-07: 1배 5,502만원 · 2배 14,058만원 · 3배 24,394만원 · 10년 중 가장 낮았던 날 3배 891만원 2010년 2월(TQQQ 상장) 이후 시작 81번 중 3배가 이긴 것 81번 · 원금 아래 2배 0번 · 3배 0번 == S&P500(총수익) — 확인용 · 1,000만원 한 번에 · 10년 · 시작 달 1988-01 ~ 2016-10 · 346번 3배가 2배보다 많이 남은 10년 160번 · 2배가 많거나 같았던 10년 186번 3배가 이긴 160번: 3배÷2배 가운데 값 1.67 · 2배의 두 배 넘게 남긴 것 45번 3배가 진 186번: 3배÷2배 가운데 값 0.73 · 2배의 절반도 못 남긴 것 47번 원금(1,000만원)보다 적게 끝난 10년: 1배 23번 · 2배 48번 · 3배 59번 2배라면 원금을 지켰는데 3배라서 원금 아래로 끝난 10년 11번 · 그 반대 0번 2배가 1배보다 많이 남은 10년 249번 시작 1985~1994년 84번 중 3배가 이긴 것 57번 시작 1995~2002년 96번 중 3배가 이긴 것 2번 시작 2003~2009년 84번 중 3배가 이긴 것 19번 시작 2010~2016년 82번 중 3배가 이긴 것 82번 매달 100만원씩 10년 나눠 산 경우: 3배가 2배보다 많이 남은 10년 216번 · 원금(1억 2천만원) 아래 2배 37번 · 3배 66번 [사례 · 3배가 진 10년 중 3배÷2배가 가운데 값에 가장 가까운 달] 2003-02 시작 → 2013-02: 1배 2,155만원 · 2배 2,219만원 · 3배 1,617만원 · 10년 중 가장 낮았던 날 3배 193만원 [사례 · 3배가 이긴 10년 중 3배÷2배가 가운데 값에 가장 가까운 달] 2008-11 시작 → 2018-11: 1배 3,512만원 · 2배 7,450만원 · 3배 12,460만원 · 10년 중 가장 낮았던 날 3배 272만원 끝.
# -*- coding: utf-8 -*-
"""나스닥 레버리지 ETF — 10년 묻어 둘 거면 2배냐 3배냐 (AlgoLab · 2026-10-27)
표준 라이브러리만 씁니다. 같은 폴더의 data/ 를 읽습니다(야후 일봉, 2026-10-23까지 얼림).
돌리는 법: python run_nasdaqlev.py
계산
- 나스닥100 총수익: 1999-03-10 부터 QQQ 수정종가(배당 재투자) · 그 전은 나스닥100 지수(^NDX) 하루 수익 + 배당 추정 연 0.7%
- L배 레버리지(매일 L배를 다시 맞추는 실제 ETF 방식):
하루 수익 = L × 지수 하루 수익 − (L−1) × (미국 3개월 국채 금리 + 0.5%) ÷ 252 − 보수 연 0.95% ÷ 252
1배는 지수 그대로(보수 없음)
- 계좌: 매달 첫 거래일 종가에 1,000만원을 한 번에 사고, 10년 뒤 같은 달 첫 거래일 종가로 본다(매수만 · 호가 차이 없음)
"""
import csv
import os
import statistics
import sys
sys.stdout.reconfigure(encoding="utf-8")
HERE = os.path.dirname(os.path.abspath(__file__))
ASOF = "2026-10-23"
SPREAD, FEE, NDX_DIV = 0.005, 0.0095, 0.007
WON = 1000 # 만원
def series(name):
out = {}
with open(os.path.join(HERE, "data", name + ".csv"), encoding="utf-8") as f:
for r in csv.DictReader(f):
if r["date"] <= ASOF and r["close"] not in ("", "nan") and float(r["close"]) > 0:
out[r["date"]] = float(r["close"])
return out
IRX = series("IRX")
def ndx_tr():
ndx, qqq = series("NDX"), series("QQQ")
ds = sorted(ndx)
q0 = min(qqq)
v, out = 1.0, {ds[0]: 1.0}
for p, d in zip(ds, ds[1:]):
if d > q0 and p in qqq and d in qqq:
r = qqq[d] / qqq[p] - 1
else:
r = ndx[d] / ndx[p] - 1 + NDX_DIV / 252
v *= 1 + r
out[d] = v
return out
def paths(px):
"""날짜 목록과 1·2·3배 누적 가치."""
ds = sorted(px)
ik = sorted(IRX)
j, rf, P = 0, 0.0, {1: [1.0], 2: [1.0], 3: [1.0]}
for k in range(1, len(ds)):
while j < len(ik) and ik[j] <= ds[k]:
rf = IRX[ik[j]] / 100.0
j += 1
r = px[ds[k]] / px[ds[k - 1]] - 1
for L in (1, 2, 3):
rl = r if L == 1 else L * r - (L - 1) * (rf + SPREAD) / 252 - FEE / 252
P[L].append(P[L][-1] * (1 + max(rl, -0.999)))
return ds, P
def month_starts(ds):
idx, prev = [], None
for i, d in enumerate(ds):
if d[:7] != prev:
idx.append(i)
prev = d[:7]
return idx
def windows(px, years=10):
ds, P = paths(px)
ms = month_starts(ds)
n = years * 12
rows = []
for a in range(len(ms) - n):
s, e = ms[a], ms[a + n]
row = {"시작": ds[s][:7], "끝": ds[e][:7]}
for L in (1, 2, 3):
p = P[L]
row[L] = WON * p[e] / p[s]
row["바닥", L] = WON * min(p[s:e + 1]) / p[s]
row["적립", L] = 100 * sum(p[e] / p[ms[k]] for k in range(a, a + n))
rows.append(row)
return rows
def won(x):
return f"{x:,.0f}만원" if x >= 10 else f"{x:,.1f}만원"
def report(name, rows):
n = len(rows)
print(f"\n== {name} · 1,000만원 한 번에 · 10년 · 시작 달 {rows[0]['시작']} ~ {rows[-1]['시작']} · {n}번")
w3 = [x for x in rows if x[3] > x[2]]
l3 = [x for x in rows if x[3] <= x[2]]
print(f"3배가 2배보다 많이 남은 10년 {len(w3)}번 · 2배가 많거나 같았던 10년 {len(l3)}번")
rw = [x[3] / x[2] for x in w3]
rl = [x[3] / x[2] for x in l3]
print(f"3배가 이긴 {len(w3)}번: 3배÷2배 가운데 값 {statistics.median(rw):.2f} · 2배의 두 배 넘게 남긴 것 {sum(r >= 2 for r in rw)}번")
print(f"3배가 진 {len(l3)}번: 3배÷2배 가운데 값 {statistics.median(rl):.2f} · 2배의 절반도 못 남긴 것 {sum(r < 0.5 for r in rl)}번")
lo = {L: sum(1 for x in rows if x[L] < WON) for L in (1, 2, 3)}
print(f"원금(1,000만원)보다 적게 끝난 10년: 1배 {lo[1]}번 · 2배 {lo[2]}번 · 3배 {lo[3]}번")
only3 = sum(1 for x in rows if x[3] < WON <= x[2])
only2 = sum(1 for x in rows if x[2] < WON <= x[3])
print(f"2배라면 원금을 지켰는데 3배라서 원금 아래로 끝난 10년 {only3}번 · 그 반대 {only2}번")
print(f"2배가 1배보다 많이 남은 10년 {sum(1 for x in rows if x[2] > x[1])}번")
for a, b in (("1985", "1994"), ("1995", "2002"), ("2003", "2009"), ("2010", "2016")):
sub = [x for x in rows if a <= x["시작"][:4] <= b]
if sub:
print(f" 시작 {a}~{b}년 {len(sub)}번 중 3배가 이긴 것 {sum(1 for x in sub if x[3] > x[2])}번")
acc = sum(1 for x in rows if x["적립", 3] > x["적립", 2])
acclo = {L: sum(1 for x in rows if x["적립", L] < 100 * 120) for L in (2, 3)}
print(f"매달 100만원씩 10년 나눠 산 경우: 3배가 2배보다 많이 남은 10년 {acc}번 · 원금(1억 2천만원) 아래 2배 {acclo[2]}번 · 3배 {acclo[3]}번")
for tag, grp, rs in (("3배가 진", l3, rl), ("3배가 이긴", w3, rw)):
m = statistics.median(rs)
x = min(zip(grp, rs), key=lambda t: abs(t[1] - m))[0]
print(f"[사례 · {tag} 10년 중 3배÷2배가 가운데 값에 가장 가까운 달] {x['시작']} 시작 → {x['끝']}: "
f"1배 {won(x[1])} · 2배 {won(x[2])} · 3배 {won(x[3])} · 10년 중 가장 낮았던 날 3배 {won(x['바닥', 3])}")
def real_vs_model(px, etf, L):
ds, P = paths(px)
e = series(etf)
common = [i for i, d in enumerate(ds) if d in e]
i0, i1 = common[0], common[-1]
yrs = (i1 - i0) / 252
syn = (P[L][i1] / P[L][i0]) ** (1 / yrs) - 1
act = (e[ds[i1]] / e[ds[i0]]) ** (1 / yrs) - 1
print(f" {etf}({L}배) {ds[i0]} ~ {ds[i1]}: 계산 연 {syn * 100:.2f}% / 실제 연 {act * 100:.2f}%")
if __name__ == "__main__":
print(f"기준일 {ASOF}")
ndx = ndx_tr()
sp = series("SP500TR")
print("실제 레버리지 ETF 와 계산 대조(같은 구간):")
for px, etf, L in ((ndx, "QLD", 2), (ndx, "TQQQ", 3), (sp, "SSO", 2), (sp, "UPRO", 3)):
real_vs_model(px, etf, L)
q, t = series("QLD"), series("TQQQ")
d0 = min(t)
d1 = max(d for d in t if d in q)
print(f"실제 TQQQ 상장일 {d0} ~ {d1}: TQQQ {t[d1] / t[d0]:.0f}배 · QLD {q[d1] / q[d0]:.0f}배")
rows = windows(ndx)
report("나스닥100", rows)
post = [x for x in rows if x["시작"] >= "2010-02"]
print(f" 2010년 2월(TQQQ 상장) 이후 시작 {len(post)}번 중 3배가 이긴 것 {sum(1 for x in post if x[3] > x[2])}번 · "
f"원금 아래 2배 {sum(1 for x in post if x[2] < WON)}번 · 3배 {sum(1 for x in post if x[3] < WON)}번")
report("S&P500(총수익) — 확인용", windows(sp))
print("\n끝.")
알고랩 Strategy Lab — 전략을 검증하고, 검증한 것만 자동매매로 옮깁니다. 처음 정한 배수를 10년 동안 흔들리지 않고 지키는 일은 사람보다 규칙이 잘합니다. 알고랩 자동매매 살펴보기 · 전략 검증 전체 보기
과거 데이터를 돌려 본 결과이며 미래 수익을 보장하지 않습니다. 투자 판단과 책임은 본인에게 있습니다.