A comprehensive Python backtesting framework for analyzing the "Niche Index Inclusions" trading strategy targeting newly added S&P SmallCap 600 stocks.
Target: S&P SmallCap 600 newly added companies
Universe: US stocks with market cap between $500M - $8B
Entry: Buy at closing price on announcement day
Exit Rules:
- ✅ Profit Target: Sell at +15% gain
- ❌ Stop Loss: Sell at -7% loss
- ⏰ Time Exit: Sell after 45 trading days
sp600_backtest/
├── data/
│ └── sp600_additions.csv # Historical S&P 600 addition events
├── src/
│ ├── __init__.py
│ ├── config.py # Strategy configuration
│ ├── data_loader.py # Data fetching and preprocessing
│ ├── backtest_engine.py # Core backtesting logic
│ └── performance_analyzer.py # Performance metrics and visualization
├── results/ # Output files (generated)
├── notebooks/ # Jupyter notebooks for analysis
├── requirements.txt # Python dependencies
├── main.py # Main execution script
└── README.md # This file
- Clone or download this project
- Install dependencies:
pip install -r requirements.txt
You need a CSV file at data/sp600_additions.csv with the following columns:
ticker: Stock symbolcompany_name: Company nameannouncement_date: When addition was announced (YYYY-MM-DD)effective_date: When it became effective (YYYY-MM-DD)
Sources for this data:
- S&P Dow Jones Indices press releases
- Bloomberg Terminal
- Refinitiv/Eikon
- FactSet
- Specialized financial data providers
Note: The framework includes sample data for demonstration, but you must replace it with actual historical data for meaningful results.
python main.pyThe framework will:
- Load S&P 600 additions data
- Filter stocks by market cap criteria
- Fetch historical price data via yfinance
- Run the backtesting simulation
- Generate comprehensive performance analysis
- Export results to the
results/directory
Modify strategy parameters in src/config.py:
class BacktestConfig:
PROFIT_TARGET = 0.15 # 15% profit target
STOP_LOSS = 0.07 # 7% stop loss
HOLDING_PERIOD = 45 # Max days to hold
INITIAL_CAPITAL = 100000 # Starting portfolio
TRANSACTION_COST = 0.001 # 0.1% per trade
START_DATE = datetime(2010, 1, 1)
END_DATE = datetime(2024, 12, 31)The framework calculates comprehensive metrics including:
- Total Return & CAGR
- Sharpe, Sortino & Calmar Ratios
- Maximum Drawdown
- Win/Loss/Neutral Rates (key for Monte Carlo validation)
- Average returns by outcome type
- Profit factor and consecutive streaks
- Volatility and drawdown analysis
- Rolling performance metrics
- Monthly return heatmaps
Results are exported to the results/ directory:
detailed_trade_log.csv: Every trade with entry/exit detailsdaily_portfolio_values.csv: Daily portfolio performanceperformance_metrics.csv: Summary statistics- Interactive plots and visualizations
This backtest is designed to validate assumptions used in Monte Carlo simulations:
Expected Strategy Performance:
- Win Rate: ~40-50%
- Loss Rate: ~20-30%
- Neutral Rate: ~20-40%
The framework compares actual results against these expectations.
- Survivorship Bias: yfinance may not include delisted stocks
- Lookahead Bias: Framework ensures only historical data is used
- Market Cap Filtering: Validates eligibility at announcement date
- Transaction costs are simplified (fixed percentage)
- No consideration for liquidity or market impact
- Limited to US market hours trading simulation
- Requires manual data sourcing for S&P 600 additions
For production backtesting:
- Use professional data providers (Bloomberg, Refinitiv)
- Include comprehensive corporate actions handling
- Add more sophisticated transaction cost models
- Implement portfolio constraints and risk management
from src.config import BacktestConfig
from src.backtest_engine import BacktestEngine
from src.performance_analyzer import PerformanceAnalyzer
# Run custom backtest
config = BacktestConfig()
config.PROFIT_TARGET = 0.20 # 20% target
# ... run backtest with custom parametersUse the notebooks/ directory for:
- Interactive data exploration
- Custom visualizations
- Sensitivity analysis
- Strategy variations
Common Issues:
- No trades executed: Check if S&P 600 data file exists and has valid date ranges
- Price data failures: yfinance rate limits - add delays or use cached data
- Market cap filtering issues: Some tickers may lack fundamental data
Performance Tips:
- Cache price data for multiple runs
- Use date range filtering to reduce data volume
- Consider parallel processing for large datasets
This backtesting framework is provided for educational and research purposes.
Contributions welcome! Areas for improvement:
- Additional data source integrations
- Enhanced risk management features
- Portfolio optimization capabilities
- Alternative exit strategies
Disclaimer: This framework is for research purposes only. Past performance does not guarantee future results. Always validate results with multiple data sources and consider transaction costs, market impact, and other real-world factors before implementing any trading strategy.