A Systematic Signal Refinement Framework
We turn a noisy momentum sleeve into a disciplined, probability-aware process. A calibrated meta-model predicts the chance each candidate trade will resolve within horizon; we gate and size by that probability and execute with realistic hygiene (close→next-close, asymmetric costs, EWMA vol target, leverage cap). The result is a diversifying sleeve that deploys cleanly as a 50/50 blend with SPY.
- Meta-Labeled Strategy (net): 12.17% return @ 19.51% vol, Sharpe 0.62, β ≈ −0.11, ρ ≈ −0.12, max DD −28.07%.
- 50/50 SPY + Strategy (net): 14.64% return @ 13.43% vol, Sharpe 1.09, max DD −28.07% (SPY −33.72%).
- Beta-neutral (net): 14.20% return @ 19.36% vol, Sharpe 0.73, β ≈ 0 (by design).
- Trade quality: 3,612 trades, 65.75% win rate, PF 2.92, avg holding 24.2d.
Full tables/figures are in the case report PDF and under results/ & figures/.
This project emphasizes rigorous data hygiene, explicit out-of-sample evaluation, calibration-first modeling, probability-aware execution, and realistic portfolio frictions. It is intended as a research case study in systematic signal refinement rather than a claim of production-ready live performance.
- Case study PDF: professional write-up with methods, diagnostics, and results (/docs/Meta-Labeling Alpha Filter - Case Report.pdf).
- Reproducible pipeline: point-in-time (PIT) universe, leakage-safe labeling, calibrated base models, classwise convex blender stacker, probability-aware execution, costs, and risk overlays.
- Artifacts: run manifest, config snapshot, and fold fingerprints saved per run for traceability.
Branches.
maincontains the classwise convex blender stacker used for the reported results.experimentalpreserves MLP stacker variants and related meta-feature experiments for reference.
- Filter first, trade second. We predict resolution (TP before SL/timeout), not raw direction.
- Calibration before control. Decisions ride on calibrated class probabilities; thresholds, margins, and sizes are meaningful only if probabilities are reliable.
- Stack on probabilities, not features. A classwise convex blender combines LightGBM & MLPv1 after calibration—stable, leakage-safe, and monotone.
- Execution hygiene. Close→next-close PnL, asymmetric long/short costs on executed turnover, EWMA(63) vol targeting to a risk budget, and a hard gross cap.
# 1) Install
python -m venv .venv && source .venv/bin/activate # (Windows: .venv\Scripts\activate)
pip install -r requirements.txt
# 2) Put inputs in place (one-time)
# data/ should contain:
# - S&P 500 PIT constituents snapshot (CSV you downloaded at project start)
# - FRED series (DGS10, T10Y3M) as CSVs
# Then fetch OHLCV via:
python -m src.data_download
# 3) Run the full pipeline (Fold-1→3)
python -m src.main
# 4) Browse results
open results/performance_summary.xlsx
Outputs:
results/performance_summary.xlsx— headline summary table used in the reportresults/— backtest tables, strategy plots, and model diagnosticsshap/— SHAP summaries and explainability outputsruns/<timestamp>/— full run snapshot including manifests, fingerprints, logs, and generated artifactsdocs/— polished case report PDF: Meta-Labeling Alpha Filter - Case Report.pdf
Note: blend and beta-neutral variants show N/A for trade-level statistics by design, since they are portfolio constructs rather than direct trade streams.
- Labeling:
PT_SL_FACTOR=(5,5),MAX_HOLDING_PERIOD=63,VOL_WINDOW=63.THRESHOLD_LONG=0.45,..._SHORT=0.50,MIN_GAP=0.10,TOP_K_PER_DAY=3,META_SCORE_MODE="edge". - Sizing:
PROB_WEIGHTING=True,WEIGHT_MODE="margin". - Risk:
TARGET_VOL=0.20,VOL_SPAN=63,LEVERAGE_CAP=3. - Costs:
LONG_SIDE_TC=10bps,SHORT_SIDE_TC=20bps (per-side, on executed turnover).
Defaults are conservative; thresholds, Top-K, and risk caps are easy to sweep.
- PIT S&P 500 membership and symbol normalization; SPY/VIX context series snapshotted.
- Time-ordered folds: discovery (Fold-1), calibration + stacker (Fold-2), true OOS (Fold-3).
- Leakage-safe calibration: vector-scaled softmax fit only on prior data; applied forward.
- Determinism: global seeds; manifests and config snapshots written each run.
Every run writes: manifest.json (env + code hash), config_snapshot.json (resolved parameters), fold_fingerprints.json (fold dates/hashes), and run.log.jsonl (timeline).
Data sources: S&P 500 PIT membership (Aultman, MIT-licensed snapshot), Yahoo Finance OHLCV (auto-adjusted), SPY/VIX context; FRED 10Y and 10Y–3M.
meta-labeling-alpha-filter/
├── data/ # inputs: PIT constituents snapshot, FRED CSVs (DGS10, T10Y3M), yfinance caches
├── docs/ # the PDF case report
├── figures/ # GENERATED: model calibration curves and diagnostics
├── models/ # GENERATED: saved models
├── results/ # GENERATED: backtest tables/plots and model diagnostics
├── runs/ # GENERATED: per-run folders (manifests, fingerprints, logs)
├── shap/ # GENERATED: SHAP summaries & values
├── src/ # code (orchestrator + modules)
│ ├── main.py # orchestrates the full pipeline end-to-end
│ ├── config.py # single source of truth for folds, costs, sizing knobs, thresholds
│ ├── data_download.py # PIT OHLCV (yfinance), SPY/VIX; writes parquet
│ ├── data_loader.py # leak-safe loaders; alignment & resampling
│ ├── labeling.py # triple-barrier labels
│ ├── features.py # point-in-time feature set (micro + regime)
│ ├── modeling.py # LightGBM w/ TS-CV + calibration
│ ├── mlp_modeling.py # MLP w/ nested TS-CV + calibration
│ ├── analysis.py # model diagnostics (AUC/log-loss, reliability, SHAP hooks)
│ ├── signals.py # gating (threshold + gap), ranking (edge/logit_edge), Top-K
│ ├── sizing.py # prob→weights maps, λ-blend (hysteresis), vol-target, leverage cap, costs
│ ├── evaluation.py # PnL, alpha/beta, underwater, rolling Sharpe/corr; summary table
│ ├── strategy.py # base cross-sectional momentum logic
│ └── utils.py / notifications.py
├── config_snapshot.json # latest run’s resolved config (handy to diff)
├── fold_fingerprints.json# fold boundaries + hashes for reproducibility
├── manifest.json # environment + code hash snapshot
├── run.log.jsonl # per-run log with time stamps and key events
The source code in this repository is licensed under the BSD 3-Clause License. See the LICENSE file for details.
The case report PDF remains licensed separately under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License (CC BY-NC-ND 4.0).
Gautier Petit
