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, odds-band filter.
  • 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.
  • 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.2.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.2.0
File Size Uploaded Provenance
backtestbuddy-0.2.0.tar.gz 91.3 kB Without provenance Details

Built distribution (wheel)

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

Total release size: 129.9 kB

Release files / backtestbuddy-0.2.0.tar.gz

Download URL backtestbuddy-0.2.0.tar.gz
Size 91.3 kB
Tags Source
SHA-256 checksum
How to use checksums
892d6c879152868f92cb3c8f5cbc361c157a22fb127fc9fc1c43c2716d6895d0
BLAKE2b-256 checksum
How to use checksums
45c90b9951e912a65570029062a77b9bf194ab3ee0f0ec109dc4a6452a83eed3
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.2.0-py3-none-any.whl

Download URL backtestbuddy-0.2.0-py3-none-any.whl
Size 38.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
32b6e764d40ff5e3164a0e10289705f144eec80113a364b20e6cb59cfcbdcdc8
BLAKE2b-256 checksum
How to use checksums
f0876d94892c3c9fddadac2af6dfa7589addcd6c46552092a29c0ea4eb8bc308
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.2.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