Skip to main content

2000년 이후 FED PUT의 미국증시 왜곡 효과

미국 주식 투자에서 무조건적 줍줍+존버 전략이 합리적이었던 이유

Data
Macro
Author

gitSAM

Published

October 2, 2026

1 나라도 무지성 대풀롱(Buy & Hold)한다

2000년 이후 미국 증시 데이터가 증명하는 사실은 단순하다. 연준은 위기 때마다 예외 없이 구원투수로 등판했고, 그 직후 주식시장은 평시보다 높은 일별 평균 수익률(NDX 기준 +0.32%/일)로 V자 폭등했다. NBER의 공식 침체기 (USREC) 585거래일 중 230일(39%)은 사실상 ‘연준이 발행한 무료 풋옵션’ 위에서 펼쳐진 랠리 구간이었으며, 이 구간을 제거하면 NDX의 침체기 일별 평균 손실은 -0.004%에서 -0.213%로 55배 악화된다.

월가는 이런 Free Lunch 패턴을 학습했다. 침체가 와도 연준이 바닥을 깔아주고, 확장기엔 유동성이 주가를 밀어올린다. 양쪽 모두 롱 포지션에 유리하게 설계된 게임이다. 확률적 기대값만 놓고 보면 숏은 순수 침체기 355거래일(전체의 5.3%)에만 유효하고, 나머지 94.7%의 시간은 롱이 지배한다. 구조적으로 ’기울어진 운동장’에서 합리적 전략이란, 풋 프리미엄 없이 중앙은행의 꼬리위험 보증을 등에 업고 무지성 대풀롱을 유지하는 것이다.

2000년 거래 시작일(2000-01-03) 이후를 기준으로 미국 주식시장 3대 대표 벤치마크(W5000: 전체시장, GSPC: S&P 500, NDX: NASDAQ 100)에 대해 NBER의 공식 미국 실물경기침체국면(USREC)과 연준의 구원투수(Fed Put) 개입 효과를 보정한 USREC_REAL 국면의 일별 수익률 분포 및 기술통계를 비교 분석한다.

1.1 1980년 이후 주요 위기 사건 및 Fed Put 역사

시기 위기 사건 유발 사건 연준의 개입 방식 구조적 유산
1987년 10월 블랙 먼데이 포트폴리오 보험(알고리즘 매매)의 연쇄 투매 전격 금리 인하 및 무제한 유동성 공급 선언 ‘그린스펀 풋(Fed Put)’ 용어 공식 탄생
1998년 9월 LTCM 파산 위기 러시아 디폴트 발 퀀트 헤지펀드 채권 차익거래 붕괴 긴급 금리 3회 연속 인하 및 월가 채권단 구성 강제 2000년 닷컴 버블 고원지대의 기폭제 제공
2000년~2001년 닷컴 버블 붕괴 및 9.11 기술주 가격 붕괴 및 실물 경기 침체 기준금리 6.5% → 1.0%로 수직 인하, 9/11 직후 전격 긴급 인하 2000년대 중반 부동산 서브프라임 버블 잉태
2008년 글로벌 금융위기 서브프라임 모기지 부실 및 투자은행(리먼) 파산 제로금리(ZIRP) 도입 및 양적완화(QE 1,2,3) 최초 가동 대형 은행 구제 및 중앙은행 대차대조표의 영구적 비대화
2020년 3월 팬데믹 유동성 위기 전 세계 셧다운 및 미 국채시장 유동성 경색 무제한 QE, 회사채 직매입(SMCCF), MMF 지원 2021~2023년 40년 만의 글로벌 인플레이션 촉발

1.2 실물 지표 중심의 침체 판정과 금융 충격의 괴리

USREC는 주가나 금융 변동성이 아니라 실질 개인소득, 비농업 부문 고용, 산업 생산, 실질 제조업·도소매 판매 등 실물 경제 전반의 동시적·지속적 위축(수개월 이상 지속) 을 기준으로 침체를 정의한다.

  • 1987년 10월 블랙 먼데이: 하루 만에 주가가 20% 폭락했으나, 그린스펀 연준의 전격 금리 인하 및 무제한 유동성 공급 선언(‘그린스펀 풋’ 탄생)으로 고용과 생산 등 실물 펀더멘털로 전이되지 않아 NBER 침체 미발생(USREC=0 유지) 으로 귀결되었다.
  • 1990년 걸프전 및 유가 충격: 실업률 상승과 소비 급감 등 실물 침체가 명백히 확인되어 공식 침체(USREC=1) 로 판정되었다.
  • 1998년 9월 LTCM 파산 위기: 러시아 디폴트 발 금융 경색에 대응해 연준이 3회 연속 긴급 금리 인하를 단행하여 위기를 금융권 내에 격리시킴으로써 NBER 침체 미발생(USREC=0 유지) 되었다.

1.3 2000년 이후 집중 분석 배경: 극심화된 Fed Put과 Optimism Bias

2000년 이후 금융시장에서는 비전통적 통화정책(ZIRP, 양적완화 QE 1·2·3, 무제한 QE 및 회사채 직매입)으로 대표되는 연준의 전방위적 유동성 백스톱이 상시화되었다. 이로 인해 공식 NBER 침체 기간(수개월~1년 이상 지속) 내에서도 연준이 구원투수로 등판한 직후부터 주식시장은 바닥을 찍고 폭발적인 유동성 랠리를 펼치게 된다. 따라서 2000년 이후 데이터를 분석할 때 공식 USREC 지표를 그대로 사용하면 침체기 통계에 강력한 반등 랠리가 섞여 침체기 하방 위험이 극도로 과소평가되는 낙관 편향(Optimism Bias) 이 발생한다.

Code
from pathlib import Path
import duckdb
from IPython.core.pylabtools import figsize
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from IPython.display import display

# 1. DuckDB 데이터베이스 파일 경로 탐색 (동일 폴더, temp 폴더 등 독립 실행 완벽 지원)
db_candidates = [
    Path("usrec_real.duckdb"),
    Path("temp/usrec_real.duckdb"),
    Path.cwd() / "usrec_real.duckdb",
    Path.cwd() / "temp" / "usrec_real.duckdb",
]
db_path = next((p for p in db_candidates if p.exists()), None)

# 2. 시작 시점 설정 (2000년 거래 시작일인 2000-01-03부터 분석)
START_DATE = "2000-01-03"

# 3. 데이터 로드 (usrec_real.duckdb 우선 로드, 부재 시 Parquet 폴더 fallback)
if db_path is not None:
    print(f"DuckDB 데이터베이스 연동: {db_path}")
    con = duckdb.connect(str(db_path), read_only=True)
    df_db = con.execute("SELECT * FROM usrec_benchmark_daily ORDER BY date").df()
    con.close()
    
    df_db["date"] = pd.to_datetime(df_db["date"])
    df_db = df_db.set_index("date").sort_index().loc[START_DATE:]
    
    w5000 = df_db["W5000"].dropna()
    gspc = df_db["GSPC"].dropna()
    ndx = df_db["NDX"].dropna()
    usrec_series = df_db["USREC"].dropna()
else:
    print("Parquet 원본 데이터 fallback 로드")
    curr = Path.cwd().resolve()
    data_dir = next((p for p in [curr, curr.parent, curr.parent.parent] if (p / "data").exists()), Path("data"))
    w5000 = pd.read_parquet(data_dir / "yfinance" / "W5000.parquet")["W5000"].loc[START_DATE:].dropna().sort_index()
    gspc = pd.read_parquet(data_dir / "yfinance" / "GSPC.parquet")["GSPC"].loc[START_DATE:].dropna().sort_index()
    ndx = pd.read_parquet(data_dir / "yfinance" / "NDX.parquet")["NDX"].loc[START_DATE:].dropna().sort_index()
    usrec_series = pd.read_parquet(data_dir / "fred" / "USREC.parquet")["USREC"].loc[START_DATE:].dropna().sort_index()

# 4. 일별 수익률 계산 (Dictionary 관리)
benchmarks = {
    "W5000": {"name": "Wilshire 5000 (Total Market)", "series": w5000, "ret": w5000.pct_change().dropna()},
    "GSPC": {"name": "S&P 500 (Large Cap)", "series": gspc, "ret": gspc.pct_change().dropna()},
    "NDX": {"name": "NASDAQ 100 (Tech Growth)", "series": ndx, "ret": ndx.pct_change().dropna()},
}

print(f"분석 시작일: {START_DATE}")
for sym, info in benchmarks.items():
    s, e = info['ret'].index.min().strftime('%Y-%m-%d'), info['ret'].index.max().strftime('%Y-%m-%d')
    print(f"- {sym:<6} ({info['name']}): {s} ~ {e} ({len(info['ret']):,} 거래일)")
DuckDB 데이터베이스 연동: usrec_real.duckdb
분석 시작일: 2000-01-03
- W5000  (Wilshire 5000 (Total Market)): 2000-01-04 ~ 2026-09-25 (6,664 거래일)
- GSPC   (S&P 500 (Large Cap)): 2000-01-04 ~ 2026-09-25 (6,664 거래일)
- NDX    (NASDAQ 100 (Tech Growth)): 2000-01-04 ~ 2026-09-25 (6,664 거래일)

2 공식 NBER 경기침체(USREC) 기준 일별 수익률 분포 (2000 ~ 현재)

공식 USREC(0: Expansion, 1: Recession)에 따라 2000년 이후 3대 벤치마크의 일별 수익률을 분리하고 기술통계와 히스토그램을 확인한다.

Code
# 1. 벤치마크별 USREC 기준 기술통계 테이블 출력
for sym, info in benchmarks.items():
    ret = info["ret"]
    u = usrec_series.asof(ret.index)
    info["usrec"] = u
    info["ret_norm"] = ret[u == 0]
    info["ret_rec"] = ret[u == 1]
    
    desc_df = pd.DataFrame({
        "Full Sample": ret.describe(percentiles=[0.25, 0.5, 0.75]),
        "Expansion (USREC=0)": info["ret_norm"].describe(percentiles=[0.25, 0.5, 0.75]),
        "Recession (USREC=1)": info["ret_rec"].describe(percentiles=[0.25, 0.5, 0.75]),
    })
    print(f"\n[USREC 기준 기술통계 - {info['name']}]")
    display(desc_df.round(6))

# 2. 1행 3열 서브플롯으로 W5000, GSPC, NDX 히스토그램 및 분위수 vline 시각화
fig, axes = plt.subplots(1, 3, figsize=(18, 5), sharey=True)
bins = np.linspace(-0.12, 0.12, 80)

for ax, (sym, info) in zip(axes, benchmarks.items()):
    r_norm = info["ret_norm"]
    r_rec = info["ret_rec"]
    
    q25_n, q75_n = r_norm.quantile([0.25, 0.75])
    q25_r, q75_r = r_rec.quantile([0.25, 0.75])
    
    ax.hist(r_norm, bins=bins, density=True, alpha=0.5, color="#1f77b4", label=f"Exp (N={len(r_norm):,})", edgecolor="white")
    ax.hist(r_rec, bins=bins, density=True, alpha=0.5, color="#d62728", label=f"Rec (N={len(r_rec):,})", edgecolor="white")
    
    ax.axvline(q25_n, color="#1f77b4", linestyle="--", linewidth=1.5, label=f"Exp 25% ({q25_n:.4f})")
    ax.axvline(q75_n, color="#1f77b4", linestyle="-.", linewidth=1.5, label=f"Exp 75% ({q75_n:.4f})")
    ax.axvline(q25_r, color="#d62728", linestyle="--", linewidth=1.5, label=f"Rec 25% ({q25_r:.4f})")
    ax.axvline(q75_r, color="#d62728", linestyle="-.", linewidth=1.5, label=f"Rec 75% ({q75_r:.4f})")
    
    ax.set_title(f"{sym}: {info['name']}", fontsize=12, fontweight="bold")
    ax.set_xlabel("Daily Return")
    ax.grid(True, linestyle=":", alpha=0.6)
    ax.legend(loc="upper right", fontsize=8, frameon=True)

axes[0].set_ylabel("Density")
plt.suptitle("Daily Return Distribution by USREC Regime (2000 ~ Present)", fontsize=14, fontweight="bold", y=1.02)
plt.tight_layout()
plt.show()

[USREC 기준 기술통계 - Wilshire 5000 (Total Market)]
Full Sample Expansion (USREC=0) Recession (USREC=1)
count 6664.000000 6079.000000 585.000000
mean 0.000336 0.000420 -0.000540
std 0.012375 0.010547 0.024263
min -0.122472 -0.070663 -0.122472
25% -0.004858 -0.004516 -0.011623
50% 0.000663 0.000696 -0.000091
75% 0.006199 0.005947 0.010819
max 0.114011 0.095681 0.114011

[USREC 기준 기술통계 - S&P 500 (Large Cap)]
Full Sample Expansion (USREC=0) Recession (USREC=1)
count 6664.000000 6079.000000 585.000000
mean 0.000325 0.000410 -0.000561
std 0.012154 0.010259 0.024272
min -0.119841 -0.066634 -0.119841
25% -0.004728 -0.004292 -0.011759
50% 0.000657 0.000685 -0.000084
75% 0.005906 0.005722 0.010350
max 0.115800 0.095154 0.115800

[USREC 기준 기술통계 - NASDAQ 100 (Tech Growth)]
Full Sample Expansion (USREC=0) Recession (USREC=1)
count 6664.000000 6079.000000 585.000000
mean 0.000461 0.000509 -0.000039
std 0.017200 0.015597 0.029043
min -0.121932 -0.097318 -0.121932
25% -0.006687 -0.006148 -0.016297
50% 0.001061 0.001116 0.000178
75% 0.008111 0.007763 0.014331
max 0.187713 0.187713 0.125799

3 연준(Fed Put) 개입 시점 보정: USREC_REAL 생성 및 왜곡 교정

2000년 이후 공식 침체기 내에서 연준이 전면적인 구원투수로 등판한 시점을 기점으로 0(정상/유동성 랠리)으로 전환한 USREC_REAL을 생성한다.

3.1 2000년 이후 3대 침체기 내 연준 구원투수 등판 시점

  1. 2001년 닷컴/9.11 침체 (2001-09-17):
    • 9/11 테러 직후 전격 긴급 50bp 인하 및 무제한 긴급 재할인 유동성 공급 단행.
    • 증시는 9월 21일 저점 후 10~11월 나스닥 +30% 이상 폭등 랠리.
    • 보정: 2001-09-17 ~ 2001-11-30 구간을 0으로 수정.
  2. 2008년 글로벌 금융위기 (2008-11-25):
    • Fed 역사상 최초의 양적완화인 QE1(MBS 5,000억 달러, 기관채 1,000억 달러 매입) 공식 발표.
    • (참고: 2008-12-16 ZIRP 제로금리 도입, 2009-03-18 국채 3,000억 달러 직접 매입 확대 발표).
    • 보정: 2008-11-25 ~ 2009-06-30 구간을 0으로 수정.
  3. 2020년 코로나19 팬데믹 (2020-03-23):
    • Fed 사상 최대 ‘무제한 QE (Unlimited QE)’ 및 회사채 직매입(PMCCF/SMCCF) 전격 발표.
    • 당일 미국 증시 역사적 최저점 기록 후 V자 대세 폭등 시작.
    • 보정: 2020-03-23 ~ 2020-04-30 구간을 0으로 수정.
Code
# 1. 벤치마크별 usrec_real 생성 및 기술통계 산출
for sym, info in benchmarks.items():
    ret = info["ret"]
    u = info["usrec"]
    
    u_real = u.copy().rename("USREC_REAL")
    # 2001년 9/11 긴급 인하 및 유동성 투입
    u_real.loc["2001-09-17":"2001-11-30"] = 0
    # 2008년 Fed 최초 QE1 발표
    u_real.loc["2008-11-25":"2009-06-30"] = 0
    # 2020년 Fed 무제한 QE 발표
    u_real.loc["2020-03-23":"2020-04-30"] = 0
    
    info["usrec_real"] = u_real
    info["ret_real_norm"] = ret[u_real == 0]
    info["ret_real_rec"] = ret[u_real == 1]
    
    desc_real_df = pd.DataFrame({
        "Full Sample": ret.describe(percentiles=[0.25, 0.5, 0.75]),
        "Exp/Rescue (USREC_REAL=0)": info["ret_real_norm"].describe(percentiles=[0.25, 0.5, 0.75]),
        "Real Rec (USREC_REAL=1)": info["ret_real_rec"].describe(percentiles=[0.25, 0.5, 0.75]),
    })
    print(f"\n[USREC_REAL 기술통계 - {info['name']}] (침체일수: {(u==1).sum():,}일 -> {(u_real==1).sum():,}일, {(u==1).sum() - (u_real==1).sum():,}일 축소)")
    display(desc_real_df.round(6))

# 2. 1행 3열 서브플롯으로 USREC_REAL 히스토그램 및 분위수 vline 시각화
fig, axes = plt.subplots(1, 3, figsize=(18, 5), sharey=True)
bins = np.linspace(-0.12, 0.12, 80)

for ax, (sym, info) in zip(axes, benchmarks.items()):
    r_rnorm = info["ret_real_norm"]
    r_rrec = info["ret_real_rec"]
    
    q25_rn, q75_rn = r_rnorm.quantile([0.25, 0.75])
    q25_rr, q75_rr = r_rrec.quantile([0.25, 0.75])
    
    ax.hist(r_rnorm, bins=bins, density=True, alpha=0.5, color="#1f77b4", label=f"Exp/Rescue (N={len(r_rnorm):,})", edgecolor="white")
    ax.hist(r_rrec, bins=bins, density=True, alpha=0.5, color="#d62728", label=f"Real Rec (N={len(r_rrec):,})", edgecolor="white")
    
    ax.axvline(q25_rn, color="#1f77b4", linestyle="--", linewidth=1.5, label=f"Exp 25% ({q25_rn:.4f})")
    ax.axvline(q75_rn, color="#1f77b4", linestyle="-.", linewidth=1.5, label=f"Exp 75% ({q75_rn:.4f})")
    ax.axvline(q25_rr, color="#d62728", linestyle="--", linewidth=1.5, label=f"Real Rec 25% ({q25_rr:.4f})")
    ax.axvline(q75_rr, color="#d62728", linestyle="-.", linewidth=1.5, label=f"Real Rec 75% ({q75_rr:.4f})")
    
    ax.set_title(f"{sym}: {info['name']}", fontsize=12, fontweight="bold")
    ax.set_xlabel("Daily Return")
    ax.grid(True, linestyle=":", alpha=0.6)
    ax.legend(loc="upper right", fontsize=8, frameon=True)

axes[0].set_ylabel("Density")
plt.suptitle("Daily Return Distribution by USREC_REAL Regime (Fed Rescue Adjusted, 2000 ~ Present)", fontsize=14, fontweight="bold", y=1.02)
plt.tight_layout()
plt.show()

[USREC_REAL 기술통계 - Wilshire 5000 (Total Market)] (침체일수: 585일 -> 355일, 230일 축소)
Full Sample Exp/Rescue (USREC_REAL=0) Real Rec (USREC_REAL=1)
count 6664.000000 6309.000000 355.000000
mean 0.000336 0.000477 -0.002174
std 0.012375 0.011278 0.024689
min -0.122472 -0.091453 -0.122472
25% -0.004858 -0.004644 -0.011650
50% 0.000663 0.000702 -0.000864
75% 0.006199 0.006136 0.007187
max 0.114011 0.095681 0.114011

[USREC_REAL 기술통계 - S&P 500 (Large Cap)] (침체일수: 585일 -> 355일, 230일 축소)
Full Sample Exp/Rescue (USREC_REAL=0) Real Rec (USREC_REAL=1)
count 6664.000000 6309.000000 355.000000
mean 0.000325 0.000461 -0.002088
std 0.012154 0.010992 0.024925
min -0.119841 -0.089295 -0.119841
25% -0.004728 -0.004455 -0.011933
50% 0.000657 0.000697 -0.001052
75% 0.005906 0.005849 0.006949
max 0.115800 0.095154 0.115800

[USREC_REAL 기술통계 - NASDAQ 100 (Tech Growth)] (침체일수: 585일 -> 355일, 230일 축소)
Full Sample Exp/Rescue (USREC_REAL=0) Real Rec (USREC_REAL=1)
count 6664.000000 6309.000000 355.000000
mean 0.000461 0.000607 -0.002130
std 0.017200 0.016105 0.030657
min -0.121932 -0.097318 -0.121932
25% -0.006687 -0.006259 -0.020208
50% 0.001061 0.001136 -0.001970
75% 0.008111 0.007944 0.012814
max 0.187713 0.187713 0.125799

4 2000년 이후 Fed Put으로 인한 증시 왜곡 규명

아래 테이블은 공식 USREC 침체기와 연준 구원투수 보정 후 USREC_REAL 침체기의 주요 통계치 변화를 종합 비교한 결과이다. 2000년 이후 샘플에서 Fed Put 개입 효과를 제거하면 NDX의 경우 침체기 일별 평균 수익률이 기존 -0.0039%에서 -0.2130%로 약 55배 급락하며 실물경제 침체 국면에 일별수익률 분포의 right skew 현상이 교정된다.

Code
summary_records = []
for sym, info in benchmarks.items():
    r_rec_orig = info["ret_rec"]
    r_rec_real = info["ret_real_rec"]
    
    summary_records.append({
        "Benchmark": sym,
        "USREC Days": len(r_rec_orig),
        "USREC_REAL Days": len(r_rec_real),
        "Days Reduced": len(r_rec_orig) - len(r_rec_real),
        "USREC Rec Mean [%]": round(r_rec_orig.mean() * 100, 4),
        "USREC_REAL Rec Mean [%]": round(r_rec_real.mean() * 100, 4),
        "USREC Rec 25% [%]": round(r_rec_orig.quantile(0.25) * 100, 3),
        "USREC_REAL Rec 25% [%]": round(r_rec_real.quantile(0.25) * 100, 3),
        "USREC Rec 50% [%]": round(r_rec_orig.median() * 100, 3),
        "USREC_REAL Rec 50% [%]": round(r_rec_real.median() * 100, 3),
    })

summary_comp_df = pd.DataFrame(summary_records).set_index("Benchmark")
display(summary_comp_df)
USREC Days USREC_REAL Days Days Reduced USREC Rec Mean [%] USREC_REAL Rec Mean [%] USREC Rec 25% [%] USREC_REAL Rec 25% [%] USREC Rec 50% [%] USREC_REAL Rec 50% [%]
Benchmark
W5000 585 355 230 -0.0540 -0.2174 -1.162 -1.165 -0.009 -0.086
GSPC 585 355 230 -0.0561 -0.2088 -1.176 -1.193 -0.008 -0.105
NDX 585 355 230 -0.0039 -0.2130 -1.630 -2.021 0.018 -0.197

5 Fed Rescue Rally 구간의 V자 반등 효과 검증

공식 NBER 침체기(USREC=1) 중 연준의 전격적인 유동성 백스톱이 가동되어 USREC_REAL에서 0으로 수정한 세 구간만을 별도로 추출·병합한다: 1. 2001-09-17 ~ 2001-11-30 (9/11 테러 직후 전격 긴급 50bp 인하 및 무제한 재할인 유동성 공급, 54거래일) 2. 2008-11-25 ~ 2009-06-30 (연준 역사상 최초 QE1 공식 발표 및 ZIRP 도입, 149거래일) 3. 2020-03-23 ~ 2020-04-30 (사상 최대 ‘무제한 QE’ 및 회사채 직매입 전격 발표, 28거래일)

이러한 231거래일의 Fed Rescue Rally 구간을 순수 침체기(Real Recession) 및 순수 확장기(Pure Expansion) 와 삼자 대조하여, 공식 침체 라벨 하에서 발생한 연준발 V자 폭등 랠리의 일별 수익률 분포 및 누적 수익률 반등 효과를 확인한다.

Code
# 1. 3대 국면 분리 (Pure Expansion vs Real Recession vs Fed Rescue Rally)
# - Pure Expansion  : USREC == 0 (공식 확장기)
# - Real Recession  : USREC_REAL == 1 (연준 구원 이전 순수 침체기)
# - Fed Rescue Rally: (USREC == 1) & (USREC_REAL == 0) (연준 구원투수 등판 후 V자 반등 구간)

for sym, info in benchmarks.items():
    ret = info["ret"]
    u = info["usrec"]
    u_real = info["usrec_real"]
    
    r_pure_exp = ret[u == 0].rename("Pure Expansion")
    r_real_rec = ret[u_real == 1].rename("Real Recession")
    r_rescue = ret[(u == 1) & (u_real == 0)].rename("Fed Rescue Rally")
    
    info["ret_pure_exp"] = r_pure_exp
    info["ret_rescue"] = r_rescue
    
    desc_3way = pd.DataFrame({
        "Pure Expansion": r_pure_exp.describe(percentiles=[0.25, 0.5, 0.75]),
        "Real Recession": r_real_rec.describe(percentiles=[0.25, 0.5, 0.75]),
        "Fed Rescue Rally": r_rescue.describe(percentiles=[0.25, 0.5, 0.75]),
    })
    print(f"\n[3대 국면 기술통계 비교 - {info['name']}]")
    display(desc_3way.round(6))

# 2. 1행 3열 서브플롯으로 3대 국면 일별 수익률 분포 오버레이 플롯
fig, axes = plt.subplots(1, 3, figsize=(18, 5), sharey=True)
bins = np.linspace(-0.12, 0.12, 80)

for ax, (sym, info) in zip(axes, benchmarks.items()):
    r_exp = info["ret_pure_exp"]
    r_rec = info["ret_real_rec"]
    r_res = info["ret_rescue"]
    
    q25_res, q75_res = r_res.quantile([0.25, 0.75])
    
    # Pure Expansion (파란색, 반투명)
    ax.hist(r_exp, bins=bins, density=True, alpha=0.35, color="#1f77b4", label=f"Pure Exp (N={len(r_exp):,})", edgecolor="white")
    # Real Recession (붉은색, 반투명)
    ax.hist(r_rec, bins=bins, density=True, alpha=0.35, color="#d62728", label=f"Real Rec (N={len(r_rec):,})", edgecolor="white")
    # Fed Rescue Rally (녹색, 강조)
    ax.hist(r_res, bins=bins, density=True, alpha=0.55, color="#2ca02c", label=f"Fed Rescue (N={len(r_res):,})", edgecolor="black", linewidth=0.8)
    
    # Fed Rescue 분위수 vline 표시
    ax.axvline(q25_res, color="#2ca02c", linestyle="--", linewidth=1.8, label=f"Rescue 25% ({q25_res:.4f})")
    ax.axvline(q75_res, color="#2ca02c", linestyle="-.", linewidth=1.8, label=f"Rescue 75% ({q75_res:.4f})")
    ax.axvline(r_res.mean(), color="#006400", linestyle="-", linewidth=2.0, label=f"Rescue Mean ({r_res.mean():.4f})")
    
    ax.set_title(f"{sym}: {info['name']}", fontsize=12, fontweight="bold")
    ax.set_xlabel("Daily Return")
    ax.grid(True, linestyle=":", alpha=0.6)
    ax.legend(loc="upper right", fontsize=8, frameon=True)

axes[0].set_ylabel("Density")
plt.suptitle("Daily Return Distribution: Pure Expansion vs Real Recession vs Fed Rescue Rally", fontsize=14, fontweight="bold", y=1.02)
plt.tight_layout()
plt.show()

[3대 국면 기술통계 비교 - Wilshire 5000 (Total Market)]
Pure Expansion Real Recession Fed Rescue Rally
count 6079.000000 355.000000 230.000000
mean 0.000420 -0.002174 0.001983
std 0.010547 0.024689 0.023420
min -0.070663 -0.122472 -0.091453
25% -0.004516 -0.011650 -0.011079
50% 0.000696 -0.000864 0.001215
75% 0.005947 0.007187 0.014154
max 0.095681 0.114011 0.092471

[3대 국면 기술통계 비교 - S&P 500 (Large Cap)]
Pure Expansion Real Recession Fed Rescue Rally
count 6079.000000 355.000000 230.000000
mean 0.000410 -0.002088 0.001797
std 0.010259 0.024925 0.023084
min -0.066634 -0.119841 -0.089295
25% -0.004292 -0.011933 -0.011222
50% 0.000685 -0.001052 0.001609
75% 0.005722 0.006949 0.014329
max 0.095154 0.115800 0.093828

[3대 국면 기술통계 비교 - NASDAQ 100 (Tech Growth)]
Pure Expansion Real Recession Fed Rescue Rally
count 6079.000000 355.000000 230.000000
mean 0.000509 -0.002130 0.003190
std 0.015597 0.030657 0.026096
min -0.097318 -0.121932 -0.082533
25% -0.006148 -0.020208 -0.011047
50% 0.001116 -0.001970 0.001567
75% 0.007763 0.012814 0.016865
max 0.187713 0.125799 0.078053

Code
# 3. 3대 위기 사건별 Fed 구원투수 등판 이후 V자 반등 누적 수익률 궤적 시각화
crisis_periods = [
    {"label": "2001 Dot-com / 9/11 Fed Cut", "range": ("2001-09-17", "2001-11-30")},
    {"label": "2008-09 GFC QE1 Announcement", "range": ("2008-11-25", "2009-06-30")},
    {"label": "2020 COVID-19 Unlimited QE", "range": ("2020-03-23", "2020-04-30")},
]

fig, axes = plt.subplots(1, 3, figsize=(18, 5))

for ax, crisis in zip(axes, crisis_periods):
    s, e = crisis["range"]
    lbl = crisis["label"]
    
    for sym, info in benchmarks.items():
        # 시작일(s) 종가를 기준점(Day 0 = 0.0%)으로 정규화하여 모든 자산의 시작점을 0%로 완벽히 일치시킴
        sub_price = info["series"].loc[s:e]
        cum_ret = (sub_price / sub_price.iloc[0] - 1.0) * 100
        ax.plot(cum_ret.index, cum_ret.values, label=f"{sym} (Final: {cum_ret.iloc[-1]:+.1f}%)", linewidth=2)
    
    ax.set_title(f"{lbl}\n({s} ~ {e})", fontsize=11, fontweight="bold")
    ax.set_xlabel("Date")
    ax.set_ylabel("Cumulative Return [%]")
    ax.grid(True, linestyle=":", alpha=0.6)
    ax.axhline(0, color="black", linestyle="--", linewidth=0.8)
    ax.legend(loc="upper left", fontsize=8, frameon=True)

plt.suptitle("Cumulative V-Shaped Recovery Trajectories after Fed Put Intervention (Base = 0% at Day 0)", fontsize=14, fontweight="bold", y=1.02)
plt.tight_layout()
plt.show()

6 구조적으로 기울어진 게임과 무지성 대풀롱의 확률적 합리성

분석 결과를 종합하면 2000년 이후 미국 주식시장은 다음과 같은 비대칭 구조 위에 놓여 있다.

국면 거래일 비중 일별 평균 수익률 (NDX) 롱 포지션 유불리
확장기 (Pure Expansion) ~91.1% +0.051% 유리
순수 침체기 (Real Recession) ~5.3% -0.213% 불리
Fed 구원투수 랠리 (Fed Rescue) ~3.5% +0.319% 극도로 유리

전체 거래일의 94.7%에서 롱 포지션의 기대값이 양(+)이고, 숏 포지션이 우위를 점하는 순수 침체 구간은 고작 5.3%에 불과하다. 연준의 반복된 구원투수 등판은 꼬리위험을 체계적으로 잘라내며, 이 패턴을 학습한 시장 참여자들은 “연준을 믿고 버텨라(Don’t fight the Fed)”라는 격언을 확률적으로 정당화할 수 있게 되었다.

침체기에 진입하더라도 연준이 등판하는 순간부터 시장은 확장기보다 더 강한 일별 수익률(NDX 기준 +0.32%)을 기록한다. 위기 시 레버리지를 키우는 ‘줍줍(Buy the Dip)’ 전략이 사후적으로 정당화되는 구조적 환경이다. 숏 포지션으로 수익을 내려면 연준이 아직 등판하지 않은 순수 침체기 355거래일을 정확히 식별해야 하는데, 이는 실시간으로는 거의 불가능하다.

냉정한 확률론적 판단: 중앙은행이 꼬리위험의 보증인 역할을 포기하지 않는 한, 풋 프리미엄 없이 무제한 하방 보호를 받으며 영구 롱 포지션을 유지하는 것이 기대값 극대화 전략이다. 월가의 “무지성 대풀롱”이란 무지가 아니라, 이 비대칭 구조에 대한 합리적 적응의 산물이다.