An educational portfolio-research project that uses historical market data to compare selected S&P 600 small-cap stocks with the Technology Select Sector SPDR Fund (XLK). The analysis applies CAPM statistics, selects securities with high in-sample annualized alpha, and evaluates seeded sparse portfolio allocations.
This project is an analytical demonstration, not financial advice or a production trading strategy.
- Scrapes the current S&P 600 constituent table from Wikipedia.
- Downloads adjusted daily prices through
tidyquant/Yahoo Finance. - Calculates daily log returns for each constituent and for
XLK. - Estimates CAPM statistics relative to
XLKand retains the top 10% by annualized alpha. - Builds a reproducible sparse portfolio using seeded random weights.
- Compares the portfolio's growth with a hypothetical
$10,000investment inXLK. - Generates 100 seeded random candidate portfolios and ranks them by annualized return.
The saved figures illustrate one historical run. Results will change when the source constituent list, market data, package behavior, or analysis dates change.
.
├── analysis/
│ ├── sp600_portfolio_optimization.R # Complete analysis script
│ ├── sp600_portfolio_optimization.Rmd # Walkthrough notebook
│ └── qqq_vs_sp500_exploration.Rmd # Supplementary benchmark experiment
├── figures/ # Saved plots from the historical run
├── reports/
│ └── stock-optimization.html # Rendered analysis report
├── requirements.R # Required R packages
├── LICENSE
└── README.md
- R 4.x
- Internet access for Wikipedia and Yahoo Finance data
- Pandoc if rendering the R Markdown notebook
Install the dependencies:
Rscript requirements.RRun the complete script:
Rscript analysis/sp600_portfolio_optimization.RRender the walkthrough report:
Rscript -e "rmarkdown::render('analysis/sp600_portfolio_optimization.Rmd')"The analysis dates are declared in the source. Keep them fixed when reproducing the saved historical experiment, or update them deliberately for a new study.
- CAPM screen:
PerformanceAnalytics::table.CAPM, accessed throughtidyquant, estimates each stock's alpha and beta relative toXLK. - Selection rule: the script keeps observations above the 90th percentile of annualized alpha. This is a top-decile screen, despite older filenames referring to a “quintile.”
- Portfolio construction: random integer weights are sparsified and normalized. Fixed seeds make the random allocations repeatable for the same input data.
- Candidate comparison: 100 random allocations are evaluated and sorted by in-sample annualized return. This is random search, not mathematical optimization.
- Growth illustration: wealth-index returns are scaled to a hypothetical
$10,000starting value.
- The current Wikipedia constituent list is paired with 2023 prices, creating survivorship and membership-timing bias.
- Selection and evaluation use the same historical window; there is no train/test split or out-of-sample validation.
- The experiment omits transaction costs, taxes, liquidity, slippage, position constraints, and rebalancing costs.
- A technology-sector ETF is not a neutral market benchmark for every S&P 600 company.
- Yahoo Finance data and symbols can change or be unavailable, so a future rerun may not exactly reproduce the saved report.
- Randomly sampled portfolios do not prove that the highest in-sample result is durable or optimal.
- Snapshot historical constituents for the analysis date.
- Add walk-forward or rolling-window validation.
- Compare against a broad small-cap benchmark such as
IJR. - Add maximum-weight, sector, turnover, and liquidity constraints.
- Evaluate volatility, Sharpe ratio, drawdown, and risk-adjusted out-of-sample performance.
Released under the MIT License.