# -*- coding: utf-8 -*-
"""코스피 ETF 현금 비중 — 전부 넣을까, 일부는 단기채 ETF에 빼 두고 매달 맞출까
  주식     = KODEX 200(069500) · 현금 자리 = KODEX 단기채권(153130)
  가격     = 야후 수정종가(분배금 포함) · 기준일 ASOF 고정 · 1,000만원
  매달 맞춤 = 매달 첫 거래일 종가에 정한 비중으로 되돌림(사고판 금액에 편도 0.1%)
  방치     = 처음 비중으로 사고 그냥 둠
세금(일반 계좌 단기채 ETF 매매차익 15.4%)은 넣지 않았다.
표준 라이브러리만 쓴다:  python run_kcash.py
"""
import csv, os, sys
sys.stdout.reconfigure(encoding="utf-8")
ASOF = "2026-11-03"
COST = 0.001
P = 1000.0  # 만원
HERE = os.path.dirname(os.path.abspath(__file__))

def load(name):
    with open(os.path.join(HERE, "data", name + ".csv"), encoding="utf-8") as f:
        return {r["date"]: float(r["close"]) for r in csv.DictReader(f) if r["date"] <= ASOF and float(r["close"]) > 0}

S_, C_ = load("KODEX200"), load("KODEX_SHORTBOND")
D = sorted(set(S_) & set(C_))
S = [S_[d] for d in D]; C = [C_[d] for d in D]
MON = [True] + [D[i][5:7] != D[i - 1][5:7] for i in range(1, len(D))]

def sim(i0, i1, w, rebal=True):
    s = P * w * (1 - COST); c = P * (1 - w); path = [s + c]
    for t in range(i0 + 1, i1 + 1):
        s *= S[t] / S[t - 1]; c *= C[t] / C[t - 1]
        if rebal and MON[t] and w < 1:
            v = s + c; v -= abs(v * w - s) * COST; s, c = v * w, v * (1 - w)
        path.append(s + c)
    return path

def mdd(p):
    pk, m = p[0], 0.0
    for x in p:
        pk = max(pk, x); m = min(m, x / pk - 1)
    return m

def idx(day, after=True):
    if after: return next(i for i, d in enumerate(D) if d >= day)
    return max(i for i, d in enumerate(D) if d <= day)

def median(xs):
    xs = sorted(xs); n = len(xs)
    return xs[n // 2] if n % 2 else (xs[n // 2 - 1] + xs[n // 2]) / 2

def plus_years(day, y):
    yy, mm, dd = int(day[:4]) + y, day[5:7], day[8:10]
    if mm == "02" and dd == "29": dd = "28"
    return f"{yy}-{mm}-{dd}"

m = lambda x: f"{x:,.0f}만원"
print(f"자료: {D[0]} ~ {D[-1]} · 거래일 {len(D):,}일 · 1,000만원 · 매달 맞출 때 편도 {COST*100:.1f}%\n")

print("■ 올해 6월 22일(코스피 ETF 가장 높던 날) 1,000만원 — 10월 26일 바닥 / 11월 3일 지금")
pk, bt, now = idx("2026-06-22"), idx("2026-10-26"), len(D) - 1
for w in (1.0, 0.9, 0.8, 0.7, 0.6):
    a, b = sim(pk, bt, w), sim(pk, now, w)
    name = "전부" if w == 1 else f"코스피 ETF {w*100:.0f}% + 단기채 {100-w*100:.0f}% 매달 맞춤"
    print(f"  {name:<30} 바닥 {m(a[-1])} · 지금 {m(b[-1])} · 꼭대기→바닥 {mdd(a)*100:.1f}%")
b = sim(pk, now, 0.8, rebal=False)
print(f"  {'80/20 넣어 두고 그냥 둠':<30} 지금 {m(b[-1])}\n")

print("■ 대가 — 매달 첫 거래일에 시작해 10년 들고 있으면(1,000만원)")
starts = [i for i in range(len(D)) if MON[i]]
rows = []
for i0 in starts:
    t1 = plus_years(D[i0], 10)
    if t1 > D[-1]: break
    i1 = idx(t1)
    r = {w: sim(i0, i1, w)[-1] for w in (1.0, 0.9, 0.8, 0.7, 0.6)}
    r["방치"] = sim(i0, i1, 0.8, rebal=False)[-1]
    rows.append(r)
print(f"  시작 {D[starts[0]]} ~ {D[starts[len(rows)-1]]} · {len(rows)}번")
for w in (1.0, 0.9, 0.8, 0.7, 0.6):
    print(f"  {'전부' if w == 1 else f'코스피 ETF {w*100:.0f}%':<14} 10년 뒤 가운데 {m(median([r[w] for r in rows]))}")
for w in (0.9, 0.8, 0.7, 0.6):
    print(f"  코스피 ETF {w*100:.0f}% — 같은 달에 시작한 전부 넣은 계좌보다 덜 남은 돈 가운데 {m(median([r[1.0] - r[w] for r in rows]))}")
print(f"  전부가 80/20(매달 맞춤)보다 더 남은 것 {sum(r[1.0] > r[0.8] for r in rows)}/{len(rows)}번")
print(f"  80/20 매달 맞춤이 80/20 그냥 둠보다 더 남은 것 {sum(r[0.8] > r['방치'] for r in rows)}/{len(rows)}번\n")

print("■ 그냥 둔 80/20 계좌는 올해 6월 꼭대기 때 코스피 ETF가 몇 %였나")
for t0 in ("2016-11-01", "2021-01-04", "2024-01-02", "2025-01-02"):
    i0 = idx(t0); s = P * 0.8 * (1 - COST); c = P * 0.2
    for t in range(i0 + 1, pk + 1): s *= S[t] / S[t - 1]; c *= C[t] / C[t - 1]
    w_pk = s / (s + c); v_pk = s + c
    for t in range(pk + 1, bt + 1): s *= S[t] / S[t - 1]; c *= C[t] / C[t - 1]
    e = sim(i0, bt, 0.8)
    print(f"  {D[i0]} 시작: 꼭대기 때 코스피 ETF {w_pk*100:.1f}% · 꼭대기→바닥 그냥 둠 {((s+c)/v_pk-1)*100:.1f}% · 매달 맞춤 {(e[-1]/e[pk-i0]-1)*100:.1f}%")
print("\n■ 지금(ASOF)까지 놓고 보면 — 80/20 매달 맞춤 대 그냥 둠(1,000만원)")
for t0 in ("2012-03-02", "2016-11-01", "2018-01-02", "2021-01-04", "2024-01-02", "2025-01-02", "2026-01-02", "2026-06-22"):
    i0 = idx(t0); a, b = sim(i0, now, 0.8)[-1], sim(i0, now, 0.8, rebal=False)[-1]
    print(f"  {D[i0]} 시작: 매달 맞춤 {m(a)} · 그냥 둠 {m(b)} · {'매달 맞춤' if a > b else '그냥 둠'} 쪽이 더 남음")
print("\n끝.")
