Skip to main content

sports-betting

ci doc

Category Tools
Development black ruff mypy docformatter
Testing pytest coverage interrogate
Security safety bandit
Automation nox pre-commit
Package version pythonversion downloads
Documentation mkdocs
Communication discussions

Introduction

sports-betting is a set of tools for building, testing, and using sports betting models. You can use it from an AI agent, from Python, or from the command line.

The library has two main parts, dataloaders and bettors.

  • A dataloader downloads the data and shapes it for modelling. You build it from a statistics source and an odds source. You choose both, so you always know where your data came from.
  • A bettor backtests a betting strategy and predicts the value bets of upcoming events. It wraps any scikit-learn estimator.

A bettor finds value bets. The execution part places one of them. It takes a fitted bettor, one match, and a stake. It watches the match. At the moment the model was fitted for, it places the bet once. Some bookmakers have a betting API, and the library places the bet through the API. Other bookmakers have no API, so your agent drives their website on your own account. You place the bet at a bookmaker where you hold an account. This spends real money.

Installation

Install

sports-betting is on PyPI. Install it with pip.

pip install sports-betting

MCP server

The MCP server lets you drive the library from an AI agent. Install it with the mcp extra.

pip install 'sports-betting[mcp]'

Execution

Execution places bets. It also drives a bookmaker's website, which needs a browser. Install the extras, then install the browser.

pip install 'sports-betting[mcp,execution]'
python -m playwright install chromium

Development

For development, clone the repository and install the project with PDM. This installs the main and development dependencies.

git clone https://github.com/georgedouzas/sports-betting.git
cd sports-betting
pdm install

Quick start

AI agent

The agent is a first-class way to use the library. It reaches everything that Python and the command line reach. It also does more. It explores the data, builds tables, plots results, and writes the model. A betting model is a scikit-learn estimator. An agent can write one, run it, and tell you how well it did.

Install the MCP server and register it with your agent.

pip install 'sports-betting[mcp]'
claude mcp add sportsbet -- sportsbet-mcp

You can then ask the agent to work through a full task. A typical session runs in these steps.

  • Ask what data is available. The agent reads the catalogue, which is free.
  • Ask for a strategy on some leagues and seasons. The agent downloads the seasons and backtests models.
  • Ask which league holds the edge. The agent breaks the result down.
  • Ask for the value bets in the upcoming fixtures. The agent extracts the fixtures and applies the model.
  • Ask it to place a bet. The agent runs the single-event execution.

The agent names the environment variable that holds your API key. It never prints the key. Extracting the data downloads it, so a paid odds feed spends money only when you extract. Extract once and save the dataloader instead of extracting again. Driving a bookmaker's website on your account breaches most bookmakers' terms of service and risks the account and its balance.

Python API

You can do the same work in code. You build a dataloader from a statistics source and an odds source.

from sportsbet.dataloaders import DataLoader
from sportsbet.sources import FootballDataOdds, FootballDataStats

dataloader = DataLoader(
    param_grid={'league': ['Germany', 'Italy', 'France'], 'division': [1, 2], 'year': [2021, 2022, 2023, 2024]},
    stats=FootballDataStats(),
    odds=FootballDataOdds(),
)
X_train, Y_train, O_train = dataloader.extract_train_data(odds_type='market_maximum')
X_fix, _, O_fix = dataloader.extract_fixtures_data()

A betting model is any scikit-learn estimator wrapped in a bettor. The next example backtests a bettor that wraps a logistic regression classifier.

from sklearn.compose import make_column_transformer
from sklearn.impute import SimpleImputer
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import TimeSeriesSplit
from sklearn.multioutput import MultiOutputClassifier
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import OneHotEncoder
from sportsbet.evaluation import ClassifierBettor, backtest

classifier = make_pipeline(
    make_column_transformer(
        (OneHotEncoder(handle_unknown='ignore'), ['league', 'home_team', 'away_team']), remainder='passthrough'
    ),
    SimpleImputer(),
    MultiOutputClassifier(LogisticRegression(solver='liblinear', random_state=7, class_weight='balanced')),
)
bettor = ClassifierBettor(classifier, betting_markets=['draw'], init_cash=10000.0, stake=50.0)
backtest(bettor, X_train, Y_train, O_train, cv=TimeSeriesSplit(5))
                                                       Number of betting days  Number of bets  Yield percentage per bet  ROI percentage  Final cash
Training start Training end Testing start Testing end
2020-08-21     2021-02-27   2021-02-27    2021-11-06                     625            1247                       3.6            22.3     12234.0
               2021-11-06   2021-11-06    2022-05-14                     645            1305                       3.4            22.0     12205.0
               2022-05-14   2022-05-15    2023-02-25                     639            1349                      -2.3           -15.8      8420.0
               2023-02-25   2023-02-26    2023-11-06                     637            1344                       6.7            44.9     14491.5
               2023-11-06   2023-11-06    2024-06-02                     659            1348                       8.0            54.1     15409.5

Fit it with bettor.fit(X_train, Y_train, O_train), then bettor.bet(X_fix, O_fix) returns the value bets of the upcoming matches.

extract_fixtures_data downloads the fixtures separately and returns the upcoming betting events. The training data and the fixtures data share their columns, so the model trained on the history can bet on the fixtures.

CLI

The command line mirrors the API. The dataloader command extracts the data. The evaluation command works a model on it. dataloader train extract downloads the seasons once and saves the dataloader. The evaluation commands read that file, so the download runs once and the training runs once.

# Download the seasons once and save the dataloader
sportsbet dataloader train extract --stats football-data --odds football-data \
  --league Germany --league Italy --league France --division 1 --division 2 \
  --year 2021 --year 2022 --year 2023 --year 2024 \
  --odds-type market_maximum -o dataloader.pkl

# Backtest a model on the saved data
sportsbet evaluation backtest --dataloader dataloader.pkl --model logistic \
  --betting-market home_win --betting-market draw --betting-market away_win \
  --init-cash 10000 --stake 50 --cv 5

# Fit the model once and save it
sportsbet evaluation fit --dataloader dataloader.pkl --model logistic \
  --betting-market home_win --betting-market draw --betting-market away_win \
  -o model.pkl

# Value bets for the upcoming matches, through the fitted model
sportsbet evaluation bet --dataloader dataloader.pkl --bettor model.pkl

The last command prints the value bets of the upcoming matches. --stats and --odds say where the data comes from. dataloader train extract downloads it. The ready-made models cover the common cases. You can also write your own model in a Python file and name it, as in --model models.py:bettor, where bettor is the object below.

# models.py
from sklearn.compose import make_column_transformer
from sklearn.impute import SimpleImputer
from sklearn.linear_model import LogisticRegression
from sklearn.multioutput import MultiOutputClassifier
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import OneHotEncoder
from sportsbet.evaluation import ClassifierBettor

classifier = make_pipeline(
    make_column_transformer(
        (OneHotEncoder(handle_unknown='ignore'), ['league', 'home_team', 'away_team']), remainder='passthrough'
    ),
    SimpleImputer(),
    MultiOutputClassifier(LogisticRegression(solver='liblinear', random_state=7, class_weight='balanced')),
)
bettor = ClassifierBettor(classifier, betting_markets=['draw'], init_cash=10000.0, stake=50.0)

Release files for sports-betting 0.15.1

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

Source distribution (sdist)

Source distribution for sports-betting 0.15.1
File Size Uploaded
sports_betting-0.15.1.tar.gz 241.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sports-betting 0.15.1
File Interpreter ABI Platform
sports_betting-0.15.1-py3-none-any.whl Python 3 none any Details

Total release size: 396.0 kB

Release files / sports_betting-0.15.1.tar.gz

Download URL sports_betting-0.15.1.tar.gz
Size 241.9 kB
Tags Source
SHA-256 checksum
How to use checksums
bc74b1bbdcd480913e4e46b116acf9158968c77f2a33d6d2f965a5533700209e
BLAKE2b-256 checksum
How to use checksums
05b16417a3113591952578572c2853bcf06ace3c04f391eea88e2b0cd3e2863a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

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 Jul 28, 2026.

Transparency log

Release files / sports_betting-0.15.1-py3-none-any.whl

Download URL sports_betting-0.15.1-py3-none-any.whl
Size 154.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d558eb6a4a99ab77a7821255faf3b42fa67f3a97b061fefdbd01351b1e78d62b
BLAKE2b-256 checksum
How to use checksums
c1e187c2553638153a607ebe3ba0dc395cc4a77c938c1140436d65f473604eee
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

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 Jul 28, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.15.1 This release

2 release files

0.15.0

2 release files

0.14.0

2 release files

0.13.1

2 release files

0.13.0

1 release file

0.12.1

1 release file

0.12.0

1 release file

0.11.3

2 release files

0.11.2

2 release files

0.11.0

2 release files

0.10.0

2 release files

0.9.3

2 release files

0.9.2

2 release files

0.9.1

2 release files

0.9.0

2 release files

0.8.1

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.1

2 release files

0.2.9

2 release files

0.2.8

2 release files

0.2.7

2 release files

0.2.6

2 release files

0.2.5

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

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