Skip to content

Note

Click here to download the full example code

A bettor of your own

This example shows BaseBettor and derive_complementary_events.

# Author: Georgios Douzas <gdouzas@icloud.com>
# Licence: MIT

import matplotlib.pyplot as plt
import numpy as np
from sklearn.model_selection import TimeSeriesSplit

from sportsbet.dataloaders import DataLoader
from sportsbet.evaluation import BaseBettor, backtest, derive_complementary_events
from sportsbet.sources import SampleSoccerOdds, SampleSoccerStats

Two methods to implement

A bettor turns probabilities into bets. Implement _fit and _predict_proba, and the value bets, the backtest and the bankroll all follow. The bettor places a bet when the probability your model gives an outcome is higher than the probability the price implies.

class BaseRateBettor(BaseBettor):
    """A bettor that knows only how often each outcome has happened."""

    def _fit(self, X, Y, O):
        # `Y` carries the markets it was told to bet, in the order it was told them.
        self.rates_ = Y.mean().to_numpy()
        return self

    def _predict_proba(self, X):
        rates = np.tile(self.rates_, (len(X), 1))
        return rates / rates.sum(axis=1, keepdims=True)

Extracting the data

dataloader = DataLoader(
    param_grid={'league': ['England']},
    stats=SampleSoccerStats(),
    odds=SampleSoccerOdds(),
)
X_train, Y_train, O_train = dataloader.extract_train_data(odds_type='market_average')

Betting with it

bettor = BaseRateBettor(betting_markets=['home_win', 'draw', 'away_win'])
_ = bettor.fit(X_train, Y_train, O_train)
bettor.predict_proba(X_train)

Out:

array([[0.46052632, 0.21578947, 0.32368421],
       [0.46052632, 0.21578947, 0.32368421],
       [0.46052632, 0.21578947, 0.32368421],
       ...,
       [0.46052632, 0.21578947, 0.32368421],
       [0.46052632, 0.21578947, 0.32368421],
       [0.46052632, 0.21578947, 0.32368421]], shape=(380, 3))
backtest(bettor, X_train, Y_train, O_train, cv=TimeSeriesSplit(3))

Out:

                                                       Number of betting days  ...  Yield percentage per bet (away_win)
Training start Training end Testing start Testing end                          ...                                     
2023-08-11     2023-10-28   2023-10-29    2023-12-30                       57  ...                                  1.7
               2023-12-30   2023-12-30    2024-03-30                       66  ...                                -36.2
               2024-03-30   2024-03-30    2024-05-19                       56  ...                                -41.9

[3 rows x 11 columns]

Which markets are mutually exclusive

The probabilities of a group of complementary markets must sum to one. The groups come from the data, not from a list somebody wrote down. A sport that cannot be drawn has two outcomes instead of three, and nothing had to be told which sport this is.

derive_complementary_events(['home_win', 'draw', 'away_win', 'over_2.5', 'under_2.5'])

Out:

[['home_win', 'draw', 'away_win'], ['over_2.5', 'under_2.5']]
derive_complementary_events(['home_win', 'away_win'])

Out:

[['home_win', 'away_win']]

A picture of it

markets = bettor.betting_markets_.tolist()

fig, ax = plt.subplots()
ax.bar(markets, bettor.predict_proba(X_train)[0])
ax.set_title('The base rates of the Premier League season')
ax.set_ylabel('probability')

The base rates of the Premier League season

Out:

Text(42.722222222222214, 0.5, 'probability')

Total running time of the script: ( 0 minutes 1.780 seconds)

Download Python source code: plot_custom_bettor.py

Download Jupyter notebook: plot_custom_bettor.ipynb

Gallery generated by mkdocs-gallery