Skip to content

Getting started

Install

pip install overfitlab

Python 3.12 or later. pip install overfitlab[polars] lets array arguments take Polars series and frames.

Deflate a Sharpe ratio

A backtest shows an annual Sharpe ratio of 2.5 over five years, the best of 100 trials. Its returns are skewed and fat-tailed.

import overfitlab as ol

sr = 2.5 / 250**0.5  # per period
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

Statistics take per-period Sharpe ratios unless a name ends in _annual, and kurtosis is non-excess, so a normal distribution has 3.

The same case from the command line:

overfitlab dsr --sr-annual 2.5 --periods-per-year 250 --n-obs 1250 --skew -3 --kurtosis 10 --n-trials 100 --var-trials-annual 0.5

Test a whole set of trials

With a T x N matrix of returns, one column per trial:

import numpy as np
import overfitlab as ol

returns = np.random.default_rng(0).normal(0.0, 0.01, (1260, 1000))
report = ol.evaluate(returns)
print(report.verdict)  # FAIL
print(report.reasons)

evaluate applies the gate: DSR, PBO, SPA, the stepdown and the haircut must all pass.

Cross-validate with overlapping labels

PurgedKFold and CombinatorialPurgedCV work as a scikit-learn cv= argument:

import numpy as np
import overfitlab as ol

t1 = np.arange(1000) + 20  # each label ends 20 bars after it starts
cv = ol.PurgedKFold(5, t1=t1, embargo_pct=0.01)
for train, test in cv.split(np.zeros(1000)):
    pass

Log your trials

import overfitlab as ol

trials = ol.TrialLogger("results/trial_log.csv", "results/runs")
run_id = trials.log(
    strategy_family="ma_cross",
    params={"fast": 5, "slow": 60},
    dates=["2024-01-02", "2024-01-03", "2024-01-04"],
    returns=[0.01, -0.02, 0.03],
)

Then check and evaluate the log:

overfitlab trials validate results/trial_log.csv
overfitlab trials report results/trial_log.csv

The format is in the trial-log contract, and trial counting explains what counts as a trial.

Reproduce the study

uv sync
uv run olab-study all

Real-data steps need the raw files first, and are skipped with a message if they're missing. See README.md for the data commands.