Skip to main content

Backtest overfitting study

The statistics that tell a real trading signal from a lucky one, packaged as a library and turned on real research.

overfitlab deflates a backtest for the search behind it. Run 1,000 strategies on pure noise and the best shows a median annual Sharpe ratio of 1.43. It looks publishable, and it's nothing. This project implements the tests that catch that, checks them against the papers and simulations, and applies them to public data and to the owner's own trial logs.

The ten-minute memo gives the argument. The docs site has the API, the theory and a calculator.

Quickstart

pip install overfitlab
import overfitlab as ol

# A 2.5 annual Sharpe ratio over five years, the best of 100 trials.
sr = 2.5 / 250**0.5
result = ol.deflated_sharpe_ratio(
    sr, 1250, n_trials=100, var_trials=0.5 / 250, skew=-3.0, kurtosis=10.0
)
print(round(result.dsr, 4))  # 0.9004

That Sharpe ratio misses the 0.95 bar once its 100 trials and fat left tail are counted. Getting started covers trial logs, cross-validation and the verdict gate.

The problem

Researchers run many backtests and report the best. The best of many noisy trials has a high Sharpe ratio even when no trial has an edge, and a backtest report doesn't show how many trials stood behind it. The hypothesis here is that a small set of published corrections, applied with an honest trial count, separates luck from signal, and that each has failure modes worth measuring.

Data

Raw and licensed data live in data/, which is git-ignored. Only download scripts, aggregates and small synthetic fixtures are committed.

Dataset Cost What it gives
Synthetic returns (GBM, block bootstrap) Free Ground truth for validating every test.
Stooq bulk daily data and Sharadar Free, and the owner's bundle Daily prices for 12 ETFs, 2006 to 2026.
Ken French data library and AQR datasets Free 56 long factor histories for multiple-testing case studies.

AQR data: Century of Factor Premia, Time Series Momentum, Betting Against Beta and Quality Minus Junk, from AQR Capital Management, used with AQR's written permission. This repository publishes aggregate statistics and charts only, not AQR's files or series. | Open Source Asset Pricing | Free | A real "many signals" universe of 212 predictors, release 2026.10. |

Method

Method Question it answers
PSR and MinTRL Is this Sharpe ratio real, given its length and return shape?
DSR and MinBTL Is it real, given how many trials produced it?
PBO via CSCV Does in-sample selection carry over out of sample?
Reality Check, SPA, StepM Does anything in this set beat the benchmark, and which?
Harvey–Liu haircut What is the Sharpe ratio worth after multiple testing?
Purged k-fold and CPCV How do I cross-validate overlapping labels without leaking?

A verdict gate requires the DSR, PBO, SPA, StepM and the haircut to pass together. Trial logs follow a frozen contract, so N and V come from a record and not from memory.

Each method is checked three ways: against the papers' printed examples, against closed-form power, and against independent implementations. Validation has the details.

Results

Experiment Result
Best of 1,000 on noise, 100 seeds Median best Sharpe 1.43. Naive PSR significant in 100 seeds, DSR in 0. Median PBO 0.50.
1,034 factory variants on noise Median best Sharpe 1.13. DSR significant in 0 seeds. Median PBO 0.52.
Leakage on noise, 20-day labels Shuffled k-fold accuracy 0.703, purged 0.495. Gap 0.208.
Factory on 12 ETFs, 1,034 trials Sharpe 0.76 against a bar of 0.83. DSR 0.39, PBO 0.31, verdict FAIL. Holdout Sharpe 0.68.
56 factors from Ken French and AQR 30 survive StepM.
212 OSAP predictors, full history 173 at t > 1.96, 134 at t > 3, 149 after BHY, 96 after StepM.
208 OSAP predictors, after publication 54 at t > 1.96, 24 at t > 3, 9 after BHY, 8 after StepM.

The best of many noise strategies against its DSR

Detection takes a long record. With a true Sharpe ratio of 1 among 100 trials, the Reality Check, SPA and StepM need 20 years for 80% power, and the DSR doesn't reach it within the 20-year grid. See the power curves.

The owner's own trials

Only one of the six projects, equity-factor-pipeline, has a trial log so far.

Family Own N Sharpe SR₀ DSR Verdict DSR at N = 613
composite 305 1.25 2.34 0.000 FAIL 0.000
investment 32 1.00 0.70 0.952 PASS 0.429
low_risk 32 0.80 0.45 0.957 PASS 0.734
momentum 66 0.60 0.73 0.261 FAIL 0.036
quality 44 0.98 0.63 0.951 PASS 0.678
replication 86 0.81 0.60 0.840 FAIL 0.595
size 8 0.09 0.05 0.588 FAIL 0.469
value 40 0.68 0.51 0.802 FAIL 0.412

Three families pass when each is judged alone. They were not found alone: the project ran 613 trials. At that count, no family reaches 0.95. investment fails outright, because the bar of 1.03 is above its Sharpe ratio of 1.00. Which count applies depends on whether the families were independent ideas or one search, so this table can't settle whether they're real. It does show that the verdict turns on that choice.

What failed

  • DSR power (AC-W-02). The DSR rejects less often than its reference: 0.036 against 0.168, 0.149 against 0.207, and 0.003 against 0.056 at the three cells that miss. V is estimated from the same trials as the planted winner, which raises its own bar. A version given the true V matches. This is kept as a finding, and no limit was changed.
  • G-03c. One of the 40 paper examples misses its tolerance by 5e-6. It's a documented exception.
  • Studentised SPA check (AC-W-07). Against bsds.m, 19 of 20 cases agree within 0.013, and StepM agrees in all 20. Case 2 has no positive mean, and bsds.m has no floor there, so it reports p = 1.
  • Own-projects coverage (AC-H-02). One of six projects has a trial log.
  • Holm and BHY on the calculator (FR-34). Deferred. The page gives the exact Bonferroni haircut.

Limitations

  • A trial log records what was run, not what was thought about, so N is a lower bound.
  • The tests here compare with zero. A long-only ETF strategy can beat zero on the equity premium alone, which is why the factory case passes SPA and StepM and still fails the DSR.
  • Fewer predictors survive after publication partly because those samples are shorter, so that drop isn't all decay.
  • PBO measures whether rankings persist, not whether money is made. An edge that died halfway through scores near 0. See when PBO misleads.
  • Power curves assume independent strategies with one planted signal.

How to reproduce

uv sync
uv run olab-study all

The full run takes about an hour and regenerates every table and figure from the data in data/. Without that data, the real-data steps are skipped with a message. --quick runs a reduced version in about two minutes. Each run adds rows to results/experiment_log.csv.

Requirements

  • Purged k-fold with embargo and combinatorial purged CV (CPCV), handling overlapping multi-day labels. (FR-08, FR-09)
  • Probabilistic and Deflated Sharpe Ratio (Bailey and López de Prado), adjusting for skew, kurtosis and the number and variance of trials. (FR-03, FR-05)
  • Probability of Backtest Overfitting via CSCV (Bailey, Borwein, López de Prado and Zhu). (FR-10)
  • Data-snooping tests: White's Reality Check, Hansen's SPA, and the Romano–Wolf stepdown. (FR-12, FR-13, FR-14)
  • Minimum backtest length and a Sharpe ratio haircut calculator (Harvey and Liu). (FR-06, FR-07, FR-33)
  • A strategy factory that generates thousands of parameter variants (crossovers, breakouts, mean reversion) to test against. (FR-15)
  • A synthetic data generator with known ground truth: pure noise, and noise with a planted signal of chosen strength. (FR-16)

Success criteria

Correct and reproducible

  • On pure noise, the best of 1,000 strategies shows a high naive Sharpe while the DSR is not significant and PBO is near or above 0.5. (AC-W-01)
  • On planted-signal data, each test detects the signal at roughly its theoretical power. (AC-W-02: met for PSR, RC, SPA and StepM, missed for the DSR)
  • Implementations reproduce the numerical examples in the original papers to three decimals. (AC-W-03, with G-03c as a documented exception)
  • A simulation shows the accuracy gap between standard k-fold and purged k-fold on overlapping labels. (AC-W-04)

Depth

  • Power curves: how large a true Sharpe, and how long a backtest, each test needs before it detects a signal. (AC-H-01)
  • A table of naive vs deflated Sharpe for your own projects (equity-factor-pipeline, llm-text-alpha, stat-arb-pairs). (AC-H-02: one of six projects so far)
  • Packaged as a pip-installable library with docs and an interactive Sharpe-haircut page. (AC-H-03: docs and calculator are live, and the install from PyPI comes with the first release)
  • A short paper-style writeup a PM could read in ten minutes. (AC-H-04)

Questions this project must answer

Metadata

Release files for overfitlab 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for overfitlab 0.1.0
File Size Uploaded Provenance Actions
overfitlab-0.1.0.tar.gz 52.5 kB With provenance Details for overfitlab-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for overfitlab 0.1.0
File Interpreter ABI Platform Actions
overfitlab-0.1.0-py3-none-any.whl Python 3 none any Details for overfitlab-0.1.0-py3-none-any.whl

Total release size: 113.9 kB

Release files / overfitlab-0.1.0.tar.gz

Download URL overfitlab-0.1.0.tar.gz
Size 52.5 kB
Tags Source
SHA-256 checksum
How to use checksums
e051a60b001802aa05a4f6feeb83a3fe9f18e053f3148f8897e258c54ca6506e
BLAKE2b-256 checksum
How to use checksums
f75c8351abd20ebcbb0ece0ec88da155cdf247be98f09a43744f88289d836799
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.

Transparency log

Release files / overfitlab-0.1.0-py3-none-any.whl

Download URL overfitlab-0.1.0-py3-none-any.whl
Size 61.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
bff2fb1c027f0f800f9ea60c595889def1aec242f81d076a3afdf4f61c96dc2f
BLAKE2b-256 checksum
How to use checksums
6e116e53abe4fa406fdd4516b46dc918d9d176f5ee1674266752fd53325227db
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.

Transparency log

Security for overfitlab 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for overfitlab-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page