Building a UCITS‑Only Quarterly Top‑5 Rank‑Weighted Momentum Strategy

An end-to-end implementation of a UCITS‑compliant quarterly momentum rotation strategy, complete with Bayesian parameter tuning, walk‑forward validation and practical insights from real‑world retail constraints.

Momentum strategies have long delivered strong, robust risk‑adjusted returns with relative simplicity. In this project, I build on three key studies that directly informed my approach:

Findings guided my design of a UCITS‑compliant ETF rotation strategy.

Strategy Methodology & Backtesting Framework

  • Universe: UCITS‑listed, total‑return ETFs accessible via my Interactive Brokers retail account. This limitation forced a narrower ETF set — excluding some high‑quality non‑UCITS funds.
  • Data Range: May 2015 to May 2025 daily NAVs.
  • Momentum Signal: 12‑month total return look-back; alternate windows (6, 9, 24 m) were explored in experimentation.
  • Selection & Weighting: At each quarter‑end:
    1. Rank ETFs by momentum.
    2. Select top five.
    3. Allocate capital proportionally to rank (highest momentum = highest weight).
  • Trading Costs & Constraints: Strategy assumes 1 % p.a. annualized flat trading cost; benchmarks (ACWD, S&P 500) assume 0.1 % p.a. turnover. Position limits and liquidity filters ensure UCITS compliance.

Backtests were conducted in a modular Python pipeline, with separate data ingestion, signal generation, portfolio construction, and performance modules. This structure facilitated iterative experiments but grew complex over time—reinforcing code modularization’s importance.

Full methodology details: docs/methodology.md

Parameter Search & Experimental Design

To optimize performance without overfitting, I employed:

  • Bayesian Optimization using the scikit-optimize library to tune look-back windows (6–24 m) and weight scaling parameters. This approach efficiently explored parameter space rather than brute‑force grid search.
  • Enhancements Tested:
    • Volatility scaling (inverse 3‑month volatility).
    • Regime filters (50 d vs. 200 d moving average crossover).
    • Weighting schemes (raw returns vs. rank‑based scores).

While Bayesian optimization yielded strong in‑sample metrics, these tuned parameters produced unrealistically high backtest returns, indicating overfitting.

See full experiments: docs/experiments.md

Walk‑Forward Validation & Overfitting Mitigation

To ensure out‑of‑sample robustness, I used a walk‑forward optimization (WFO) scheme:

  1. Training Window: 2 years.
  2. Testing Window: 1 year.
  3. Step Size: 6 months.

At each fold, parameters (fixed 12 m look-back, rank weighting) were applied without re-optimizing to avoid introducing look‑ahead bias. In 14 out‑of‑sample folds:

MetricStrategyACWDS&P 500
Avg. CAGR (%)12.6410.0714.49
Avg. Max Drawdown (%)5.486.656.55
Win Rate vs ACWD50 % (7/14)
Win Rate vs S&P 50028.6 % (4/14)

The consistent performance and controlled drawdowns confirmed that the simple 12 m→3 m top‑5 rotation was most robust.

Detailed walk‑forward results: docs/results.md

Performance Summary (May 2015–May 2025)

MetricStrategy (Net)ACWD (Net)S&P 500 (Net)
Total Return163.8 %150.2 %231.9 %
CAGR10.19 %9.60 %12.75 %
Max Drawdown–27.32 %–49.40 %–57.42 %
Sharpe Ratio0.75600.68250.8745
Calmar Ratio0.37290.19440.2220
Alpha vs ACWD (p.a.)+2.67 %
Alpha vs S&P 500 (p.a.)+0.49 %
Benchmarks comparison

Highlights: lower drawdowns, positive alpha at ~0.78 beta exposure, and robust out‑of‑sample results.

Practical Learnings & Future Directions

  1. Correct Backtesting Matters | Walk‑Forward Importance: Parameter tuning via Bayesian optimization led to impressive in‑sample gains but failed out‑of‑sample. WFO exposed overfitting, guiding me back to the simple 12 m setup.
  2. Universe Constraints: Retail account limitations (IBKR UCITS ETFs) significantly cap performance. Non‑UCITS ETFs improved returns in parallel tests—highlighting data scope’s impact.
  3. Code Modularization: As experiments grew, clean, well‑documented modules ensured reproducibility and easier debugging.

Read more: GitHub: momentum-strategy

Get in touch: