월배당 커버드콜 ETF QYLD와 그냥 지수 ETF QQQ에 1000만원씩 넣고 2013년 12월부터 2026년 8월까지 12년을 실측했습니다. 시뮬레이션이 아니라 실물 ETF의 가격과 분배금 실지급 기록입니다. 분배금을 한 푼도 안 쓰고 전부 재투자해도 2831만원 vs 9411만원. 매달 현금으로 받아 썼다면 계좌에 남은 돈은 730만원이었습니다.
1000만원 · 2013-12-12 ~ 2026-08-27 (기준일 고정) · 만원 단위
| 시나리오 | QYLD | QQQ |
|---|---|---|
| A. 분배금 전액 재투자 (총수익) | 2831만 | 9411만 |
| B. 분배금 현금 수령 — 남은 원금 | 730만 | 8488만 |
| B. 받은 분배금 누적 | 1126만 | 274만 |
| B. 합계 (원금 + 분배금) | 1856만 | 8762만 |
| C. 분배금 15% 원천징수 후 재투자 | 2311만 | 9267만 |
| 최대낙폭 (재투자 기준) | -25% | -35% |
배당 재투자 기준 · 커버드콜이 이긴 해는 2022년 하락장 한 번
| 연도 | QYLD | QQQ | 승자 |
|---|---|---|---|
| 2014 | +3.4% | +19.2% | QQQ |
| 2015 | +6.5% | +9.4% | QQQ |
| 2016 | +3.0% | +7.1% | QQQ |
| 2017 | +18.1% | +32.7% | QQQ |
| 2018 | -3.1% | -0.1% | QQQ |
| 2019 | +22.7% | +39.0% | QQQ |
| 2020 | +8.7% | +48.4% | QQQ |
| 2021 | +10.4% | +27.4% | QQQ |
| 2022 | -19.1% | -32.6% | QYLD |
| 2023 | +22.8% | +54.9% | QQQ |
| 2024 | +19.4% | +25.6% | QQQ |
| 2025 | +9.3% | +20.8% | QQQ |
| 2026 (8월까지) | +12.1% | +17.7% | QQQ |
주당 연 분배금 · 2014년 → 2025년 실측
| ETF | 2014년 주당 | 2025년 주당 | 변화 |
|---|---|---|---|
| SCHD (배당성장) | $0.35 | $1.05 | 3.0배 |
| QYLD (커버드콜) | $2.38 | $2.04 | -14% |
표준 라이브러리만 씁니다. 파이썬만 있으면 pip 설치 없이 그대로 돌아갑니다.
파이썬 설치 — python.org에서 3.8 이상.
아래 코드 저장 — covered_call_backtest.py 이름으로 저장하거나 여기서 내려받기.
실행 — python covered_call_backtest.py. 야후 파이낸스에서 데이터를 받아 위 표의 모든 숫자를 다시 만듭니다.
ASOF를 None으로 바꾸세요 — 시세가 움직인 만큼 숫자가 달라지는 게 정상입니다.
# -*- coding: utf-8 -*-
# =============================================================================
# 커버드콜 ETF 12년 실측 — AlgoLab (algolab.co.kr/coveredcall)
#
# 영상 "커버드콜 ETF 12년, 원금이 730만원 남았습니다"의 재현 코드입니다.
# 표준 라이브러리만 씁니다(pip 설치 불필요). 파이썬 3.8+ 에서:
#
# python covered_call_backtest.py
#
# 하는 일:
# 1) 야후 파이낸스에서 QYLD·QQQ·XYLD·SPY·SCHD 일봉과 분배금 내역을 받는다
# 2) 1000만원을 넣고 세 가지로 계산한다
# A. 분배금 전액 재투자(총수익) B. 분배금 현금 수령 C. 분배금에 15% 원천징수 후 재투자
# 3) 연도별 총수익, 주당 분배금 성장까지 영상의 모든 수치를 다시 만든다
#
# ⚠ ASOF 를 영상 기준일로 고정했습니다. 오늘까지 데이터로 보려면 None 으로 바꾸세요.
# (고정하지 않으면 시세가 움직여 영상과 숫자가 달라집니다 — 오류가 아닙니다)
# =============================================================================
import datetime
import json
import urllib.request
ASOF = datetime.date(2026, 8, 27) # 영상 기준일. 최신으로 보려면 None
INIT = 1000.0 # 만원
def fetch(sym):
u = (f"https://query1.finance.yahoo.com/v8/finance/chart/{sym}"
f"?range=20y&interval=1d&events=div%2Csplit")
req = urllib.request.Request(u, headers={"User-Agent": "Mozilla/5.0"})
j = json.loads(urllib.request.urlopen(req, timeout=40).read())
r = j["chart"]["result"][0]
ts = r["timestamp"]
close = r["indicators"]["quote"][0]["close"]
adj = r["indicators"]["adjclose"][0]["adjclose"]
rows = []
for t, c, a in zip(ts, close, adj):
if c is None or a is None:
continue
d = datetime.date.fromtimestamp(t)
if ASOF and d > ASOF:
continue
rows.append((d, c, a))
divs = []
for v in (r.get("events", {}).get("dividends", {}) or {}).values():
d = datetime.date.fromtimestamp(v["date"])
if ASOF and d > ASOF:
continue
divs.append((d, v["amount"]))
divs.sort()
return rows, divs
def reinvest(rows, d0):
"""A. 분배금 전액 재투자 = adjclose 총수익"""
seg = [r for r in rows if r[0] >= d0]
return INIT * seg[-1][2] / seg[0][2]
def take_cash(rows, divs, d0, tax=0.0):
"""B. 분배금 현금 수령 — 수량 고정. (남은 평가액, 받은 분배금 합계)"""
seg = [r for r in rows if r[0] >= d0]
units = INIT / seg[0][1]
cash = sum(units * amt * (1 - tax) for d, amt in divs if seg[0][0] <= d <= seg[-1][0])
return units * seg[-1][1], cash
def reinvest_after_tax(rows, divs, d0, tax=0.15):
"""C. 분배금에 세금 떼고 그날 종가로 재투자"""
seg = [r for r in rows if r[0] >= d0]
di = dict(divs)
units = INIT / seg[0][1]
for d, c, a in seg:
if d in di:
units += units * di[d] * (1 - tax) / c
return units * seg[-1][1]
def yearly(rows, d0):
seg = [r for r in rows if r[0] >= d0]
out = {}
for y in range(seg[0][0].year, seg[-1][0].year + 1):
m = [i for i, r in enumerate(seg) if r[0].year == y]
if len(m) < 10:
continue
prev = seg[m[0] - 1][2] if m[0] > 0 else seg[m[0]][2]
out[y] = seg[m[-1]][2] / prev - 1
return out
def year_div(divs, y):
return sum(a for d, a in divs if d.year == y)
def main():
data = {s: fetch(s) for s in ("QYLD", "QQQ", "XYLD", "SPY", "SCHD")}
d0 = data["QYLD"][0][0][0] # QYLD 상장일 = 2013-12-12
print(f"구간: {d0} ~ {data['QYLD'][0][-1][0]} (1000만원 기준, 만원 단위)\n")
print("[나스닥100] 같은 지수, 두 ETF")
for sym in ("QYLD", "QQQ"):
rows, divs = data[sym]
a = reinvest(rows, d0)
b_val, b_cash = take_cash(rows, divs, d0)
c = reinvest_after_tax(rows, divs, d0)
print(f" {sym:5s} 재투자 {a:7.0f}만 | 현금수령: 남은 돈 {b_val:6.0f}만"
f" + 받은 배당 {b_cash:6.0f}만 = {b_val + b_cash:7.0f}만 | 세후재투자 {c:7.0f}만")
print("\n[S&P500] 같은 비교 — 부호가 유지되는가")
d0x = data["XYLD"][0][0][0]
for sym in ("XYLD", "SPY"):
print(f" {sym:5s} 재투자 {reinvest(data[sym][0], d0x):7.0f}만 (시작 {d0x})")
print("\n[연도별 총수익] QYLD vs QQQ — 커버드콜이 이긴 해")
yq = yearly(data["QYLD"][0], d0)
yb = yearly(data["QQQ"][0], d0)
wins = [y for y in yq if y in yb and yq[y] > yb[y]]
for y in sorted(yq):
if y in yb:
mark = " ← QYLD 승" if y in wins else ""
print(f" {y} QYLD {yq[y]*100:+6.1f}% QQQ {yb[y]*100:+6.1f}%{mark}")
print(f" → QYLD가 이긴 해 {len(wins)}번")
print("\n[주당 연 분배금] 배당이 자라는가 (2014 → 2025)")
for sym in ("SCHD", "QYLD"):
v14 = year_div(data[sym][1], 2014)
v25 = year_div(data[sym][1], 2025)
print(f" {sym:5s} ${v14:.2f} → ${v25:.2f} ({v25 / v14:.2f}배)")
rows, divs = data["SCHD"]
seg0 = [r for r in rows if r[0] >= d0][0]
print(f"\n[SCHD] 2013-12 매수가 기준 지금 시가배당률(YoC): "
f"{year_div(divs, 2025) / seg0[1] * 100:.1f}%")
print(f" SCHD 재투자 {reinvest(rows, d0):.0f}만 · "
f"같은 기간 SPY {reinvest(data['SPY'][0], d0):.0f}만")
print("\n[민감도] 시작일을 바꿔도 순위가 유지되는가 (재투자)")
for dd in (datetime.date(2018, 1, 2), datetime.date(2021, 11, 19),
datetime.date(2022, 12, 28)):
a = reinvest(data["QYLD"][0], dd)
b = reinvest(data["QQQ"][0], dd)
print(f" {dd} 시작 QYLD {a:6.0f}만 QQQ {b:6.0f}만")
print("\n한계: 미국 상장 ETF 세전 기준, 환율·국내 세금 미반영. 과거 실측이지 예측이 아닙니다.")
if __name__ == "__main__":
main()