Quant for Free
Library pointer

oos-lab: validation stats for strategies you already backtest

Most backtests are fantasies. oos-lab is an MIT Python toolkit that computes the statistical checks — PSR, Deflated Sharpe, PBO/CSCV, walk-forward and CPCV splitters, Harvey–Liu haircuts — so you can tell whether yours is real. No buy/sell signals. No performance claims of its own. Bring your own engine.

Install & import

v0.4

PyPI package oos-lab. Requires Python ≥ 3.10; depends only on numpy and scipy. Every public symbol is re-exported from oos_lab.

pip install oos-lab
MIT numpy + scipy 56 unit tests Alpha
Open GitHub → On-site DSR calculator

Library vs calculator

choose
  • Use the Deflated Sharpe calculator Quick browser check: you already have an annualized Sharpe, an observation count, and a trial count. No install, nothing leaves your device.
  • Use oos-lab in Python You have return series (or a matrix of variant returns), need PBO/CSCV, WalkForward / CombinatorialPurgedKFold index splits, or a Harvey–Liu haircut across many Sharpes — wired into your own backtester.
  • Use both Screen candidates in the browser; reproduce and automate the same DSR/PSR ideas in code with deflated_sharpe_ratio and friends before you trust a live book.

What v0.4 actually exposes

Documented from the upstream README and oos_lab/__init__.py — not invented. Public API (also exported as PBOResult and HaircutResult dataclasses):

Metrics

Sharpe / PSR / DSR

sharpe_ratio (annualised, ddof=1), probabilistic_sharpe_ratio (Bailey & López de Prado 2012), deflated_sharpe_ratio + expected_max_sharpe (2014 false-strategy theorem).

Cross-validation

Walk-forward & CPCV

WalkForward — anchored or rolling index splitter. CombinatorialPurgedKFold — combinatorial purged CV with embargo (López de Prado 2018 / AFML Ch.12.4).

Overfitting

PBO & haircut

probability_of_backtest_overfit via CSCV (returns PBO + degradation regression). haircut_sharpe — Harvey & Liu (2015) with Holm–Bonferroni or BHY.

deflated_sharpe_ratio

returns, n_trials, var_sharpe_across_trials

Sets the PSR benchmark to expected_max_sharpe(...). Needs ≥4 observations; Sharpe units are per-period inside the PSR/DSR path.

probability_of_backtest_overfit

returns_matrix (n_obs × n_variants), n_partitions=16

CSCV over even partitions (≥4). Returns PBOResult with .pbo and .performance_degradation_slope.

WalkForward

train_size, test_size, step, anchored

.split(n) yields (train_idx, test_idx). Anchored grows from t=0; otherwise the window slides.

haircut_sharpe

sharpes, n_obs, method="holm"|"bhy", alpha=0.05

Adjusted p-values inverted back to haircut Sharpes; survives_at_alpha mask on the result.

Per-module write-ups live in the repo docs/ folder (sharpe, psr, deflated_sharpe, walk_forward, cpcv, pbo, haircut, plus overview). Roadmap on the README: v0.5 bootstrap CIs for DSR; v0.6 minimum backtest / track-record length helpers.

Quickstart (from upstream README)

Illustrative random returns only — not a strategy result. Paste into a notebook after pip install oos-lab:

import numpy as np
from oos_lab import (
    sharpe_ratio,
    probabilistic_sharpe_ratio,
    deflated_sharpe_ratio,
    expected_max_sharpe,
    WalkForward,
    CombinatorialPurgedKFold,
    probability_of_backtest_overfit,
    haircut_sharpe,
)

rng = np.random.default_rng(0)
returns = rng.normal(0.0008, 0.012, size=1000)

print("Sharpe annualised:", sharpe_ratio(returns, periods_per_year=252))
print("PSR vs zero      :", probabilistic_sharpe_ratio(returns))
print("DSR over 1000    :", deflated_sharpe_ratio(
    returns, n_trials=1000, var_sharpe_across_trials=0.04))
print("Expected max SR  :", expected_max_sharpe(1000, 0.04))

# PBO needs a matrix of variant returns: shape (n_obs, n_variants)
variants = rng.normal(0.0002, 0.012, size=(1000, 20))
result = probability_of_backtest_overfit(variants, n_partitions=16)
print("PBO              :", result.pbo)
print("Degradation slope:", result.performance_degradation_slope)

For walk-forward index splits, construct WalkForward(train_size=..., test_size=..., anchored=...) and iterate .split(n). For CPCV, use CombinatorialPurgedKFold(n_splits=..., n_test_splits=..., embargo_pct=...) with a label-end vector t1. Full signatures and purge notes are in the source docstrings.

Where this sits on Quant for Free

The on-site Deflated Sharpe calculator is the interactive front door to the same Bailey & López de Prado idea. The planned Learn lesson Deflated Sharpe Ratio walks the derivation; Module 5 — Validation Gauntlet places DSR next to the rest of the selection-bias stack. For the splitter side, pair this library with the walk-forward guide (Walk-Forward Optimization in Pure Python, planned) and the existing backtest overfitting guide.

Questions

What is oos-lab?
An MIT-licensed Python validation toolkit for systematic strategies (v0.4). It exposes Sharpe, Probabilistic Sharpe, Deflated Sharpe, expected max Sharpe, WalkForward and CombinatorialPurgedKFold splitters, Probability of Backtest Overfitting via CSCV, and a Harvey–Liu multiple-testing haircut. Dependencies: numpy and scipy only.
When should I use oos-lab vs the on-site Deflated Sharpe calculator?
Use the calculator for a fast single-figure check in the browser. Use oos-lab when you need return-series inputs, PBO over many variants, time-series CV splitters, or Harvey–Liu haircuts inside a Python research stack.
Does it backtest or generate signals?
No. Upstream is explicit: not a backtester, not a strategy, no buy/sell logic. You supply returns or indices; it returns statistics.
Is this investment advice?
No. Educational and methodological use only. The library and this page evaluate backtest statistics; they do not recommend any security, strategy, or trade, and make no claim about future results.
Educational tool, not investment advice. This page points at an open-source statistics library and does not predict performance or recommend any trade. Simulated and backtested results have inherent limitations (see CFTC Rule 4.41 language in the upstream README). Verify any figure independently. Past results, real or simulated, do not guarantee future outcomes. See the disclaimer.