Skip to content

philzghub/ETF-Rotation-Backtester

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ETF Rotation Backtester

A modular, educational quantitative finance project that builds an ETF rotation strategy from scratch — starting with a rules-based momentum approach and designed from day one to be extended with machine learning.


Project Goals

This project is built in two phases:

Phase Status Description
Phase 1 🔨 In progress Rules-based momentum strategy with inverse-volatility weighting
Phase 2 📋 Planned ML model replaces the momentum signal (return prediction / ranking)

The codebase is intentionally structured so that Phase 2 requires no changes to portfolio construction or backtesting — only the signal module is swapped.


Strategy Overview (Phase 1)

Universe: 13 liquid ETFs across equities, bonds, commodities, and sectors

Signal: 12-1 momentum (12-month return, skip last month to avoid short-term reversal)

Selection: Top N ETFs by momentum score at each monthly rebalance

Weighting: Inverse volatility (allocate more to less volatile assets)

Benchmark: SPY (S&P 500)


ETF Universe

Ticker Description Asset Class
SPY S&P 500 US Equity / Benchmark
QQQ Nasdaq 100 US Equity / Growth
IWM Russell 2000 US Equity / Small Cap
EFA MSCI EAFE International Developed
EEM MSCI Emerging Markets International Emerging
TLT 20+ Year US Treasuries Long Bond
IEF 7–10 Year US Treasuries Intermediate Bond
GLD Gold Commodity / Hedge
DBC Diversified Commodities Commodity
XLK Technology Sector US Sector
XLF Financials Sector US Sector
XLE Energy Sector US Sector
XLV Healthcare Sector US Sector

Project Structure

quant-etf-rotation/
│
├── configs/
│   ├── base.yaml              # Universe, dates, rebalance frequency
│   └── strategy_v1.yaml       # Momentum params, top N, weighting method
│
├── data/
│   ├── raw/                   # yfinance downloads (auto-cached, git-ignored)
│   └── processed/             # Cleaned, aligned price data
│
├── notebooks/
│   ├── 01_download_data.ipynb
│   ├── 02_feature_engineering.ipynb
│   ├── 03_strategy_backtest.ipynb
│   └── 04_results_analysis.ipynb
│
├── src/
│   ├── data_loader.py         # Data download and caching (yfinance)
│   ├── features.py            # Momentum, volatility, and derived features
│   ├── signals.py             # Rules-based ETF ranking and selection
│   ├── portfolio.py           # Weighting and position sizing
│   ├── backtest.py            # Core backtesting engine (reusable)
│   ├── metrics.py             # Sharpe, drawdown, CAGR, benchmark comparison
│   ├── plots.py               # All visualisations
│   └── utils.py               # Shared helpers
│
├── models/                    # Phase 2: ML signal models (empty for now)
│
├── reports/
│   ├── figures/               # Saved plots
│   ├── trades/                # Rebalance logs and position history
│   └── summary.md             # Performance summary table
│
└── tests/
    ├── test_features.py
    ├── test_portfolio.py
    └── test_backtest.py

Quickstart

1. Clone and install

git clone https://github.com/philzghub/ETF-Rotation-Backtester.git
cd ETF-Rotation-Backtester
pip install -r requirements.txt

2. Download price data

python src/data_loader.py

Or run notebooks/01_download_data.ipynb for an interactive walkthrough.

3. Run the backtest

python main.py

Key Design Decisions

Modularity

Each module has a single responsibility. backtest.py doesn't know how signals are generated. portfolio.py doesn't know how ETFs are ranked. This separation is what allows the ML swap in Phase 2.

Signal contract

Both the rules-based (Phase 1) and ML-based (Phase 2) signal modules expose the same interface:

def get_signal(prices, config, date) -> pd.Series:
    # Returns a score per ticker — higher = more attractive
    ...

portfolio.py and backtest.py consume this Series without caring how it was produced.

No lookahead bias

The backtester is designed to be strict about lookahead. At each rebalance date, only data available before that date is used to generate signals. This is the most common source of inflated backtest results in amateur quant projects.

Honest benchmarking

Results are always compared against buy-and-hold SPY. Outperformance is only meaningful when stated net of transaction costs and with realistic assumptions.


Backtesting Assumptions (Phase 1)

  • Monthly rebalancing on the last trading day of each month
  • No transaction costs in the first version (noted explicitly in results)
  • No leverage
  • Prices used are adjusted close (accounts for dividends and splits)
  • Data source: Yahoo Finance via yfinance

Roadmap

  • Project scaffold and config
  • Data download and caching module
  • Feature engineering (momentum, volatility)
  • Rules-based signal and ETF selection
  • Portfolio construction (inverse volatility weighting)
  • Backtesting engine
  • Performance metrics and benchmark comparison
  • Visualisations and results notebooks
  • Phase 2: ML-based signal (return prediction / ranking)

Learning Resources

If you're working through this project to learn quant finance, these are worth reading alongside the code:

  • Quantitative Momentum — Wesley Gray & Jack Vogel
  • Advances in Financial Machine Learning — Marcos López de Prado (for Phase 2)
  • AQR's research library: aqr.com/insights
  • Investopedia's explanation of momentum investing

Known Limitations

  • Universe selection bias: the 13 ETFs were chosen knowing they survived and remained liquid through 2007-2026. This is standard practice in fixed-universe backtests but is an acknowledged limitation.
  • Execution timing: rebalancing assumes end-of-month close prices. Real execution would occur at next-day open. Flagged for V2.
  • Risk-free rate: Sharpe and related ratios use rf=0. Flagged for V2.

Disclaimer

This project is for educational purposes only. Nothing here constitutes financial advice. Past backtest performance does not guarantee future results.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors