2016년 8월부터 2026년 8월까지, 코스피에 1000만원을 넣었습니다. 한 번도 안 판 계좌에는 3393만원이, 매일 사고판 계좌에는 12만원이 남았습니다. 종목도 기간도 같습니다. 매매를 잘해서 수익률이 달라지는 부분은 계산에 넣지 않았습니다 — 같은 수익률을 냈다고 쳤을 때 비용만으로 얼마나 갈리는지를 본 것입니다.
증권거래세는 팔 때만 냅니다. 수익이 났든 손해가 났든 상관없이 판 금액에 붙습니다.
| 구분 | 2025년까지 | 2026년부터 |
|---|---|---|
| 코스피 (거래세 0.05% + 농특세 0.15%) | 0.15% | 0.20% |
| 코스닥 (농특세 없음) | 0.15% | 0.20% |
| 위탁수수료 (MTS 기준 · 매수·매도 각각) | 0.015% | |
| 왕복 합계 | 0.18% | 0.23% |
100만원어치라면 — 살 때 수수료 150원, 팔 때 수수료 150원에 세금 2000원. 한 번 사고팔면 2300원입니다. 커피 한 잔 값도 안 됩니다. 문제는 이걸 몇 번 반복하느냐입니다.
여기서 사고판다는 건 전부 팔고 곧바로 같은 걸 다시 사는 것입니다. 현금으로 들고 있거나 다른 종목으로 갈아타는 게 아닙니다. 그래야 수익률은 그대로 두고 비용만 볼 수 있습니다. 코스피는 2016년 8월 2000선에서 2026년 8월 6900선 — 10년 동안 3.4배가 된 역대급 상승장이었습니다.
| 매매 주기 | 연 왕복 횟수 | 남은 돈 | 안 판 것 대비 |
|---|---|---|---|
| 안 판다 | 0회 | 3,393만원 | 100.0% |
| 연 1회 | 1회 | 3,315만원 | 97.7% |
| 분기 1회 | 4회 | 3,094만원 | 91.2% |
| 월 1회 | 12회 | 2,574만원 | 75.9% |
| 주 1회 | 52회 | 1,029만원 | 30.3% |
| 매일 | 246회 | 12만원 | 0.4% |
눈여겨볼 곳은 위쪽입니다. 분기에 한 번까지는 3094만원이 남습니다 — 횟수가 적을 때는 비용이 결과를 크게 흔들지 못합니다. 차이가 벌어지는 건 월 1회를 넘어서면서부터입니다. 주 1회는 일주일에 한 번 정도 사고파는 흔한 습관인데, 안 판 계좌와 2363만원이 벌어졌습니다.
주가가 전혀 움직이지 않았다고 쳐 보면 비용만 남습니다.
| 매매 주기 | 연 왕복 | 1년 뒤 | 10년 뒤 |
|---|---|---|---|
| 연 1회 | 1회 | 998만원 | 977.2만원 |
| 분기 1회 | 4회 | 991만원 | 912.0만원 |
| 월 1회 | 12회 | 973만원 | 758.6만원 |
| 주 1회 | 52회 | 887만원 | 302.0만원 |
| 매일 | 246회 | 568만원 | 3.5만원 |
1000만원으로 매일 사고팔면 1년 뒤에 568만원이 남습니다. 주가는 그대로인데 절반 가까이가 사라진 것입니다. 비용은 뗄 때마다 남은 돈에서 다시 떼어 가기 때문입니다. 줄어든 원금으로 다음 매매를 하고 거기서 또 뗍니다. 수익이 복리로 불어나듯 비용도 복리로 깎아 냅니다. 방향만 반대입니다.
국내 주식형 ETF는 증권거래세가 면제됩니다. 팔 때 붙던 2000원이 아예 없습니다. 수수료만 내면 되니 100만원을 사고팔 때 300원 — 개별 주식의 8분의 1입니다.
| 매매 주기 | 개별 주식 | 국내 주식형 ETF | 차이 |
|---|---|---|---|
| 월 1회 | 2,574만원 | 3,161만원 | +587만원 |
| 주 1회 | 1,029만원 | 2,904만원 | +1,875만원 |
| 매일 | 12만원 | 1,628만원 | +1,616만원 |
다만 ETF가 세금을 하나도 안 낸다는 뜻은 아닙니다. 면제되는 건 파는 순간의 증권거래세뿐이고, 분배금에는 배당소득세 15.4%가 붙습니다. 해외 지수를 담는 ETF는 세금 구조가 또 달라서 이 계산과 다르게 나옵니다.
그래도 남는 게 둘 있습니다. 매매 횟수를 줄이면 줄인 만큼 그대로 남습니다 (주 1회에서 월 1회로만 바꿔도 1029만원이 2574만원이 됐습니다). 그리고 국내 주식형 ETF에는 증권거래세가 없습니다. 시장이 오를지 내릴지는 아무도 모르지만, 한 번 사고팔 때 100만원당 2300원이 나가는 건 이미 정해져 있습니다.
Python 3.8+ 와 numpy 만 있으면 됩니다. 데이터는 실행할 때 자동으로 받습니다(API 키 불필요). 위 표가 그대로 나옵니다. 세율·수수료·기간을 바꿔 여러분의 조건으로 실험해도 됩니다.
# -*- coding: utf-8 -*-
# =============================================================================
# AlgoLab · 매매 비용 백테스트 — 공개용
# 영상 「같은 코스피, 같은 10년 — 3393만원 vs 12만원」의 숫자를 그대로 재현합니다.
# 믿지 말고 직접 돌려보세요. 세율·수수료·기간을 바꿔 여러분의 조건으로 실험해도 됩니다.
#
# 실행: python trading_cost_backtest.py
# 필요: Python 3.8+ / numpy (pip install numpy)
# 데이터는 Yahoo Finance 공개 API 에서 자동으로 받습니다(API 키 불필요).
#
# ── 무엇을 계산하나 ──────────────────────────────────────────────────────────
# "매매를 잘해서 수익률이 달라지는 부분"은 계산에 넣지 않습니다.
# 같은 수익률(코스피 지수)을 냈다고 쳤을 때, **매매 횟수만 다를 때 비용으로 얼마나
# 갈리는가**를 봅니다. 사고판다 = 전부 팔고 곧바로 같은 걸 다시 산다(왕복 1회).
#
# ── 세율 근거 (2026-08-30 확인, 두 곳 교차) ──────────────────────────────────
# · 코스피: 증권거래세 0.05% + 농어촌특별세 0.15% = 0.20% (2026년 1월 양도분부터)
# · 코스닥: 0.20% (농특세 없음). 2025년까지는 둘 다 0.15%
# · 위탁수수료: MTS 기준 0.014~0.015% → 여기서는 0.015% (매수·매도 각각)
# · 국내 주식형 ETF: 증권거래세 면제 → 왕복 비용은 수수료뿐(0.03%)
#
# ── 이 계산의 한계 (영상에서도 밝힙니다) ─────────────────────────────────────
# · 코스피 '지수'를 그대로 사고판다고 가정합니다. 지수에는 배당이 빠져 있습니다.
# · 단타로 시장보다 더 벌 수 있다면 결과는 달라집니다. 그건 이 계산의 범위 밖입니다.
# · 세금은 매도 금액에, 수수료는 매수·매도 양쪽에 물립니다.
# · 호가 스프레드·시장충격은 넣지 않았습니다(넣으면 격차는 더 벌어집니다).
# =============================================================================
import datetime, json, os, urllib.request
import numpy as np
FEE = 0.00015 # 위탁수수료 — 매수·매도 각각
TAX_2026 = 0.0020 # 증권거래세 2026년 (코스피 0.05 + 농특세 0.15)
TAX_2025 = 0.0015 # 2025년까지
SEED = 1000 # 만원 = 1000만원
# ★ 기준일 — 영상을 만든 날까지만 씁니다.
# 이걸 안 고정하면 시장이 움직인 만큼 결과가 달라져 **영상의 숫자와 안 맞습니다**
# (실측: 고정 없이 돌리면 3393만원이 3277만원으로 나옵니다. 코스피가 그새 내렸습니다).
# 오늘까지로 보고 싶으면 None 으로 바꾸세요. 결론(횟수가 늘수록 준다)은 그대로입니다.
ASOF = datetime.date(2026, 8, 27)
FREQ = [("never", "안 판다"), ("yearly", "연 1회"), ("quarterly", "분기 1회"),
("monthly", "월 1회"), ("weekly", "주 1회"), ("daily", "매일")]
def load_kospi(cache="kospi_daily.csv"):
"""코스피 일봉. 한 번 받으면 옆에 csv 로 저장해 두고 다음부터는 그걸 씁니다."""
if os.path.exists(cache):
import csv
d, c = [], []
for r in csv.DictReader(open(cache, encoding="utf-8")):
d.append(datetime.date(*map(int, r["date"].split("-"))))
c.append(float(r["close"]))
else:
url = ("https://query1.finance.yahoo.com/v8/finance/chart/%5EKS11"
"?range=30y&interval=1d")
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
j = json.loads(urllib.request.urlopen(req, timeout=30).read())
r = j["chart"]["result"][0]
q = r["indicators"]["quote"][0]
d, c = [], []
for i, ts in enumerate(r["timestamp"]):
if q["close"][i] is None:
continue
d.append(datetime.datetime.utcfromtimestamp(ts).date())
c.append(q["close"][i])
with open(cache, "w", encoding="utf-8", newline="") as f:
f.write("date,close\n")
for x, y in zip(d, c):
f.write("{},{}\n".format(x, round(y, 4)))
print(" 데이터를 받아 {} 에 저장했습니다 ({}일)".format(cache, len(d)))
# ⚠ 기준일 자르기는 **캐시를 쓰든 새로 받든 똑같이** 적용해야 한다.
# 한쪽에만 걸면 두 번째 실행부터 결과가 달라진다.
if ASOF:
keep = [i for i, x in enumerate(d) if x <= ASOF]
d = [d[i] for i in keep]
c = [c[i] for i in keep]
return d, np.array(c)
def sell_days(dates, freq):
"""회전 주기마다 True. 그날 팔고 곧바로 다시 삽니다(왕복 1회)."""
n = len(dates)
m = np.zeros(n, dtype=bool)
if freq == "never":
return m
if freq == "daily":
m[1:] = True
return m
for i in range(1, n):
a, b = dates[i - 1], dates[i]
if freq == "weekly":
m[i] = b.weekday() < a.weekday() # 주가 바뀌는 첫 거래일
elif freq == "monthly":
m[i] = b.month != a.month
elif freq == "quarterly":
m[i] = (b.month - 1) // 3 != (a.month - 1) // 3
elif freq == "yearly":
m[i] = b.year != a.year
return m
def run(close, dates, freq, roundtrip):
"""지수 수익률을 그대로 따라가되, 회전할 때마다 왕복 비용을 뺍니다."""
ret = np.zeros(len(close))
ret[1:] = close[1:] / close[:-1] - 1
sd = sell_days(dates, freq)
eq, out, trades = 1.0, np.empty(len(close)), 0
for i in range(len(close)):
eq *= (1 + ret[i])
if sd[i]:
eq *= (1 - roundtrip)
trades += 1
out[i] = eq
return out, trades
def table(title, header, rows):
print("\n■ " + title + "\n")
print("| " + " | ".join(header) + " |")
print("|" + "|".join(["---"] * len(header)) + "|")
for r in rows:
print("| " + " | ".join(str(x) for x in r) + " |")
if __name__ == "__main__":
d, c = load_kospi()
rt26 = TAX_2026 + FEE * 2 # 2026년 개별주식 왕복 0.23%
rt25 = TAX_2025 + FEE * 2 # 2025년까지 0.18%
rt_etf = FEE * 2 # 국내 주식형 ETF 0.03%
# ── 최근 10년 (영상의 핵심 표) ────────────────────────────────────────
i10 = next(i for i, x in enumerate(d) if x >= d[-1] - datetime.timedelta(days=3653))
d10, c10 = d[i10:], c[i10:]
print("■ 코스피 {} ~ {}".format(d10[0], d10[-1]))
print(" 지수 {:.0f} → {:.0f} ({:.1f}배)".format(c10[0], c10[-1], c10[-1] / c10[0]))
print(" 왕복 비용 — 개별주식 {:.2f}% · 국내 주식형 ETF {:.2f}%"
.format(rt26 * 100, rt_etf * 100))
base = run(c10, d10, "never", rt26)[0][-1]
rows = []
for key, lab in FREQ:
v = run(c10, d10, key, rt26)[0][-1]
rows.append([lab, "{:,.0f}만원".format(v * SEED), "{:.1f}%".format(v / base * 100)])
table("1000만원을 넣고 매매 횟수만 다르게 했을 때 (최근 10년)",
["매매 주기", "남은 돈", "안 판 것 대비"], rows)
# ── 개별주식 vs 국내 주식형 ETF ───────────────────────────────────────
rows = []
for key, lab in FREQ:
a = run(c10, d10, key, rt26)[0][-1]
b = run(c10, d10, key, rt_etf)[0][-1]
rows.append([lab, "{:,.0f}만원".format(a * SEED), "{:,.0f}만원".format(b * SEED),
"{:,.0f}만원".format((b - a) * SEED)])
table("거래세가 붙느냐 안 붙느냐 (같은 10년, 같은 1000만원)",
["매매 주기", "개별 주식", "국내 주식형 ETF", "차이"], rows)
# ── 순수 비용만 (지수가 제자리였다고 가정) ────────────────────────────
rows = []
for key, lab in FREQ:
if key == "never":
continue
n = {"daily": 246, "weekly": 52, "monthly": 12, "quarterly": 4, "yearly": 1}[key]
rows.append([lab, "{}회".format(n),
"{:,.0f}만원".format((1 - rt26) ** n * SEED),
"{:,.1f}만원".format((1 - rt26) ** (n * 10) * SEED)])
table("주가가 전혀 움직이지 않았다고 쳤을 때 (비용만)",
["매매 주기", "연 왕복", "1년 뒤", "10년 뒤"], rows)
# ── 100만원 한 번 사고팔 때 ───────────────────────────────────────────
print("\n■ 100만원어치를 한 번 사고팔면\n")
print(" 살 때 수수료 {:,.0f}원 · 팔 때 수수료 {:,.0f}원 · 세금 {:,.0f}원 → 합계 {:,.0f}원"
.format(1e6 * FEE, 1e6 * FEE, 1e6 * TAX_2026, 1e6 * rt26))
print(" 국내 주식형 ETF 는 세금이 없어 {:,.0f}원 — 개별 주식의 {:.0f}분의 1"
.format(1e6 * rt_etf, rt26 / rt_etf))
print("\n ⚠ 이 계산은 매매 실력에 따른 수익률 차이를 넣지 않았습니다.")
print(" 지수에는 배당이 빠져 있고, 호가 스프레드·시장충격도 넣지 않았습니다.")
※ 본 페이지의 수치는 공개된 시장 데이터를 과거 기준으로 검증한 교육·검증 목적의 자료이며, 특정인에 대한 투자권유나 매수·매도 권유가 아닙니다. 과거 백테스트 성과가 미래 수익을 보장하지 않습니다. 세율·수수료는 2026-08-30 기준 공개 자료로 확인한 값이며, 증권사·상품·시점에 따라 다를 수 있으니 실제 거래 전에는 본인 계좌의 조건을 확인하시기 바랍니다. 모든 투자 판단과 그에 따른 책임은 이용자 본인에게 있습니다.