This repository contains a comprehensive momentum trading strategy implementation with multiple analysis tools, backtesting engines, and walk-forward optimization capabilities.
The suite provides:
- Multi-Index Analysis: Evaluate 8+ global stock indices
- Advanced Momentum Strategy: ROC + trend slope-based stock selection
- Professional Backtesting: NautilusTrader-powered engine with realistic execution
- Walk-Forward Optimization: Robust parameter testing across multiple time windows
- Comprehensive Analytics: Risk metrics, trade analysis, and performance visualization
Global Coverage (constituents fetched from Wikipedia):
- US: SP500, SP500_IT (S&P 500 IT sector), NASDAQ100
- Europe: DAX40 (Germany), FTSE100 (UK), CAC40 (France)
- Asia: NIFTY50 (India), KOSPI200 (South Korea)
Data Sources:
- Constituents: Wikipedia (with robust scrapers and fallback logic)
- Prices: Yahoo Finance with proper ticker formatting (.DE, .L, .PA, .NS, .KS suffixes)
- US tickers automatically converted (BRK.B β BRK-B)
Algorithm:
- ROC (Rate of Change):
((current_price - past_price) / past_price) * 100- Capped and normalized:
max(0, min(1, ceil(roc)))
- Capped and normalized:
- Trend Slope: Linear regression on log prices over lookback period
- Annualized:
(1 + slope) ** 252
- Annualized:
- Momentum Score:
ROC Γ Trend_Slope - Selection: Top N stocks by momentum score
- Execution: Equal-weight positions, periodic rebalancing
Key Parameters:
LOOKBACK: Days for trend calculation (typical: 150-250)ROC: Days for rate-of-change calculation (typical: 150-250)REB_DAYS: Rebalancing frequency in days (typical: 7-21)POS_SIZE: Capital utilization (typical: 0.95 = 95%)NUM_STOCKS: Number of stocks to hold (1 for top-1 strategy)
Purpose: Single-run backtest with basic NautilusTrader integration
Features:
- Simple top-1 momentum strategy on NASDAQ-100
- Fixed parameters (lookback=250, roc=250, rebalance=14 days)
- Basic trade logging and PnL reporting
- Good for understanding core strategy mechanics
Usage:
# Key parameters in v3
LOOKBACK_PERIOD = 250
ROC_PERIOD = 250
REBALANCE_DAYS = 14
POSITION_SIZE = 0.95Outputs:
- Engine performance stats (Sharpe, drawdown, total return)
- Trade log with entry/exit details
- Last 5-day momentum scores (raw + annualized)
Purpose: Enhanced backtest with improved analytics and robustness
Key Improvements over v3:
- Robust Data Handling: Better missing data management, forward-fill only
- Enhanced Trade Analytics: Detailed position tracking, realized vs unrealized PnL
- Risk Metrics: Maximum drawdown, volatility, win/loss ratios
- Visualization: Equity curves, momentum score evolution, position timelines
- Error Handling: Graceful handling of failed downloads, missing constituents
Additional Features:
- Portfolio value tracking at each rebalance
- Monthly performance breakdown
- Correlation analysis between momentum scores and future returns
- Sensitivity analysis for key parameters
Usage:
# Enhanced configuration in v5
config = {
'lookback_period': 250,
'roc_period': 250,
'rebalance_frequency': 14,
'position_size': 0.95,
'transaction_cost': 7.0,
'min_position_hold_days': 1 # New in v5
}Purpose: Systematic parameter optimization with walk-forward analysis
Core Functionality:
- Multi-Parameter Testing: Grid search across parameter combinations
- Walk-Forward Windows: Rolling 120-day test periods with 120-day steps
- Multi-Index Support: Test same strategy across different global indices
- Parallel Processing: Subprocess-based execution to avoid Jupyter hanging
- Comprehensive Output: Performance tables, rankings, statistical analysis
Configuration Example:
# Global time window
GLOBAL_START = '2022-01-01'
GLOBAL_END = '2025-07-31'
# Walk-forward setup
TEST_WINDOW_DAYS = 120 # Each test period length
STEP_DAYS = 120 # Step between test starts
# Parameter grid for optimization
PARAM_GRID = [
{'LOOKBACK': 150, 'ROC': 150, 'REB_DAYS': 14, 'POS_SIZE': 0.95},
{'LOOKBACK': 200, 'ROC': 200, 'REB_DAYS': 14, 'POS_SIZE': 0.95},
{'LOOKBACK': 250, 'ROC': 250, 'REB_DAYS': 14, 'POS_SIZE': 0.95},
{'LOOKBACK': 200, 'ROC': 150, 'REB_DAYS': 7, 'POS_SIZE': 0.95},
{'LOOKBACK': 200, 'ROC': 250, 'REB_DAYS': 21, 'POS_SIZE': 0.95},
]
# Indices to evaluate
CANDIDATE_INDICES = ['SP500','SP500_IT','NASDAQ100','DAX40','FTSE100','CAC40','NIFTY50','KOSPI200']
# Execution settings
INITIAL_CAPITAL = 10_000_000 # $10M for meaningful absolute PnL
TX_COST = 7.0 # $7 per tradeKey Features:
- Robust Parallel Execution: Subprocess isolation prevents Jupyter kernel hangs even with multiple workers
- Scalable Performance: Support for 1-16+ parallel workers with automatic load balancing
- Progress Tracking: Verbose mode shows real-time progress without log spam
- Error Recovery: Failed windows are skipped, execution continues seamlessly
- Timeout Protection: 5-minute timeout per window prevents infinite hangs
- Complete Output Isolation: NautilusTrader engine logs are fully suppressed in parallel mode
Purpose: Walk-forward backtesting engine and utilities
Key Functions:
-
run_walkforward(): Main orchestration functiondef run_walkforward( global_start: str, # '2022-01-01' global_end: str, # '2025-07-31' param_grid: List[Dict], # Parameter combinations to test candidate_indices: List[str], # ['SP500', 'NASDAQ100', ...] test_window_days: int, # 120 step_days: int, # 120 initial_capital: float, # 10_000_000 tx_cost: float, # 7.0 run_in_parallel: bool, # False (recommended for stability) verbose: bool, # True for progress tracking produce_plots: bool # False (enable for visualizations) ) -> Dict[str, pd.DataFrame]
-
get_adjusted_close(): Robust price data downloading- Handles missing tickers gracefully
- Forward-fill only (no back-fill to avoid look-ahead bias)
- Coverage-based filtering (keeps symbols with >50% data)
- Automatic business day alignment
-
run_engine_for_close(): Single backtest execution- NautilusTrader engine setup and configuration
- Proper warm-up period handling (prevents look-ahead)
- Market data bar construction from price series
- Complete stdout/stderr isolation for Jupyter stability
-
extract_net_pnl(): PnL extraction with fallbacks- Primary: NautilusTrader engine stats
- Fallback: Manual calculation from trade logs
- Handles various engine result formats
Output Structure:
# Returns: Dict[index_name, DataFrame]
{
'SP500': DataFrame([
{'LOOKBACK': 150, 'ROC': 150, 'REB_DAYS': 14, 'POS_SIZE': 0.95,
'net_pnl': 1100782.0, 'ret_pct': 11.007817}
]),
'NASDAQ100': DataFrame([...]),
# ... more indices
}Purpose: NautilusTrader strategy implementation
Key Classes:
-
MomentumConfig: Strategy configuration@dataclass class MomentumConfig: instrument_ids: List[InstrumentId] # Symbols to trade lookback_period: int # Trend calculation window roc_period: int # ROC calculation window num_stocks: int # Number of positions (1 for top-1) rebalance_days: int # Rebalancing frequency position_size: float # Capital utilization (0.95) transaction_cost: float # Fixed cost per trade ($7) liquidate_on_last_bar: bool # True (realize all PnL) min_rebalance_timestamp_ns: int # Earliest rebalance time
-
MomentumStrategy: Core trading logic- Data Management: Maintains price history per instrument
- Momentum Calculation: ROC Γ trend slope methodology
- Rebalancing Logic: Monday-based with frequency throttling
- Order Management: Market orders with proper position sizing
- Trade Logging: Detailed execution records for analysis
Execution Flow:
on_start(): Subscribe to daily bars for all instrumentson_bar(): Update price history, check rebalance conditions- Rebalance Trigger: Monday + sufficient history + min interval elapsed
- Score Calculation: Momentum scores for all instruments with enough data
- Position Changes: Market orders to reach target allocation
on_stop(): Liquidate all positions for final PnL calculation
Purpose: Wikipedia-based constituent fetching with robust parsing
Supported Fetchers:
get_sp500(): S&P 500 companiesget_sp500_it(): S&P 500 IT sector subsetget_nasdaq100(): NASDAQ-100 componentsget_dax40(): German DAX 40 (.DE suffix)get_ftse100(): UK FTSE 100 (.L suffix)get_cac40(): French CAC 40 (.PA suffix)get_nifty50(): Indian NIFTY 50 (.NS suffix)get_kospi200(): Korean KOSPI 200 (.KS suffix)
Robust Parsing Features:
- Multiple column name variants (
Symbol,Ticker,EPIC, etc.) - Unicode character cleaning (invisible characters, etc.)
- Automatic ticker formatting for Yahoo Finance compatibility
- Fallback logic when table structures change
LOOKBACK ROC REB_DAYS POS_SIZE net_pnl ret_pct
250 250 14 0.95 1,435,183 14.35
150 150 14 0.95 1,100,782 11.01
200 150 7 0.95 1,045,700 10.46
200 200 14 0.95 1,045,552 10.46
200 250 21 0.95 -6,937 -0.07
Column Definitions:
- LOOKBACK: Days for trend slope calculation
- ROC: Days for rate-of-change calculation
- REB_DAYS: Rebalancing frequency in days
- POS_SIZE: Fraction of capital deployed (0.95 = 95%)
- net_pnl: Average net profit/loss across all test windows ($)
- ret_pct: Average return percentage (net_pnl / initial_capital Γ 100)
Strong Performance Indicators:
ret_pct > 10%: Excellent momentum captureret_pct 5-10%: Good performance, consider risk metricsret_pct 0-5%: Marginal, evaluate against benchmark
Parameter Insights:
- Longer lookbacks (250) often outperform shorter ones
- Frequent rebalancing (7-14 days) typically beats monthly (21+ days)
- High position sizing (0.95) maximizes returns but increases risk
- Matching LOOKBACK and ROC periods often perform well
Strategy Limitations:
- Momentum-dependent: Performs poorly in mean-reverting markets
- Transaction costs: High turnover can erode profits with higher costs
- Concentration risk: Top-1 strategy has significant single-stock exposure
- Market regime sensitivity: Bull markets favor momentum, bear markets may not
Recommended Analysis:
- Drawdown analysis: Maximum loss periods and recovery times
- Sharpe ratio: Risk-adjusted returns comparison
- Win/loss ratios: Frequency and magnitude of profitable periods
- Correlation with market: Strategy performance vs benchmark indices
# Clone repository
git clone <repository_url>
cd stock_enhanced
# Create Python environment
python -m venv venv
source venv/bin/activate # Linux/Mac
# venv\Scripts\activate # Windows
# Install dependencies
pip install -r requirements.txt
pip install -r requirements_nautilus.txt
# Verify installation
python -c "import nautilus_trader; print('NautilusTrader ready')"# Open basic momentum strategy
jupyter notebook momentum_top1_nasdaq100_nautilus_v3.ipynb
# Run all cells - takes ~2-3 minutes
# Output: Single backtest results for NASDAQ-100# Open enhanced version with analytics
jupyter notebook momentum_top1_nasdaq100_nautilus_v5.ipynb
# Modify parameters in config cell if desired
# Run all cells - takes ~3-5 minutes
# Output: Detailed performance metrics and visualizations# Open walk-forward optimizer
jupyter notebook momentum_walkforward_runner.ipynb
# Adjust PARAM_GRID and CANDIDATE_INDICES as needed
# Set run_in_parallel=False for first run
# Execute - takes 10-60 minutes depending on scope
# Output: Comprehensive parameter rankings across indicesFor Faster Testing:
# Reduce scope for quick validation
GLOBAL_END = '2023-12-31' # Shorter time window
CANDIDATE_INDICES = ['NASDAQ100'] # Single index
TEST_WINDOW_DAYS = 60 # Shorter test windows
PARAM_GRID = [{'LOOKBACK': 200, 'ROC': 200, 'REB_DAYS': 14, 'POS_SIZE': 0.95}] # Single param setFor Production Analysis:
# Full scope for comprehensive results
GLOBAL_END = '2025-07-31' # Full recent history
CANDIDATE_INDICES = ['SP500','NASDAQ100','DAX40','FTSE100','CAC40','NIFTY50'] # Multiple indices
run_in_parallel = True # Safe to enable with subprocess isolation
max_workers = 8 # Scale up to 8-16 workers for best performance
verbose = True # Track progress without log spamTroubleshooting:
- Log spam/hangs: Use
run_in_parallel=Truewith subprocess isolation (now default safe mode) - Performance: Start with
max_workers=4, scale up to 8-16 based on CPU cores - Memory issues: Reduce
CANDIDATE_INDICESor shorten time windows - Network errors: Add delays between yfinance calls, check internet connection
- Empty results: Verify ticker symbols are valid and have sufficient price history
- Timeout issues: Tasks auto-timeout at 5 minutes; increase if needed for very large datasets
This comprehensive momentum strategy suite provides enterprise-grade backtesting capabilities with robust error handling, making it suitable for both research and potential production deployment.