RF100 is a causal, monthly cross-sectional stock-ranking experiment built from 100 price-derived features and a fixed random forest. The research question was deliberately narrow: can a nonlinear model add economically meaningful value beyond a simple 126-day momentum ranking?
The answer is no. RF100 produced statistically positive out-of-sample rank information, but it did not beat the momentum benchmark after identical execution assumptions. This repository publishes the complete negative result, including code, preregistered rules, fold audits, predictions, transaction-cost sensitivity, and a failed HMM extension.
Out-of-sample period: January 2010 to July 2026, 197 monthly portfolios. Results below include 10 bps per side.
| Portfolio | CAGR | Sharpe | Max drawdown | Annual turnover |
|---|---|---|---|---|
| Equal weight | 23.05% | 1.153 | -24.99% | 0.81x |
| 126-day momentum, top 5 | 32.14% | 1.075 | -37.62% | 7.15x |
| RF100, top 5 | 30.49% | 0.931 | -37.52% | 11.18x |
RF100 minus momentum had an annualized mean return difference of 0.01% with a Newey-West/HAC t-statistic of 0.001. The model won in the first half of the sample (+17.34% compounded relative wealth) and failed in the second half (-30.68%). Its mean monthly cross-sectional Spearman IC was 0.0596 with a HAC t-statistic of 2.40: predictive structure existed, but it was not converted into incremental portfolio alpha.
Research verdict: NO-GO for deployment.
- Fixed universe of 20 US and European stocks; this intentionally retains survivorship and universe-selection bias.
- 100 causal OHLC features across momentum/trend, volatility, downside tails, drawdown/path, reversal/position, OHLC structure, cross-sectional, and market-regime families.
- Target: cross-sectional rank of the 42-session open-to-open return, net of 10 bps per side.
- Signal observed after close on day
t; entry at open ont+1; exit at open ont+43. - Annual walk-forward refits with a minimum 43-session purge; monthly top-five equal-weight portfolios.
- Fixed 300-tree
RandomForestRegressor; no hyperparameter search on the out-of-sample period. - In-fold missingness filters, median imputation, and feature selection only.
- Equal-weight and 126-day momentum portfolios use the same dates, holdings count, execution convention, and costs.
- Cost sensitivity at 10, 25, and 50 bps per side.
- Point-in-time perturbation test: changing every OHLC value after the audit cutoff left all features at the cutoff unchanged (maximum absolute difference 0.0).
The full specification is in docs/METHODOLOGY.md and the frozen research rules are in docs/PREREGISTRATION_RF100.md.
Permutation importance was computed only on each year's held-out observations. The public result files contain both annual and aggregate importance, so feature narratives can be checked rather than inferred from in-sample impurity scores.
A preregistered challenger added 25 forward-filtered features from five three-state Gaussian HMM families (asset trend, asset risk, market direction, market stress, and market style). Every fit cutoff preceded the month being predicted; backward-smoothed state probabilities were prohibited.
At 10 bps per side, RF125-HMM achieved 27.48% CAGR, 0.878 Sharpe, and -38.50% maximum drawdown. It trailed RF100 by 2.77% annualized (HAC t-statistic -1.41) and also trailed momentum. The extension is therefore a second NO-GO, not a rescued specification.
| Strengths | Weaknesses |
|---|---|
| Causal signal and execution timing; strict walk-forward purge; fixed model; benchmark-relative evaluation; out-of-sample permutation importance; explicit cost sensitivity; reproducible point-in-time audit. | Fixed 20-name survivor-selected universe; no delisted securities or point-in-time membership; Yahoo adjusted OHLC only; high RF turnover; concentrated top-five portfolio; poor second-half stability. |
| Opportunities | Threats |
| A true point-in-time universe with delistings; turnover-aware ranking or holding buffers; a frozen untouched forward sample; broader genuine fundamental or microstructure data; testing whether IC can be monetized with a different portfolio layer. | Momentum absorbs the apparent signal; statistically significant IC may remain economically unusable; transaction costs and capacity; repeated-research selection; adjusted-data revisions; regime dependence. |
config/ Frozen ticker universe
data/ Data instructions; raw market data are not redistributed
docs/ Methodology, preregistrations, audit, and provenance
results/feature_store/ Feature catalog and causal-quality audits
results/rf100/ Published RF100 OOS results and predictions
results/hmm3_features/ Causal HMM feature and fit audits
results/rf100_hmm3/ Published HMM challenger results
src/ Download, feature, WFA, HMM, and plotting code
assets/ Rebuilt figures
Python 3.11 or newer is recommended.
git clone https://github.com/Filip303/RF100.git
cd RF100
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install -r requirements.txt
python src/download_data.py
python src/rf100_feature_store.py
python src/rf100_wfa.py
python src/hmm3_feature_store.py
python src/rf100_hmm3_wfa.py
python src/plot_results.pyFresh computations are written to results/reproduced/, leaving the published evidence unchanged. Yahoo data can be revised, so exact future reruns may differ slightly from the frozen July 2026 outputs. See docs/DATA.md.
This is a research audit, not investment advice. The results are simulated, use a small survivor-selected universe, and do not establish deployable alpha. No live trading system is included.


