포트폴리오의 초과수익(Excess Return)을 벤치마크(S&P500 섹터 ETF) 대비 분해하여, 섹터 비중 조절(Allocation)과 종목선택(Selection)이 성과에 각각 얼마나 기여했는지 정량적으로 분석하는 프로젝트다.
데이터 수집 → 포트폴리오/벤치마크 구성 → 섹터별·전체 수익률 계산 → 누적수익률 비교 →
성과지표(CAGR/Sharpe/Alpha/Beta/IR/Tracking Error) → Brinson-Fachler 귀속분석 → 섹터/종목
기여도 시각화 → Attribution Dashboard → 자동 리포트 생성, 8단계 전체가 노트북 하나
(notebooks/01_performance_attribution.ipynb)에 순서대로 구현되어 있다.
섹터
Selection 효과에 벤치마크 비중이 아니라 포트폴리오 비중을 쓰는 것이 Brinson-Fachler의 핵심이다. 이렇게 하면 BHB(Brinson-Hood-Beebower) 모델처럼 별도의 Interaction 항을 두지 않고도, 섹터 합계가 정확히 총 초과수익과 일치한다:
이 재구성 항등식은 tests/test_attribution.py에서 합성 데이터로 직접 검증한다. 여러 달에
걸친 결과는 월별 효과를 산술적으로 합산하며, 이는 복리를 정확히 반영하는 다기간 연결
(Frongello/Menchero smoothing)의 근사치다.
- 벤치마크: S&P500 GICS 11개 섹터의 SPDR 섹터 ETF (
XLK/XLF/XLV/XLY/XLC/XLI/XLP/XLE/XLU/XLRE/XLB,yfinance), 섹터 비중은 근사 스냅샷(src/config.py) - 포트폴리오: 성장주(Technology/Communication Services/Health Care) 오버웨이트, 가치·
경기방어주(Financials/Industrials/Consumer Staples/Energy/Utilities/Real Estate/Materials)
언더웨이트로 구성한 샘플 액티브 포트폴리오, 섹터별 실제 종목 1~3개 (
AAPL/MSFT/NVDA/GOOGL/META/UNH/LLY등) - 분석 기간: 최근 3년 (
src/config.py의START_DATE/END_DATE), 수익률 빈도: 월간
performance-attribution/
├── data/
│ ├── raw/ # yfinance 원본 가격 캐시 (git 미포함, 최초 실행 시 자동 생성)
│ └── processed/ # 월간 수익률 데이터
├── notebooks/
│ └── 01_performance_attribution.ipynb # 1~8단계 전체를 순서대로 실행하는 노트북
├── src/
│ ├── config.py # 섹터 ETF, 벤치마크/포트폴리오 비중, 분석 기간, 성과지표 파라미터
│ ├── data_loader.py # 포트폴리오 보유종목 + 벤치마크 섹터 ETF 가격 수집 및 캐싱
│ ├── portfolio.py # 보유종목 수익률 → 섹터별/전체 포트폴리오 수익률
│ ├── benchmark.py # 섹터 ETF 수익률 → 섹터별/전체 벤치마크 수익률
│ ├── attribution.py # Brinson-Fachler 귀속분석 (월별 계산 + 기간 합산)
│ ├── metrics.py # CAGR, 변동성, Sharpe, Beta, Alpha, Tracking Error, Information Ratio
│ └── report.py # 종목별 기여도 계산 + 자동 리포트(markdown) 생성
├── tests/
│ ├── test_attribution.py # Brinson-Fachler 재구성 항등식, 효과별 sanity 테스트
│ └── test_metrics.py # 성과지표 계산 sanity 테스트
├── requirements.txt
└── pytest.ini
pip install -r requirements.txt
jupyter notebook notebooks/01_performance_attribution.ipynb단위 테스트 실행:
pytest- 벤치마크 섹터 비중과 포트폴리오 종목 비중은 분석 기간 내내 고정된 스냅샷이다. 실제로는 지수 구성비와 포트폴리오 비중 모두 매달 변하므로, 월별 실제 비중을 반영하면 귀속분석 정확도가 높아진다.
- 다월 구간의 귀속분석 결과는 월별 효과를 산술적으로 합산한 것으로, 복리 효과를 정확히 반영하는 다기간 연결 방식은 아니다. 분석 기간이 길어질수록 산술합과 복리 기준 초과수익의 차이가 커질 수 있다.
- 종목별 기여도도 같은 이유로 비중을 고정한 근사치이며, 매월 리밸런싱에 따른 비중 변화 (수익률에 따른 자연 표류)는 반영하지 않는다.
- 거래비용, 슬리피지, 세금, 배당재투자 타이밍 차이는 반영되지 않았다.
- 섹터 수익률을 개별 종목이 아닌 SPDR 섹터 ETF로 근사했기 때문에, 실제 GICS 지수 구성종목과 ETF 보유종목이 완전히 일치하지는 않는다.