← 검증 방법

코드 감사 & 참고용 비교

1. 백테스트 코드 — 직접 읽고 감사하세요

아래 코드를 복사해 다른 AI에게 물어보세요: “이 코드에 룩어헤드(미래 데이터 누수)가 있나? 결론이 이 코드에서 나오나?” 우리 결론을 믿지 말고 코드를 감사하는 것이 가장 정직한 검증입니다.

✓ 룩어헤드 자동검사: 의심 패턴 없음
  • ✓ ret[t]를 거래 결정 이전에 적용 (포인트인타임 패턴 확인)

※ 휴리스틱 검사이며 증명이 아닙니다. 정적 패턴 매칭일 뿐, 사람·다른 AI의 감사를 대체하지 않습니다.

"""Sensitivity / robustness: does '60/0/40 defends, C earns more' survive
when we change the assumptions one at a time? Rolling 10y windows, monthly.
Reports whether the QUALITATIVE conclusion holds, not just point numbers.
"""
import numpy as np, pandas as pd
SIDE, MONTHLY = 0.00065, 400_000
px = pd.read_pickle("/home/claude/alphix/ips_prices.pkl").dropna(subset=["069500.KS"])

def build(bond_rate, use_fx, start):
    us = (px["SPY"]*px["KRW=X"]) if use_fx else px["SPY"]
    m = pd.DataFrame({"US": us.resample("ME").last(),
                      "KR": px["069500.KS"].resample("ME").last()}).dropna()
    n=len(m); m["BOND"]=100.0*((1+bond_rate)**(np.arange(n)/12))
    m=m.loc[start:]
    return m.pct_change().dropna()[["US","KR","BOND"]].values

def sim(ret,w,band=0.10):
    A=["US","KR","BOND"]; tw=np.array([w.get(a,0.0) for a in A]); hold=np.zeros(3); contrib=0.0
    vals,contribs,eq=[],[],[1.0]
    for t in range(ret.shape[0]):
        prev=hold.sum(); hold=hold*(1+ret[t]); eq.append(eq[-1]*(hold.sum()/prev) if prev>0 else eq[-1])
        cash=MONTHLY; contrib+=MONTHLY; total=hold.sum()+cash
        if band and hold.sum()>0 and np.max(np.abs(hold/total-tw))>band:
            sells=np.clip(hold-total*tw,0,None); hold-=sells; cash+=sells.sum()*(1-SIDE)
        deficit=np.clip(total*tw-hold,0,None)
        if deficit.sum()>0: buy=deficit*min(1.0,cash/deficit.sum()); hold+=buy/(1+SIDE); cash-=buy.sum()
        hold[np.argmax(tw)]+=cash/(1+SIDE); vals.append(hold.sum()); contribs.append(contrib)
    v=np.array(vals); c=np.array(contribs); e=np.array(eq[1:])
    return v[-1]/c[-1], float((e/np.maximum.accumulate(e)-1).min())

VARS={"현행 60/20/20":{"US":.6,"KR":.2,"BOND":.2},
      "방어 60/0/40":{"US":.6,"BOND":.4},
      "공격 100%US":{"US":1.0}}

def windows(R,w,W=120):
    res=[(sim(R[s:s+W],w)) for s in range(0,len(R)-W+1)]
    mult=np.array([r[0] for r in res]); mdd=np.array([r[1] for r in res])
    return np.median(mult), np.median(mdd), mult.min(), mdd.min()

SCEN=[("기준(채권2.75%,환율O,2007~)",2.75,True,"2007-01-31"),
      ("채권0%(현금)",0.0,True,"2007-01-31"),
      ("채권5%",5.0,True,"2007-01-31"),
      ("환율무시(원화효과제거)",2.75,False,"2007-01-31"),
      ("2010년시작",2.75,True,"2010-01-31"),
      ("2015년시작",2.75,True,"2015-01-31")]

print(f"{'시나리오':<28}{'변형':<16}{'배수중앙':>9}{'MDD중앙':>9}{'배수최악':>9}{'MDD최악':>9}  결론유지?")
print("-"*100)
for name,br,fx,st in SCEN:
    R=build(br/100,fx,st)
    row={}
    for vn,w in VARS.items():
        med_m,med_d,wm,wd=windows(R,w)
        row[vn]=(med_m,med_d,wm,wd)
        print(f"{name:<28}{vn:<16}{med_m:>9.2f}{med_d*100:>8.1f}%{wm:>9.2f}{wd*100:>8.1f}%")
    # qualitative checks
    defends = row["방어 60/0/40"][1] > row["현행 60/20/20"][1]   # shallower MDD (less negative)
    earns   = row["공격 100%US"][0] > row["현행 60/20/20"][0]
    print(f"{'':28}{'→ 60/0/40 방어우위:':<16}{str(defends):>9}   100%US 수익우위: {earns}\n")

2. 참고용 비교 — 검증이 아님

🚫 이것은 독립 검증이 아닙니다. 아래 숫자는 우리 자체 백테스트 코드를 벤치마크 ETF에 돌린 결과입니다 — 양쪽에 같은 버그가 있으면 같이 틀립니다. 유일하게 정직한 용도는, 이 숫자를 들고 진짜 외부 계산기(testfol.io 등)에서 직접 대조하는 것입니다. 그 대조는 당신의 눈이 해야 검증이 성립합니다.

현행 60/20/20

외부 입력: SPY 60 / EWY 20 / SHY 20 · 월 $300 · 10% 밴드 · 2007-02~

방어 60/0/40

외부 입력: SPY 60 / SHY 40 · 월 $300 · 10% 밴드 · 2007-02~

공격 100% S&P500

외부 입력: SPY 100 · 월 $300 · 10% 밴드 · 2007-02~

외부 계산기는 미국상장 ETF(달러)를 쓰고 우리 시스템은 국내상장(원화)을 쓰므로 환율 차이로 절대 수치가 다릅니다. 대조의 핵심은 소수점이 아니라 방향 — 방어형이 MDD를 줄이는가, 공격형이 더 버는가입니다. 숫자가 크게 어긋나면 우리를 잡은 것이니 thumbs-down으로 알려주세요.

본 페이지는 방법론 투명성을 위한 것이며 투자 추천이 아닙니다. 룩어헤드 자동검사는 휴리스틱 패턴 매칭이며 코드 정확성을 보증하지 않습니다.