"""
코스피와 코스닥은 얼마나 같이 움직였나: 상관계수, 큰 하락일의 동조화, 하락장, 수익률 차이

사용법:
    pip install finance-datareader pandas numpy matplotlib
    python kospi_vs_kosdaq.py
    python kospi_vs_kosdaq.py --synthetic     # 난수 데이터로 동작 확인

데이터: FinanceDataReader 의 코스피(KS11)·코스닥(KQ11) 일별 종가.
  - 코스닥 지수가 시작한 1996-07-01 부터 2026-10-30 까지(종료일 고정). 두 지수가 모두 있는 날만 쓴다.
  - 둘 다 배당을 뺀 가격지수다. 연복리(CAGR)는 달력 연수로 계산한다.
결과: output/kospi_vs_kosdaq.txt 와 차트 PNG
"""
import argparse
import os

import numpy as np
import pandas as pd

HERE = os.path.dirname(os.path.abspath(__file__))
OUT = os.path.join(HERE, "output")
START, END = "1996-07-01", "2026-10-30"
BLOCKS = [("1996-07-01", "2000-12-31"), ("2001-01-01", "2005-12-31"), ("2006-01-01", "2010-12-31"),
          ("2011-01-01", "2015-12-31"), ("2016-01-01", "2020-12-31"), ("2021-01-01", END)]
lines = []


def log(s=""):
    print(s)
    lines.append(str(s))


def load(synthetic=False):
    if synthetic:
        rng = np.random.default_rng(3)
        idx = pd.bdate_range(START, END)
        z = rng.standard_normal((len(idx), 2))
        a = 0.015 * z[:, 0]
        b = 0.018 * (0.75 * z[:, 0] + np.sqrt(1 - 0.75 ** 2) * z[:, 1])
        return pd.DataFrame({"kospi": 1000 * np.cumprod(1 + a), "kosdaq": 1000 * np.cumprod(1 + b)}, index=idx)
    import FinanceDataReader as fdr
    ks = fdr.DataReader("KS11", START, END)["Close"]
    kq = fdr.DataReader("KQ11", START, END)["Close"]
    return pd.concat([ks, kq], axis=1, keys=["kospi", "kosdaq"]).dropna()


def cagr(p):
    years = (p.index[-1] - p.index[0]).days / 365.25
    return (p.iloc[-1] / p.iloc[0]) ** (1 / years) - 1


def window(px, s, e=END):
    """s 직전 거래일 종가에서 출발하는 구간(그 전 거래일이 없으면 첫날부터)."""
    before = px.index[px.index < pd.Timestamp(s)]
    return px.loc[(before[-1] if len(before) else px.index[0]):e]


def mdd(p):
    dd = p / p.cummax() - 1
    return dd.min(), dd.idxmin(), p[:dd.idxmin()].idxmax()


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--synthetic", action="store_true")
    a = ap.parse_args()
    os.makedirs(OUT, exist_ok=True)
    px = load(a.synthetic)
    r = px.pct_change().dropna()
    log(f"데이터: {px.index[0]:%Y-%m-%d} ~ {px.index[-1]:%Y-%m-%d}, 두 지수가 모두 있는 {len(px)}거래일")
    pd.set_option("display.width", 220)
    pd.set_option("display.max_columns", 20)

    log("\n[1] 전체 기간")
    for k, name in [("kospi", "코스피"), ("kosdaq", "코스닥")]:
        p = px[k]
        m, trough, peak = mdd(p)
        after = p[p.index > peak]
        rec = after[after >= p[peak]]
        rec_txt = f"{rec.index[0]:%Y-%m-%d} 회복" if len(rec) else "데이터 끝까지 회복 못 함"
        log(f"  {name}: {p.iloc[0]:.2f} → {p.iloc[-1]:.2f} ({p.iloc[-1] / p.iloc[0]:.2f}배), 연복리 {cagr(p):.2%}, "
            f"연 변동성 {r[k].std() * np.sqrt(252):.1%}, MDD {m:.1%} (고점 {peak:%Y-%m-%d} {p[peak]:.2f}, "
            f"바닥 {trough:%Y-%m-%d}), 고점 {rec_txt}")
    log(f"  일별 수익률 상관계수 {r['kospi'].corr(r['kosdaq']):.3f}")
    rm = px.resample("ME").last().pct_change().dropna()
    log(f"  월별 수익률 상관계수 {rm['kospi'].corr(rm['kosdaq']):.3f} ({len(rm)}개월)")
    beta = r["kosdaq"].cov(r["kospi"]) / r["kospi"].var()
    log(f"  코스닥의 코스피 베타(일별) {beta:.2f}")

    log("\n[2] 5년 단위 구간")
    rows = []
    for s, e in BLOCKS:
        p = px.loc[s:e]
        base = window(px, s, e)          # 구간 수익률은 직전 거래일 종가에서 출발한다
        rr = base.pct_change().dropna()
        rw = base.resample("W-FRI").last().pct_change().dropna()
        rows.append({"구간": f"{p.index[0]:%Y.%m}~{p.index[-1]:%Y.%m}",
                     "코스피 연복리(%)": cagr(base["kospi"]) * 100, "코스닥 연복리(%)": cagr(base["kosdaq"]) * 100,
                     "차이(%p)": (cagr(base["kosdaq"]) - cagr(base["kospi"])) * 100,
                     "일별 상관": rr["kospi"].corr(rr["kosdaq"]),
                     "주별 상관": rw["kospi"].corr(rw["kosdaq"]),
                     "하루 늦은 상관": rr["kosdaq"].corr(rr["kospi"].shift(1)),
                     "변동성 비율(코스닥/코스피)": rr["kosdaq"].std() / rr["kospi"].std(),
                     "베타": rr["kosdaq"].cov(rr["kospi"]) / rr["kospi"].var()})
    log(pd.DataFrame(rows).to_string(index=False, float_format=lambda v: f"{v:.2f}"))
    log("  (하루 늦은 상관 = 오늘 코스닥과 어제 코스피의 상관. 코스닥 가격이 늦게 반영될수록 커진다)")
    rw_all = px.resample("W-FRI").last().pct_change().dropna()
    log(f"  전체 주별 상관 {rw_all['kospi'].corr(rw_all['kosdaq']):.3f}")

    roll = r["kospi"].rolling(252).corr(r["kosdaq"]).dropna()
    log(f"\n  252거래일 이동 상관계수: 중앙값 {roll.median():.2f}, 최저 {roll.min():.2f} ({roll.idxmin():%Y-%m-%d}), "
        f"최고 {roll.max():.2f} ({roll.idxmax():%Y-%m-%d}), 0.5 미만인 날 비율 {(roll < 0.5).mean():.1%}")
    for y in range(1997, 2027):
        sub = roll[roll.index.year == y]
        if len(sub):
            log(f"    {y}년: 연말 {sub.iloc[-1]:.2f}, 최저 {sub.min():.2f}, 최고 {sub.max():.2f}, 0.5 미만 {int((sub < 0.5).sum())}일")

    log("\n[3] 코스피가 크게 움직인 날 코스닥은")
    out = []
    for label, mask in [("코스피 -3% 이하", r["kospi"] <= -0.03), ("코스피 -1%~-3%", (r["kospi"] > -0.03) & (r["kospi"] <= -0.01)),
                        ("코스피 -1%~+1%", (r["kospi"] > -0.01) & (r["kospi"] < 0.01)),
                        ("코스피 +1%~+3%", (r["kospi"] >= 0.01) & (r["kospi"] < 0.03)), ("코스피 +3% 이상", r["kospi"] >= 0.03)]:
        g = r[mask]
        out.append({"코스피가": label, "일수": len(g), "코스피 평균(%)": g["kospi"].mean() * 100,
                    "코스닥 평균(%)": g["kosdaq"].mean() * 100, "같은 방향 비율(%)": (np.sign(g["kosdaq"]) == np.sign(g["kospi"])).mean() * 100,
                    "코스닥이 더 크게 움직인 비율(%)": (g["kosdaq"].abs() > g["kospi"].abs()).mean() * 100})
    log(pd.DataFrame(out).to_string(index=False, float_format=lambda v: f"{v:.2f}"))
    for label, mask in [("하락일(코스피 < 0)", r["kospi"] < 0), ("상승일(코스피 > 0)", r["kospi"] > 0)]:
        g = r[mask]
        b = g["kosdaq"].cov(g["kospi"]) / g["kospi"].var()
        log(f"  {label}만 쓴 베타 {b:.2f}, 상관 {g['kospi'].corr(g['kosdaq']):.2f} ({len(g)}일)")
    for y0, y1 in [("1996-07-01", "2000-12-31"), ("2001-01-01", "2008-12-31"), ("2009-01-01", END)]:
        g = r.loc[y0:y1]
        dn, up = g[g["kospi"] < 0], g[g["kospi"] > 0]
        log(f"  {y0[:4]}~{y1[:4]}: 하락일 베타 {dn['kosdaq'].cov(dn['kospi']) / dn['kospi'].var():.2f}, "
            f"상승일 베타 {up['kosdaq'].cov(up['kospi']) / up['kospi'].var():.2f}")
        big = g[g["kospi"] <= -0.03]
        log(f"  {y0[:4]}~{y1[:4]}: 코스피 -3% 이하 {len(big)}일, 그날 코스닥 평균 {big['kosdaq'].mean():.2%}, "
            f"코스닥도 하락 {(big['kosdaq'] < 0).mean():.1%}, 코스닥이 더 크게 하락 {(big['kosdaq'] < big['kospi']).mean():.1%}")
    md = rm[rm["kospi"] < 0]
    log(f"  월별: 코스피가 떨어진 {len(md)}개월 중 코스닥도 떨어진 달 {(md['kosdaq'] < 0).mean():.1%}")
    mu = rm[rm["kospi"] > 0]
    log(f"  월별: 코스피가 오른 {len(mu)}개월 중 코스닥도 오른 달 {(mu['kosdaq'] > 0).mean():.1%}")
    log(f"  월별 베타: 코스피가 떨어진 달 {md['kosdaq'].cov(md['kospi']) / md['kospi'].var():.2f}, "
        f"오른 달 {mu['kosdaq'].cov(mu['kospi']) / mu['kospi'].var():.2f}")

    log("\n[4] 코스피 하락장(고점 대비 -20% 이상)마다 같은 기간 코스닥")
    p = px["kospi"]
    dd = p / p.cummax() - 1
    episodes, in_bear, peak_d = [], False, p.index[0]
    run_max = p.iloc[0]
    for d, v in p.items():
        if v >= run_max:
            if in_bear:
                episodes.append((peak_d, d))
                in_bear = False
            run_max, peak_d = v, d
        elif v / run_max - 1 <= -0.20:
            in_bear = True
    if in_bear:
        episodes.append((peak_d, None))
    rows = []
    for pk, rc in episodes:
        seg = p[pk:rc] if rc is not None else p[pk:]
        tr = seg.idxmin()
        kq_pk_tr = px.loc[tr, "kosdaq"] / px.loc[pk, "kosdaq"] - 1
        kq_seg = px["kosdaq"][pk:tr]
        kq_worst = (kq_seg / kq_seg.cummax() - 1).min()
        rows.append({"코스피 고점": f"{pk:%Y-%m-%d}", "코스피 바닥": f"{tr:%Y-%m-%d}",
                     "코스피 하락(%)": (p[tr] / p[pk] - 1) * 100, "같은 기간 코스닥(%)": kq_pk_tr * 100,
                     "그 기간 코스닥 최대 낙폭(%)": kq_worst * 100,
                     "코스피 회복": f"{rc:%Y-%m-%d}" if rc is not None else "미회복"})
    bears = pd.DataFrame(rows)
    log(bears.to_string(index=False, float_format=lambda v: f"{v:.1f}"))

    log("\n[5] 해마다 누가 더 올랐나")
    yr = px.resample("YE").last()
    yr = pd.concat([px.iloc[[0]], yr])
    yret = yr.pct_change().dropna()
    yret.index = yret.index.year
    yret["차이(%p)"] = (yret["kosdaq"] - yret["kospi"]) * 100
    log((yret[["kospi", "kosdaq"]] * 100).assign(**{"차이(%p)": yret["차이(%p)"]}).to_string(float_format=lambda v: f"{v:.1f}"))
    full = yret.loc[1997:2025]
    log(f"  1997~2025년 29해 중 코스닥이 더 오른 해 {(full['kosdaq'] > full['kospi']).sum()}해, "
        f"차이의 절댓값 중앙값 {full['차이(%p)'].abs().median():.1f}%p")
    log(f"  두 지수의 연간 수익률 부호가 같은 해 {(np.sign(full['kosdaq']) == np.sign(full['kospi'])).sum()}해")
    for s in ["1996-07-01", "2001-01-01", "2009-01-01", "2016-01-01"]:
        q = window(px, s)
        q24 = window(px, s, "2024-12-31")
        log(f"  {s[:7]} 시작: 코스피 연복리 {cagr(q['kospi']):.2%}, 코스닥 {cagr(q['kosdaq']):.2%} "
            f"(2024년 말까지만: 코스피 {cagr(q24['kospi']):.2%}, 코스닥 {cagr(q24['kosdaq']):.2%})")
    ratio = px["kosdaq"] / px["kospi"]
    ratio = ratio / ratio.iloc[0]
    log(f"  코스닥/코스피 누적 비율: 최고 {ratio.max():.2f} ({ratio.idxmax():%Y-%m-%d}), 끝 {ratio.iloc[-1]:.3f}")

    log("\n[6] 반반 섞으면 변동성이 얼마나 줄어드나 (매일 반반으로 맞춘다고 가정)")
    s1, s2 = r["kospi"].std() * np.sqrt(252), r["kosdaq"].std() * np.sqrt(252)
    rho = r["kospi"].corr(r["kosdaq"])
    mix = 0.5 * r["kospi"] + 0.5 * r["kosdaq"]
    formula = np.sqrt(0.25 * s1 ** 2 + 0.25 * s2 ** 2 + 2 * 0.25 * rho * s1 * s2)
    log(f"  코스피 {s1:.1%}, 코스닥 {s2:.1%}, 가중평균 {0.5 * s1 + 0.5 * s2:.1%}, 식으로 {formula:.1%}, "
        f"실제 반반 {mix.std() * np.sqrt(252):.1%}")
    ks_dd = (px["kospi"] / px["kospi"].cummax() - 1).min()
    mix_px = (1 + mix).cumprod()
    mix_dd = mix_px / mix_px.cummax() - 1
    log(f"  MDD: 코스피 {ks_dd:.1%}, 반반 {mix_dd.min():.1%} "
        f"(고점 {mix_px[:mix_dd.idxmin()].idxmax():%Y-%m-%d}, 바닥 {mix_dd.idxmin():%Y-%m-%d})")

    extra_checks(px, r, roll, synthetic=a.synthetic)

    with open(os.path.join(OUT, "kospi_vs_kosdaq.txt"), "w", encoding="utf-8") as fh:
        fh.write("\n".join(lines) + "\n")
    plot(px, roll)


def bear_episodes(p, threshold=-0.20, end_rule="new_high"):
    """코스피 하락장 구간. end_rule='new_high': 직전 최고점을 다시 넘을 때까지 한 구간.
    end_rule='rebound': 바닥에서 20% 반등하면 그 하락장이 끝난 것으로 본다."""
    eps, peak_d, peak_v, in_bear, trough_d, trough_v = [], p.index[0], p.iloc[0], False, None, None
    for d, v in p.items():
        if not in_bear:
            if v >= peak_v:
                peak_d, peak_v = d, v
            elif v / peak_v - 1 <= threshold:
                in_bear, trough_d, trough_v = True, d, v
        else:
            if v < trough_v:
                trough_d, trough_v = d, v
            done = v >= peak_v if end_rule == "new_high" else v / trough_v - 1 >= 0.20
            if done:
                eps.append((peak_d, trough_d))
                in_bear, peak_d, peak_v = False, d, v
    if in_bear:
        eps.append((peak_d, trough_d))
    return eps


def extra_checks(px, r, roll, synthetic=False):
    log("\n[7] 해석을 확인하기 위한 추가 계산")
    # 7-1 이동 상관계수와 같은 창 안의 코스피 최대 낙폭
    p = px["kospi"]
    win_mdd = p.rolling(252).apply(lambda x: (x / np.maximum.accumulate(x) - 1).min(), raw=True).reindex(roll.index)
    big = win_mdd <= -0.20
    log(f"  직전 1년 안에 코스피 -20% 이상 하락이 있던 날: 이동 상관 중앙값 {roll[big].median():.2f} ({int(big.sum())}일), "
        f"없던 날: {roll[~big].median():.2f} ({int((~big).sum())}일)")
    top = roll[roll >= 0.87]
    log(f"  이동 상관 0.87 이상인 날 {len(top)}일 중 직전 1년 안에 코스피 -20% 이상 하락을 담은 날 {(win_mdd[top.index] <= -0.20).mean():.1%}")
    for y in [2003, 2009, 2020, 2022, 2023]:
        sub = roll[roll.index.year == y]
        d = sub.idxmax()
        log(f"    {y}년 최고 {sub.max():.2f} ({d:%Y-%m-%d}), 그 창의 코스피 최대 낙폭 {win_mdd[d]:.1%}")
    for w in (126, 504):
        rw = r["kospi"].rolling(w).corr(r["kosdaq"]).dropna()
        log(f"  이동 창 {w}거래일: 중앙값 {rw.median():.2f}")
    # 7-2 연도별 하락일·상승일 베타
    cnt, tot = 0, 0
    for y, g in r.groupby(r.index.year):
        dn, up = g[g["kospi"] < 0], g[g["kospi"] > 0]
        if len(dn) > 20 and len(up) > 20:
            tot += 1
            cnt += int(dn["kosdaq"].cov(dn["kospi"]) / dn["kospi"].var() > up["kosdaq"].cov(up["kospi"]) / up["kospi"].var())
    log(f"  해마다 따로 구하면 하락일 베타가 상승일 베타보다 큰 해: {tot}해 중 {cnt}해")
    mid = r[r["kospi"].abs() <= 0.03]
    dn, up = mid[mid["kospi"] < 0], mid[mid["kospi"] > 0]
    log(f"  코스피 ±3% 이내 날만: 하락일 베타 {dn['kosdaq'].cov(dn['kospi']) / dn['kospi'].var():.2f}, "
        f"상승일 베타 {up['kosdaq'].cov(up['kospi']) / up['kospi'].var():.2f}")
    for y0, y1 in [("1996-07-01", "2000-12-31"), ("2001-01-01", "2008-12-31"), ("2009-01-01", END)]:
        g = r.loc[y0:y1]
        bd, bu = g[g["kospi"] <= -0.03], g[g["kospi"] >= 0.03]
        log(f"  {y0[:4]}~{y1[:4]}: -3% 이하 날 코스피 평균 {bd['kospi'].mean():.2%}, 코스닥 {bd['kosdaq'].mean():.2%} "
            f"(비율 {bd['kosdaq'].mean() / bd['kospi'].mean():.2f}); +3% 이상 날 코스피 {bu['kospi'].mean():.2%}, "
            f"코스닥 {bu['kosdaq'].mean():.2%} (비율 {bu['kosdaq'].mean() / bu['kospi'].mean():.2f})")
    for th in (0.02, 0.04):
        bd, bu = r[r["kospi"] <= -th], r[r["kospi"] >= th]
        log(f"  기준 ±{th:.0%}: 하락 {len(bd)}일 코스닥도 하락 {(bd['kosdaq'] < 0).mean():.1%}, 평균 비율 {bd['kosdaq'].mean() / bd['kospi'].mean():.2f}; "
            f"상승 {len(bu)}일 평균 비율 {bu['kosdaq'].mean() / bu['kospi'].mean():.2f}")
    # 7-3 1996~2000년 수익률 기간을 늘린 상관
    e = px.loc[:"2000-12-31"]
    lag = r.loc[:"2000-12-31"]
    log(f"  1996~2000년: 일별 {lag['kospi'].corr(lag['kosdaq']):.2f}, 5일 {e.pct_change(5)['kospi'].corr(e.pct_change(5)['kosdaq']):.2f}, "
        f"월별 {e.resample('ME').last().pct_change()['kospi'].corr(e.resample('ME').last().pct_change()['kosdaq']):.2f}")
    for s0, e0 in BLOCKS[1:]:
        m = window(px, s0, e0).resample("ME").last().pct_change().dropna()
        log(f"    {s0[:4]}~{e0[:4]} 월별 상관 {m['kospi'].corr(m['kosdaq']):.2f}")
    h2 = px.loc[:"1996-12-31"]
    log(f"  1996년 7~12월: 코스피 {h2['kospi'].iloc[-1] / h2['kospi'].iloc[0] - 1:.1%}, 코스닥 {h2['kosdaq'].iloc[-1] / h2['kosdaq'].iloc[0] - 1:.1%}")
    # 7-4 하락장 정의 바꾸기
    for th, rule in [(-0.20, "new_high"), (-0.20, "rebound"), (-0.15, "new_high"), (-0.25, "new_high")]:
        eps = bear_episodes(p, th, rule)
        chg = [px.loc[t, "kosdaq"] / px.loc[pk, "kosdaq"] - 1 for pk, t in eps]
        log(f"  하락장 기준 {th:.0%}, 끝내는 규칙 {rule}: {len(eps)}번, 코스닥이 오른 구간 {sum(c > 0 for c in chg)}번, "
            f"코스닥 하락이 20% 미만인 구간 {sum(-0.20 < c <= 0 for c in chg)}번")
        if rule == "rebound":
            for (pk, t), c in zip(eps, chg):
                if c > -0.20:
                    log(f"    {pk:%Y-%m-%d}→{t:%Y-%m-%d}: 코스피 {p[t] / p[pk] - 1:.1%}, 코스닥 {c:+.1%}")
    # 7-5 누적 비율(같은 돈을 넣었을 때 코스닥 쪽 ÷ 코스피 쪽)의 연말 값과 시기별 기여
    ratio = (px["kosdaq"] / px["kosdaq"].iloc[0]) / (px["kospi"] / px["kospi"].iloc[0])
    ye = ratio.resample("YE").last()
    log("  연말 누적 비율: " + ", ".join(f"{d.year} {v:.3f}" for d, v in ye.items()))
    lr = np.log(pd.concat([pd.Series([1.0], index=[px.index[0]]), ye]))
    contrib = lr.diff().dropna()
    contrib.index = ye.index.year
    total = np.log(ratio.iloc[-1])
    for name, yrs in [("1996~1997", [1996, 1997]), ("1998", [1998]), ("1999~2000", [1999, 2000]), ("2001", [2001]),
                      ("2002~2004", [2002, 2003, 2004]), ("2005", [2005]), ("2006~2008", [2006, 2007, 2008]),
                      ("2009~2024", list(range(2009, 2025))), ("2025~2026", [2025, 2026])]:
        c = contrib.loc[yrs].sum()
        log(f"    {name}: 로그 기여 {c:+.3f} (비율 ×{np.exp(c):.2f}, 전체의 {c / total:.0%})")
    lo = ratio["2009":"2024"]
    log(f"  2009~2024년 누적 비율 최저 {lo.min():.3f} ({lo.idxmin():%Y-%m-%d}), 최고 {lo.max():.3f} ({lo.idxmax():%Y-%m-%d})")
    # 7-6 반반 포트폴리오의 낙폭 비교
    mix = 0.5 * r["kospi"] + 0.5 * r["kosdaq"]
    mpx = (1 + mix).cumprod()
    m_dd = mpx / mpx.cummax() - 1
    mt = m_dd.idxmin()
    mp = mpx[:mt].idxmax()
    log(f"  반반 MDD 구간 {mp:%Y-%m-%d}→{mt:%Y-%m-%d}: 코스피 {p[mt] / p[mp] - 1:.1%}, 코스닥 {px.loc[mt, 'kosdaq'] / px.loc[mp, 'kosdaq'] - 1:.1%}")
    kdd = p / p.cummax() - 1
    kt = kdd.idxmin()
    kp = p[:kt].idxmax()
    log(f"  코스피 MDD 구간 {kp:%Y-%m-%d}→{kt:%Y-%m-%d}: 반반 {mpx[kt] / mpx[kp] - 1:.1%}")
    for label, freq in [("매월", "ME"), ("매년", "YE")]:
        w = px / px.shift(1)
        val, out = 1.0, []
        hold = np.array([0.5, 0.5])
        last_period = None
        for d, g in w.iloc[1:].iterrows():
            period = d.to_period("M" if freq == "ME" else "Y")
            if last_period is not None and period != last_period:
                hold = np.array([0.5, 0.5]) * hold.sum()
            hold = hold * g.values
            last_period = period
            out.append(hold.sum())
        s_ = pd.Series(out)
        log(f"  반반 {label} 재조정 MDD {(s_ / s_.cummax() - 1).min():.1%}")
    bh = 0.5 * px["kospi"] / px["kospi"].iloc[0] + 0.5 * px["kosdaq"] / px["kosdaq"].iloc[0]
    log(f"  반반으로 사서 그대로 둔 MDD {(bh / bh.cummax() - 1).min():.1%}")
    # 7-7 1995년 고점 기준 코스피
    if not synthetic:
        import FinanceDataReader as fdr
        k95 = fdr.DataReader("KS11", "1995-01-01", END)["Close"]
        pk95 = k95[:"1996-06-30"].idxmax()
        dd95 = k95[pk95:] / k95[pk95] - 1
        rec = k95[pk95:][k95[pk95:] >= k95[pk95]]
        rec = rec[rec.index > dd95.idxmin()]
        log(f"  1995년 이후 코스피 고점 {pk95:%Y-%m-%d} {k95[pk95]:.2f}, 1996-07-01 은 그보다 {px['kospi'].iloc[0] / k95[pk95] - 1:.1%}, "
            f"그 고점 기준 MDD {dd95.min():.1%}, 회복 {rec.index[0]:%Y-%m-%d}")


def plot(px, roll):
    import matplotlib
    matplotlib.use("Agg")
    import matplotlib.pyplot as plt
    fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10.5, 6.6), sharex=True, gridspec_kw={"height_ratios": [1.6, 1]})
    norm = px / px.iloc[0]
    ax1.plot(norm.index, norm["kospi"], color="#1f5fbf", linewidth=1.3, label="KOSPI")
    ax1.plot(norm.index, norm["kosdaq"], color="#8c8c8c", linewidth=1.3, label="KOSDAQ")
    ax1.set_yscale("log")
    ticks = [0.25, 0.5, 1, 2, 4, 8]
    ax1.set_yticks(ticks, [f"{t:g}" for t in ticks])
    ax1.minorticks_off()
    ax1.set_xlim(px.index[0], px.index[-1])
    ax1.axhline(1, color="#333333", linewidth=0.7)
    ax1.set_ylabel("Growth of 1 (log scale)")
    ax1.set_title(f"KOSPI vs KOSDAQ, price index ({px.index[0]:%Y-%m} to {px.index[-1]:%Y-%m})", fontsize=10.5)
    ax1.legend(frameon=False, fontsize=9, loc="upper left")
    ax2.plot(roll.index, roll, color="#b22222", linewidth=1.1)
    ax2.axhline(roll.median(), color="#8c8c8c", linewidth=0.8, linestyle="--")
    ax2.text(roll.index[5], roll.median() + 0.02, f"median {roll.median():.2f}", fontsize=8.5, color="#555555", va="bottom")
    ax2.set_ylim(0, 1)
    ax2.set_ylabel("1-year rolling corr.\n(daily returns)")
    for ax in (ax1, ax2):
        ax.spines[["top", "right"]].set_visible(False)
        ax.grid(axis="y", color="#e6e6e6", linewidth=0.6)
        ax.set_axisbelow(True)
    fig.tight_layout()
    fig.savefig(os.path.join(OUT, "67_kospi_vs_kosdaq.png"), dpi=130)
    plt.close(fig)


if __name__ == "__main__":
    main()
