이 프로젝트는 SPY 초과수익을 목표로 설계한 ETF 로테이션 전략 연구 프로젝트다.
기존의 단순 멀티자산 자산배분 방식과 달리, 이 전략은 주식형 ETF 내부의 상대 강도(relative strength) 에 집중한다.
핵심 아이디어는 다음과 같다.
- 상대적으로 강한 ETF에 자금을 배분한다.
- 시장 환경이 약해지면
SHY로 방어한다. - 특히 성장/기술 leadership이 동시에 약해지는 구간에서는 방어 비중을 더 높인다.
이 전략은 다음 검증 과정을 거쳤다.
- 전체 기간 백테스트
- OOS 검증
- walk-forward 검증
- 거래비용 민감도 테스트
- 스타일 약세 구간 분석
- ETF 상장 시점을 반영한 동적 유니버스 검증
최종 결론은 보수적으로 정리했다.
이 전략은 2003년 이후 전체 구간에서 SPY와 유사한 장기 수익률과 더 낮은 최대낙폭을 보였지만,
장기적으로 SPY를 안정적으로 초과하는 전략이라고 보기는 어렵다.
이 프로젝트의 원래 목표는 다음과 같았다.
- SPY를 초과하는 ETF 로테이션 전략 설계
- 해석 가능하고 구현 가능한 구조 유지
- 전략이 어디서 왜 깨지는지까지 확인
최종적으로 이 전략은 다음처럼 정리된다.
- 국면 의존형 ETF 로테이션 전략
- 장기 CAGR은 SPY와 유사
- 최대낙폭은 SPY보다 완화
- 성장 / 기술 / 반도체 leadership에 대한 의존성이 높음
SPYQQQIWFIWMSMHVWOVNQHYG
SHY
- 월간 리밸런싱
각 ETF의 12개월 모멘텀을 계산하고, 해당 시점 ETF들 간의 상대 강도를 비교해 순위를 매긴다.
최종 baseline에서는 여러 실험 요소를 제외하고,
가장 단순하면서 해석 가능한 구조만 남겼다.
- 6개월 + 12개월 혼합 모멘텀
- trend 가산/감점
- carry proxy
- macro regime overlay
- volatility targeting
- 일반 overlay 중첩
즉 현재 baseline의 핵심은 12개월 상대 모멘텀이다.
- 각 ETF의 12개월 모멘텀을 계산한다.
- 12개월 모멘텀이 양수인 ETF만 후보로 인정한다.
- 후보 중 상위 2개 ETF를 선택한다.
- 후보가 없으면 **SHY 100%**로 이동한다.
선택된 상위 2개 ETF는 점수비례 가중을 사용한다.
- 더 강한 ETF에 더 큰 비중
- 두 번째 ETF에 더 작은 비중
- 점수는
power = 1.5비선형 강화 후 정규화
- 동일가중
- top 1 집중
- top 3 분산
- 70:30 고정가중
최종적으로 top 2 + 점수비례 가중을 채택했다.
테스트 결과, 이 전략은 성장/기술 leadership이 동시에 약해지는 구간에 취약했다.
다음 조건이 모두 참이면 방어를 강화한다.
SMH월간 수익률 <SPY월간 수익률QQQ월간 수익률 <SPY월간 수익률IWF월간 수익률 <SPY월간 수익률
이때 포트폴리오는 다음처럼 조정된다.
- Offensive top 2 비중 합계 50%
SHY50%
즉 평소에는 공격적으로 운용하지만,
확인된 약점 구간에서는 방어 비중을 높인다.
유니버스는 동적(dynamic)으로 적용한다.
각 ETF는 다음 조건을 만족해야 후보가 된다.
- 해당 시점에 이미 상장되어 있어야 함
- 12개월 모멘텀 계산이 가능한 가격 이력이 있어야 함
- 해당 시점에 여전히 존재하는 자산이어야 함
즉, 모든 ETF가 처음부터 존재했다고 가정하는 비현실적인 백테스트를 피했다.
- 다운로드 시작일:
2002-01-01 - 백테스트 시작일:
2003-01-31
- Universe:
SPY, QQQ, IWF, IWM, SMH, VWO, VNQ, HYG, SHY - Signal: 12M momentum only
- Rebalance: Monthly
- Selection: Top 2
- Weighting: Score-weighted
- Default fallback: SHY 100%
- Weak-regime override: SHY 50% + offensive 50%
- Overlay: OFF
- Universe handling: 상장 시점 반영 동적 유니버스
전략과 SPY의 누적 성과 비교 그래프다.
장기적으로는 유사한 CAGR을 보였지만, 특정 국면에서는 성과 차이가 크게 벌어지는 구간이 존재한다.
전략과 SPY의 drawdown 비교 그래프다.
전략은 장기적으로 SPY보다 더 낮은 최대낙폭을 기록했다.
전략과 SPY의 연도별 수익률 비교 그래프다.
전략이 어떤 시장 국면에서 강하고 약한지 확인할 수 있다.
- Strategy CAGR: 9.28%
- SPY CAGR: 9.24%
- Strategy Volatility: 14.84%
- SPY Volatility: 14.45%
- Strategy Sharpe: 0.67
- SPY Sharpe: 0.69
- Strategy Max Drawdown: -41.60%
- SPY Max Drawdown: -52.20%
- Upside Capture: 0.41
- Downside Capture: 0.96
- Monthly Win Rate vs SPY: 50.0%
2003년 이후 전체 구간 기준으로 이 전략은:
- 장기 CAGR이 SPY와 거의 유사
- Sharpe는 SPY보다 약간 낮음
- 최대낙폭은 SPY보다 의미 있게 낮음
즉 이 전략은
장기적으로 SPY를 안정적으로 이기는 전략
이라기보다,
장기 수익률은 SPY와 비슷하지만, 낙폭을 다소 줄이는 국면 의존형 ETF 로테이션 전략
으로 보는 것이 더 정확하다.
이 전략은 시장 국면에 따라 성과 차이가 크다.
전략이 선호하는 리더십이 강했던 구간에서는 성과가 좋았다.
예:
- 2006: 23.25% vs SPY 13.74%
- 2007: 12.58% vs SPY 3.24%
- 2008: -33.02% vs SPY -38.28% (상대적 방어)
- 2014: 18.34% vs SPY 11.29%
- 2020: 49.75% vs SPY 16.16%
- 2024: 27.46% vs SPY 23.30%
광범위한 강세장이나 리더십 구조가 맞지 않은 구간에서는 성과가 약했다.
예:
- 2003: 21.15% vs SPY 29.31%
- 2004: -0.64% vs SPY 8.62%
- 2009: 2.68% vs SPY 23.49%
- 2013: 15.61% vs SPY 29.69%
- 2021: 18.78% vs SPY 27.04%
즉 이 전략은 항상 강한 전략이 아니라, 특정 환경에서 강한 전략이다.
- Train CAGR: 8.75%
- Test CAGR: 11.09%
- Train SPY CAGR: 8.54%
- Test SPY CAGR: 11.63%
- Test Sharpe: 0.82
- Test SPY Sharpe: 0.81
- Test Max Drawdown: -20.95%
- Test SPY Max Drawdown: -24.80%
OOS 테스트 구간에서 이 전략은:
- CAGR 기준으로는 SPY를 소폭 하회
- Sharpe는 SPY보다 소폭 우위
- 최대낙폭은 SPY보다 낮음
즉 OOS 결과는
- 강한 초과수익 검증 이라기보다,
- 위험조정 성과 측면에서 경쟁력 있는 결과
에 더 가깝다.
walk-forward 테스트에서도 혼합된 결과가 나타났다.
- 2008-02 ~ 2009-01: 전략이 SPY 대비 방어 우위
- 2009-02 ~ 2010-01: 전략이 SPY 대비 크게 부진
- 2014-02 ~ 2015-01: 전략 우위
- 2020-02 ~ 2021-01: 전략 우위
- 2021-02 ~ 2022-01: 전략 부진
- 2025-02 ~ 2026-01: 전략 우위
walk-forward 결과 역시 동일한 메시지를 준다.
이 전략은 시장 국면과 리더십 구조에 따라 성과가 크게 달라지는 전략이다.
즉 항상 잘 작동하는 전략은 아니다.
| Cost Rate | Strategy CAGR | SPY CAGR | Excess CAGR |
|---|---|---|---|
| 0.002 | 9.28% | 9.24% | +0.04% |
| 0.004 | 8.94% | 9.24% | -0.30% |
| 0.006 | 8.60% | 9.24% | -0.64% |
이 부분은 중요하다.
장기 전체 구간에서는 거래비용을 보수적으로 높이면
전략의 초과수익은 거의 사라지거나 음수로 바뀐다.
즉 최근 구간에서는 비용 내성이 괜찮아 보였지만,
장기 전체 표본에서는 거래비용에 꽤 민감한 전략이라고 해석해야 한다.
전략이 실제로 어떤 환경에서 약한지 확인하기 위해
SMH, QQQ, IWF가 SPY보다 약한 달들을 따로 분석했다.
전략은 특히 다음 구간에서 약했다.
SMH < SPY달: 평균 초과수익 -0.64%/월QQQ < SPY달: 평균 초과수익 -0.68%/월IWF < SPY달: 평균 초과수익 -0.54%/월- 세 조건이 모두 동시에 발생한 달: 평균 초과수익 -1.10%/월
이 전략의 본질은 일반적인 전술적 자산배분이 아니라,
성장 / 기술 / 반도체 leadership 로테이션 전략 + SHY 방어 구조
에 가깝다.
이 점이 전략의 강점이기도 하고, 동시에 구조적 약점이기도 하다.
실제 월별 비중을 보면 전략은 대체로 다음처럼 움직였다.
- 강한 성장/기술 구간에서는 SMH / QQQ / IWF 비중이 크게 올라감
- 혼조 혹은 방어 구간에서는 SHY 비중이 크게 늘어남
- 일부 시기에는
IWM,VWO,VNQ로 이동하지만, 핵심 엔진은 여전히 성장/기술 leadership이다
즉 실제 보유 종목 기준으로도 이 전략은
성장/기술 로테이션 + SHY 방어
라고 요약할 수 있다.
- 구조가 단순하고 해석 가능함
- ETF 상장 시점을 반영한 현실적인 동적 유니버스 적용
- SPY 대비 더 낮은 장기 최대낙폭
- 최근 구간에서는 위험조정 성과가 경쟁력 있음
- OOS, walk-forward, 비용 민감도, 스타일 약세 구간까지 폭넓게 검증
- 유리한 결과만 남기지 않고 약점까지 명확히 드러냄
- 2003년 이후 전체 구간에서 SPY를 확실히 초과하지 못함
- 장기 Sharpe는 SPY보다 약간 낮음
- 비용 가정을 보수적으로 두면 초과수익이 음수로 전환될 수 있음
- 성장 / 기술 / 반도체 leadership에 대한 의존성이 큼
- broad bull market이나 강한 반등장에서 자주 underperform
- 국면 의존성이 구조적인 특징임
이 전략은 다음처럼 소개하면 안 된다.
- 장기적으로 SPY를 꾸준히 이기는 전략
- 모든 시장에서 강한 만능 전략
- 즉시 실전 자금 투입 가능한 완성형 기관 전략
이 전략은 이렇게 소개하는 것이 맞다.
ETF 모멘텀 로테이션이 장기적으로 어떤 특성을 가지는지, 그리고 어디서 강하고 어디서 약한지를 정직하게 보여주는 정량 리서치 프로젝트
즉 이 프로젝트의 가치는
“완벽한 전략을 찾았다”는 데 있는 게 아니라,
가설 설정 → 설계 → 검증 → 약점 분석 → 재해석까지 이어지는 완전한 퀀트 리서치 과정을 보여준다는 데 있다.
비록 장기 전체 결과가 최근 구간만 봤을 때보다 더 보수적으로 나왔지만,
이 프로젝트는 다음 과정을 모두 포함한다.
- 가설 설정
- 신호 설계
- ETF 유니버스 구성
- 비중 산정 로직 설계
- fallback/방어 구조 설계
- OOS 검증
- walk-forward 검증
- 거래비용 민감도 테스트
- 스타일 약세 구간 분석
- ETF 상장 시점을 반영한 동적 유니버스 확장
- 더 엄격한 조건에서 전략을 다시 해석
즉 이 프로젝트는 “좋아 보이는 숫자만 남기는 프로젝트”가 아니라,
정량 전략을 어떻게 검증하고 냉정하게 재평가해야 하는지 보여주는 프로젝트다.
이 저장소는 다음처럼 포지셔닝하는 것이 가장 적절하다.
- ETF 로테이션 전략 연구
- 국면 의존형 전술적 자산배분 연구
- 정량 포트폴리오 설계 및 검증 프로젝트
다음처럼 소개하는 것은 부정확하다.
- 장기 SPY 초과수익 확정 전략
- production-ready alpha engine
- 강건한 장기 시장 초과수익 시스템
이 저장소는 최종 baseline을 다음 이름으로 보존한다.
baseline_equity_rotation_v1
이 프로젝트는 첫 번째 완성형 연구 프로젝트로 보존하고,
다음 단계 확장은 별도 프로젝트에서 진행하는 것이 적절하다.
quant_portfolio/
├── config/
│ ├── universe.py
│ ├── settings.py
│ ├── data_config.example.py
│ ├── macro_series.py
│ ├── etf_metadata_column.py
│ └── etf_manual_metadata.py
│
├── data/
│ ├── raw/
│ ├── processed/
│ ├── cache/
│ └── factors/
│
├── images/
│ ├── cumulative_returns.png
│ ├── drawdown_comparison.png
│ └── yearly_returns.png
│
├── scripts/
│ ├── update_data.py
│ ├── build_etf_metadata.py
│ ├── preprocess_data.py
│ ├── build_features.py
│ ├── build_factors.py
│ ├── build_risk_model.py
│ ├── build_portfolio.py
│ ├── apply_overlays.py
│ ├── run_execution.py
│ ├── run_backtest.py
│ ├── run_analytics.py
│ ├── run_benchmark_report.py
│ ├── run_oos_validation.py
│ ├── run_walk_forward_validation.py
│ ├── run_transaction_cost_sensitivity.py
│ ├── run_style_weakness_report.py
│ └── run_plot_report.py
│
└── src/
├── data/
├── preprocessing/
├── features/
├── factors/
├── risk/
├── portfolio/
├── overlays/
├── execution/
├── backtest/
├── analytics/
└── utils/
이 프로젝트는 외부 데이터 API를 사용한다. 실제 API 키는 Git에 포함하지 않는다.
공개 저장소에는 예시 파일만 포함한다.
예:
- config/data_config.example.py
예시:
Copy this file to `config/data_config.py` and fill in your real API keys.
Do not commit `config/data_config.py` to Git.
FRED_API_KEY = "your_fred_api_key_here"
ALPHA_VANTAGE_API_KEY = "your_alpha_vantage_api_key_here"# Python
__pycache__/
*.pyc
# Secrets
.env
config/data_config.py
# Data artifacts
data/raw/
data/processed/
data/cache/
data/factors/- 데이터 다운로드 및 메타데이터 생성
python -m scripts.update_data
python -m scripts.build_etf_metadata- 전처리 및 피처 생성
python -m scripts.preprocess_data
python -m scripts.build_features
python -m scripts.build_factors- 포트폴리오 비중 생성 및 실행 반영
python -m scripts.build_portfolio
python -m scripts.apply_overlays
python -m scripts.run_execution- 백테스트 및 분석
python -m scripts.run_backtest
python -m scripts.run_analytics
python -m scripts.run_benchmark_report- 추가 검증
python -m scripts.run_oos_validation
python -m scripts.run_walk_forward_validation
python -m scripts.run_transaction_cost_sensitivity
python -m scripts.run_style_weakness_report- 그래프 생성
python -m scripts.run_plot_reportpython -m scripts.update_data
python -m scripts.build_etf_metadata
python -m scripts.preprocess_data
python -m scripts.build_features
python -m scripts.build_factors
python -m scripts.build_portfolio
python -m scripts.apply_overlays
python -m scripts.run_execution
python -m scripts.run_backtest
python -m scripts.run_analytics
python -m scripts.run_benchmark_report
python -m scripts.run_oos_validation
python -m scripts.run_walk_forward_validation
python -m scripts.run_transaction_cost_sensitivity
python -m scripts.run_style_weakness_report
python -m scripts.run_plot_report이 저장소는 완성된 1차 연구 프로젝트로 보는 것이 맞다.
즉, 이 baseline을 계속 덧칠하는 것보다:
- 이 프로젝트는 ETF 로테이션 연구 결과로 보존하고
- 다음 단계는 별도 프로젝트에서 기관형 멀티 슬리브 구조로 확장하는 것이 더 적절하다.


