Skip to content

Repository files navigation

AI-Driven Stock Selection & Backtesting System

A leakage-aware research platform for cross-sectional stock selection, downside-risk modelling, financial-news NLP, realistic execution, and paper-live monitoring.

Python 3.11+ Research status Tests

The project asks whether machine learning can identify future relative winners while controlling downside risk more reliably than direct return prediction. It also studies whether timestamp-valid financial sentiment contributes useful incremental information.

The current evidence supports a small but measurable ranking contribution. It does not establish production alpha or a strategy that consistently beats SPY.

Status date: August 2, 2026

Current research direction: multi-task opportunity and risk estimation, followed by a constrained reward-aware portfolio policy

Historical universe: point-in-time S&P 500 membership, lagged liquid top 250, sector-capped portfolios

Paper-live monitor: independently scheduled Ridge and XGBoost arms at 5, 10, and 20 sessions

How the project evolved

The system became narrower as its validation standard became stronger.

  1. The original project combined direct return prediction, optimization, pair trading, technical indicators, and sentiment. Its complete design and early experiments are preserved on the archive-experiments branch.
  2. Execution timing, transaction costs, label maturity, point-in-time membership, and price-adjustment audits invalidated several attractive early results. The corrected workflow now fails closed when those contracts are violated.
  3. The central ML question changed from predicting an exact return to ranking future relative winners. Ridge remained the hardest baseline to beat, while more complex ranking models did not consistently improve portfolio results.
  4. A ten-year replay showed that the ranking signal can beat matched random selection at some horizons, but none of the tested active portfolios beat schedule-matched SPY. High-recall severe-loss filters also rejected too many eventual winners.
  5. The next design therefore estimates both opportunity and risk: upside rank, expected residual return, downside quantiles, severe-loss probability, and uncertainty. A transparent constrained policy must pass strict controls before contextual or offline reinforcement learning is considered.

The dated evidence behind each change is linked in Current evidence. Superseded tables and long experiment narratives remain available through those reports rather than being pasted into the active README.

Current evidence

Corrected ten-year result

The latest common-date 20-session development experiment covers 520 weekly OOS decisions from December 2013 through November 2023. Daily portfolio returns are reconstructed from exact overlapping sleeves.

Portfolio Mean rank IC Gross CAGR Gross Sharpe Gross maximum drawdown
Ridge return 0.0018 12.09% 0.619 -46.44%
Ridge rank 0.0123 11.42% 0.590 -49.58%
XGBoost rank 0.0128 11.28% 0.596 -44.28%
LambdaMART, five grades -0.0041 10.02% 0.481 -50.18%
SPY index N/A 12.29% 0.774 -32.05%

The table is a zero-cost sensitivity intended to isolate model behaviour. SPY still has the highest CAGR and Sharpe and the smallest drawdown. Ranking labels improve Ridge rank IC but do not improve its portfolio return or tail risk.

Read the ten-year ranking and tail-control experiment

What the model contributes

Frozen-score attribution found the clearest selection contribution at 40 and 50 sessions. Their median gross CAGR advantages over sector-matched random portfolios were 2.84 and 1.87 percentage points. Every tested horizon still trailed schedule-matched SPY before costs, so this is evidence of a weak selection signal rather than a market-beating strategy.

Read the horizon performance attribution

Why the current tail filter remains inactive

The ten-year Ridge-rank tail treatment reduced severe-loss frequency from 8.03% to 6.90% and improved CVaR. Its veto precision was only 13.84%, 53.37% of rejected observations were eventual winners, and return preservation did not generalize across models. The result motivates joint upside and downside modelling instead of another hard high-recall veto.

Read the severe-loss A/B evidence

Sentiment status

Sentiment remains promising but unproven. Historical development comparisons showed favourable point estimates, but source coverage, timestamp quality, entity linking, and the absence of a prospective technical-only control prevent a causal performance claim. Sentiment stays in the research system while the NLP and evaluation design are strengthened.

Read the current project evidence map

Current research direction

The approved redesign separates prediction from portfolio policy.

Prediction heads
  upside ranking
  expected residual return
  downside quantiles
  severe-loss probability

Uncertainty estimates
  fold and seed disagreement
  predicted quantile range
  data-quality risk

Portfolio policy
  expected opportunity
  less downside-risk penalty
  less uncertainty penalty
  subject to exposure, liquidity, turnover, drawdown, and CVaR controls

The four outcomes remain separate training targets so their contribution can be measured. Reward is introduced at the portfolio-policy layer rather than being used as one opaque stock label. The first experiment uses a deterministic constrained policy. A contextual controller and conservative offline RL are eligible only if sequential portfolio state adds value beyond that baseline.

Promotion requires every candidate to:

  • beat sector-matched random portfolios and the eligible-universe control;
  • produce positive gross active return against schedule-matched SPY;
  • improve Sharpe without worsening maximum drawdown or CVaR;
  • remain stable across folds, years, regimes, seeds, and nearby horizons;
  • reduce severe-loss exposure without rejecting too many winners; and
  • pass a genuinely untouched chronological confirmation period.

Read the multi-task signal, risk, and policy-learning proposal

Architecture

flowchart TD
    INGEST["Market, membership, fundamentals, and news ingestion"]
    AUDIT["Point-in-time availability, corporate-action, and coverage audits"]
    PANEL["Leakage-safe universe, features, and horizon-matched labels"]
    HEADS["Opportunity and risk models: rank, return, quantile, and severe loss"]
    POLICY["Uncertainty-aware scoring and constrained portfolio policy"]
    REPLAY["Exact next-open portfolio replay with costs and SPY"]
    LIVE["Immutable paper-live cohorts and matured outcomes"]
    EVIDENCE["IC, calibration, return, drawdown, CVaR, SHAP, and controls"]
    DASH["Live Monitor, Horizon Comparison, and Research Evidence dashboards"]

    INGEST --> AUDIT --> PANEL --> HEADS --> POLICY --> REPLAY
    POLICY --> LIVE
    REPLAY --> EVIDENCE
    LIVE --> EVIDENCE --> DASH
Loading
Module Responsibility
Market, membership, and news ingestion Refresh adjusted market history and timestamped financial news; preserve effective-dated membership, sectors, sources, and freshness metadata
Leakage-safe research panel Form the lagged liquid universe; build technical, sector-relative, risk, fundamental, sentiment, and recency features; create exact next-open horizon labels
Model development Use purged temporal folds, fold-local preprocessing and feature selection, training-only early stopping, Optuna TPE, common rows, and saved OOS predictions
Portfolio policy and replay Convert frozen scores into constrained holdings; execute at audited prices; track exposure, turnover, costs, cash, drawdown, CVaR, and SPY-relative results
Evidence and monitoring Preserve immutable forecasts; mature outcomes without look-ahead; publish signal, portfolio, model, feature, and live-forward diagnostics

The much larger historical architecture is available on the archive-experiments branch.

Visual evidence

Selection contribution across horizons

Horizon performance attribution

The 40- and 50-session portfolios beat sector-matched random selection most clearly, but all tested horizons trail schedule-matched SPY.

Corrected ten-year portfolio behaviour

Backtest and execution diagnostics

The chart keeps SPY visible beside the corrected active portfolios and reports growth, drawdown, daily return distributions, and exact sleeve turnover.

Signal diagnostics

Qlib-style signal diagnostics

The signal report separates rank IC and score-quantile behaviour from portfolio accounting. Overlapping horizon returns are not compounded as independent weekly outcomes.

Tail-control evidence

Tail-control A/B diagnostics

The treatment improves several tail statistics in the Ridge-rank arm but does not preserve return reliably across models, so it remains inactive.

Model interpretation

TreeSHAP feature contributions

TreeSHAP explains the frozen July 30 XGBoost 20-session cross-section. It describes model behaviour, not causal importance.

Regenerate the tracked README figures with:

python -m src.experiments.readme_figures

Public dashboards

The public site uses one visual system across three linked views:

The daily publisher rebuilds and validates all three pages from sanitized artifacts. A dashboard can display partial observations, but it does not label an outcome complete until the exact entry and exit prices exist.

Paper-live experiment

The monitor issues daily forecasts while matching each arm's model-refit and portfolio-rebalance clock to its horizon.

Arm Refit Rebalance Label purge Role
Ridge and XGBoost, 5 sessions Every 5 sessions Every 5 sessions 5 sessions Short-horizon diagnostic
Ridge and XGBoost, 10 sessions Every 10 sessions Every 10 sessions 10 sessions Intermediate challenger
Ridge and XGBoost, 20 sessions Every 20 sessions Every 20 sessions 20 sessions Provisional longer-horizon arm

Forecasts are saved every trading day without forcing daily portfolio replacement. Model outputs, selected features, top stocks, execution dates, and maturity status are immutable once issued.

Run a completed-market-day cycle with:

python -m src.cli run-live-forward-20d --as-of YYYY-MM-DD

Read the live-forward design

Research controls

  • Membership, sectors, liquidity, and features are reconstructed as of the simulated decision time.
  • Labels must mature before training and are purged from temporal boundaries.
  • Imputation, scaling, feature selection, calibration, early stopping, and hyperparameter selection stay inside the training boundary.
  • Candidate models use common dates, rows, folds, execution, and compute budgets.
  • SPY, eligible-universe, and matched-random controls remain visible.
  • Gross, zero-cost, declared-cost, and tactical results are reported separately.
  • Missing prices, stale inputs, failed NLP, invalid scores, or incomplete artifacts stop the run.
  • A viewed test period is development evidence and cannot be renamed an untouched confirmation period.

The reusable modelling standard is documented in ml-framework.md.

Quick start

python -m venv .venv

# Windows
.venv\Scripts\activate

pip install -r requirements.txt
pip install -e ".[tuning]"
pytest -q

Useful commands:

# Run one paper-live cycle after a completed US market close
python -m src.cli run-live-forward-20d --as-of YYYY-MM-DD

# Refresh the frozen-cohort monitor and public bundle
python -m src.cli run-live-forward-daily --as-of YYYY-MM-DD

Run python -m src.cli --help for the complete command surface.

Documentation and experiment archive

The README contains only the active system, corrected evidence, and approved next direction. Detailed experiments remain linked for reproducibility.

Failed experiments remain evidence. They are preserved in their dated reports instead of being presented as simultaneously active strategies.

Known limitations

  1. The strongest results remain development evidence. The repeatedly inspected 2013 through 2023 period is not an untouched confirmation period.
  2. Public data does not completely solve delisted-security coverage, permanent-identifier history, corporate actions, or historical sectors.
  3. The average ranking edge is small, unstable by year and regime, and has not produced a standalone portfolio that beats schedule-matched SPY.
  4. The active tail treatment has insufficient precision and remains disabled.
  5. Sentiment lacks sufficient high-quality coverage and a prospective technical-only control for causal attribution.
  6. The paper-live evidence is young; partial marks and immature horizons cannot establish long-run performance.
  7. Static execution costs do not establish capacity, taxes, borrow availability, market impact, or partial fills.
  8. Reinforcement learning remains a proposal. It receives no promotion unless the simpler multi-task constrained policy passes every required gate first.

Research disclaimer

This repository is an educational and research system. Backtests, model scores, paper portfolios, and live-forward monitors are not investment advice and do not guarantee future performance.

About

A production-style research project combining ML-based return forecasting, CVaR-aware portfolio optimization, pair-trading, realistic transaction costs, and a semantic NLP event pipeline for S&P 500 equities.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages