Skip to main content

BacktestBuddy

Tests

Backtest sports-betting strategies in Python: a sequential bankroll simulation over your historical odds, with staking strategies, risk metrics, closing line value, and interactive Plotly charts.

Works with any data source: you pass a pandas DataFrame and tell BacktestBuddy which columns hold the odds, the outcome, the date, and your model output.

Python >= 3.9 · MIT license

Features

  • Two ways to backtest: PredictionBacktest for predictions you already have, ModelBacktest to train an sklearn-style model walk-forward.
  • Strategies: fixed stake, Kelly criterion, value betting, unit staking, edge-proportional staking, odds-band filter, and risk limits (stake caps, daily limits, loss pauses, drawdown stop).
  • Strategy toolkit: combine any outcome selector with any stake sizer, e.g. value-bet selection with Kelly sizing, or write your own block in a few lines.
  • Simultaneous matches: size same-day bets from the day's opening bankroll and cap their total Kelly stake.
  • Metrics: ROI, Yield, CAGR, Sharpe, Sortino, Calmar, drawdown, calibration (Brier, log loss, ECE), and a market baseline.
  • Closing line value: compare the odds you took with any later or sharper line.
  • Margin removal: multiplicative, additive, power, and Shin methods.
  • Odds stress test: re-run with 1%, 2%, 3% worse odds to see how robust the edge is.
  • Hyperparameter tuning: evaluate() returns only the metrics an optimizer like Optuna needs, several times faster than a full run, plus a holdout split helper.
  • Charts: bankroll and drawdown, reliability diagram, odds distribution.

Installation

pip install backtestbuddy

Quick example

import numpy as np
import pandas as pd
import backtestbuddy as btb

# One row per match: date, decimal odds per outcome, actual outcome (0-based), model output
rng = np.random.default_rng(0)
n = 500
p_home = rng.uniform(0.3, 0.7, n)
data = pd.DataFrame({
    "date": pd.date_range("2023-01-01", periods=n, freq="D"),
    "odds_home": np.round(0.95 / p_home, 2),
    "odds_away": np.round(0.95 / (1 - p_home), 2),
    "winner": (rng.uniform(size=n) > p_home).astype(int),  # 0 = home, 1 = away
})
model_p = np.clip(p_home + rng.normal(0, 0.05, n), 0.01, 0.99)
data["prob_home"] = model_p
data["prob_away"] = 1 - model_p
data["prediction"] = (model_p < 0.5).astype(int)

backtest = btb.PredictionBacktest(
    data=data,
    odds_columns=["odds_home", "odds_away"],
    outcome_column="winner",
    date_column="date",
    prediction_column="prediction",
    model_prob_columns=["prob_home", "prob_away"],
    strategy=btb.KellyCriterion(downscaling=0.5),
    initial_bankroll=1000,
)
backtest.run()

metrics = backtest.calculate_metrics()
print(metrics["ROI [%]"], metrics["Yield [%]"], metrics["Max Drawdown [%]"])
# This toy model is only noise around the true odds, so the 5% margin wins: expect a loss.
backtest.plot()  # interactive Plotly chart

Documentation

Browse the docs locally with pip install backtestbuddy[docs] and mkdocs serve.

Development

The project uses uv. From a clone of the repository:

uv run --extra test pytest          # full test suite, including every docs example
uv run --extra docs mkdocs serve    # docs at http://127.0.0.1:8000

GitHub Actions runs the tests on Python 3.9 to 3.13 and builds the docs for every pull request.

Metadata

Release files for backtestbuddy 0.3.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 backtestbuddy 0.3.0
File Size Uploaded Provenance
backtestbuddy-0.3.0.tar.gz 121.4 kB Without provenance Details

Built distribution (wheel)

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

Total release size: 176.8 kB

Release files / backtestbuddy-0.3.0.tar.gz

Download URL backtestbuddy-0.3.0.tar.gz
Size 121.4 kB
Tags Source
SHA-256 checksum
How to use checksums
5c125c966531f33ae0f6aa4c4d27f996ac721da184e4121b3f958309fb52345e
BLAKE2b-256 checksum
How to use checksums
6bd296e35635998711a85d42e469efedc55cac443d8f2086886d59a4926784d8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.2

Release files / backtestbuddy-0.3.0-py3-none-any.whl

Download URL backtestbuddy-0.3.0-py3-none-any.whl
Size 55.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
401ea7519eb0097367216dfe2cc8de848ed1db11b439bce60601d45c6abadd5d
BLAKE2b-256 checksum
How to use checksums
6fc1c59c65172939a9a5cde4ef140c481639c1de328fbd074afb6d679293f2a9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.2

Security for backtestbuddy 0.3.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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

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.

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