footix.strategy package
Submodules
footix.strategy.bets module
- class footix.strategy.bets.Bet(match_id, market, odds, prob_mean, edge_std=None, prob_edge_pos=None, stake=0.0)[source]
Bases:
objectRepresents a single betting opportunity with associated edge information.
- Parameters:
- class footix.strategy.bets.OddsInput(home_team, away_team, odds)[source]
Bases:
objectRepresents the input odds for a match.
- odds
Decimal odds in the format [H, D, A], where: - H: Odds for the home team to win. - D: Odds for a draw. - A: Odds for the away team to win.
footix.strategy.kelly_strategies module
- footix.strategy.kelly_strategies.classic_kelly(list_bets, bankroll)[source]
Compute bet stakes based on the classic Kelly criterion.
This function calculates the stake for each bet in the input list using the traditional Kelly formula. For each bet, it determines the Kelly fraction as the ratio of the estimated edge (i.e., the advantage) over the net odds (odds - 1). Negative Kelly fractions are set to zero, ensuring no bet is made when the edge is unfavorable. The final stake for each bet is computed by multiplying the Kelly fraction by the available bankroll.
- Parameters:
- Returns:
- The list of Bet objects with their ‘stake’ attribute updated according to
the Kelly criterion.
- Return type:
- footix.strategy.kelly_strategies.realKelly(list_bets, bankroll, max_multiple=1, num_iterations=1000, learning_rate=0.1, penalty_weight=1000.0, device='cpu', early_stopping=True, tolerance=5)[source]
Compute the Kelly criterion using a GPU accelerated gradient-based optimizer (PyTorch).
- Parameters:
bankroll (float) – Total bankroll available.
max_multiple (int, optional) – Maximum number of selections to combine. Defaults to 1.
num_iterations (int, optional) – Number of iterations for gradient descent.
learning_rate (float, optional) – Learning rate for the optimizer.
penalty_weight (float, optional) – Weight for the penalty term enforcing the bankroll constraint.
device (str, optional) – Device to run the computations on (“cuda” or “cpu”).
early_stopping (bool, optional) – Whether to stop early if convergence is detected.
tolerance (int, optional) – Tolerance for early stopping.
- Returns:
- A dictionary containing, for each bet with non-negligible stake,
the bet string, the bet odd, and the stake.
- Return type:
- footix.strategy.kelly_strategies.bayesian_kelly(list_bets, lambda_samples, bankroll=100, summary='quantile', alpha=0.3, fraction_kelly=0.5, per_bet_cap=0.9)[source]
Compute the optimal bet sizes using a Bayesian Kelly criterion.
This function uses Monte Carlo samples of the scoring intensities (lambda samples) to estimate the posterior probabilities of match outcomes via a Skellam model. It then computes the Kelly fraction for each bet based on either the mean or a given quantile of the computed fractions. A fraction of the Kelly stake is applied along with per-bet capping.
- Parameters:
list_bets (list[Bet]) – List of bet objects for which to compute the stake.
lambda_samples (dict[str, SampleProbaResult) – Mapping of match IDs to a tuple of numpy arrays representing the lambda samples for home and away teams.
bankroll (float, optional) – Total available bankroll. Defaults to 100.
summary (Literal["mean", "quantile"], optional) – Method to summarize the Kelly fraction computation. If ‘mean’, the average is used; if ‘quantile’, the quantile specified by alpha is used. Defaults to “quantile”.
alpha (float, optional) – Quantile level used if summary is “quantile”. Defaults to 0.3.
fraction_kelly (float, optional) – Proportion of the calculated Kelly stake to bet. Defaults to 0.5.
per_bet_cap (float, optional) – Maximum allowed fraction of the bankroll to wager
0.90. (on a single bet. Defaults to)
- Raises:
ValueError – If the summary parameter is not ‘mean’ or ‘quantile’.
- Returns:
List of bet objects with the calculated stake assigned.
- Return type:
- footix.strategy.kelly_strategies.kelly_shrinkage(list_bets, lambda_samples, per_bet_cap=0.1, bankroll_cap=0.3, bankroll=100, fraction_kelly=0.25)[source]
Compute bet sizes using a shrinkage-adjusted Kelly criterion.
This function calculates the bet stake by applying a shrinkage correction to the classic Kelly criterion. For each bet, the posterior probability is estimated using a Skellam model with lambda samples and its mean and variance are computed. A shrinkage factor is derived from these statistics and is used to adjust the full Kelly fraction. The computed fraction is then capped per bet and scaled by the available bankroll. An overall bankroll cap is also enforced if the sum of bet fractions exceeds a predefined threshold.
- Parameters:
lambda_samples (dict[str, SampleProbaResult) – Dictionary mapping match IDs to probabilities of sampled MCMC trajectory for the game.
per_bet_cap (float, optional) – Maximum fraction of the bankroll allowed on a single bet.
0.10. (Defaults to)
bankroll_cap (float, optional) – Maximum allowed total fraction of the bankroll across
0.30. (all bets. Defaults to)
bankroll (float, optional) – Total available bankroll. Defaults to 100.
fraction_kelly (float, optional) – Fraction of the shrinkage-adjusted Kelly stake to wager.
0.25. (Defaults to)
- Returns:
List of bet objects with their stake updated according to the shrinkage-adjusted Kelly criterion.
- Return type:
- footix.strategy.kelly_strategies.kelly_portfolio_torch(list_bets, lambda_samples, *, per_bet_cap=0.1, bankroll_cap=0.3, bankroll=100.0, fraction_kelly=0.25, iters=5000, lr=0.003, tol=1e-08, verbose=False)[source]
Compute optimal bet sizes using a shrinkage-adjusted Kelly criterion with gradient-based optimization in PyTorch.
This function calculates bet stakes by applying a shrinkage correction to the classic Kelly criterion. It uses gradient ascent to optimize the portfolio allocation while respecting per-bet and total bankroll constraints.
- Parameters:
lambda_samples (dict[str, SampleProbaResult) – Dictionary mapping match IDs to probabilities samples for the game.
per_bet_cap (float, optional) – Maximum fraction of the bankroll allowed on a single bet. Defaults to 0.10.
bankroll_cap (float, optional) – Maximum allowed total fraction of the bankroll across all bets. Defaults to 0.30.
bankroll (float, optional) – Total available bankroll. Defaults to 100.0.
fraction_kelly (float, optional) – Fraction of the shrinkage-adjusted Kelly stake to wager. Defaults to 0.25.
iters (int, optional) – Maximum number of iterations for gradient ascent. Defaults to 5000.
lr (float, optional) – Learning rate for the optimizer. Defaults to 0.003.
tol (float, optional) – Tolerance for early stopping. If the objective value falls below this threshold, the optimization stops. Defaults to 1e-8.
verbose (bool, optional) – If True, prints detailed information about the bankroll usage and possible returns. Defaults to False.
- Returns:
List of bet objects with their stake updated according to the shrinkage-adjusted Kelly criterion.
- Return type:
Notes
The shrinkage factor is derived from the mean and variance of the posterior probabilities, ensuring more robust stake calculations.
The optimization respects both per-bet and total bankroll constraints, projecting the solution back into the feasible region when necessary.
The function uses PyTorch for efficient gradient-based optimization.
Example
>>> bets = [Bet(match_id="match1", market="H", odds=2.5), ...] >>> lambda_samples = {"match1": (np.array([...]), np.array([...]))} >>> optimized_bets = kelly_portfolio_torch( bets, lambda_samples, bankroll=100, verbose=True ) >>> for bet in optimized_bets: >>> print(bet)
footix.strategy.portfolio_management module
- footix.strategy.portfolio_management.stack_bets(bets)[source]
Computes the mean and standard deviation of the edges for a list of bets.
- Parameters:
bets (list[Bet]) – A list of Bet objects, where each Bet contains attributes edge_mean (float) and edge_std (float or None).
- Returns:
- A tuple containing two numpy arrays:
The first array contains the mean edge values.
The second array contains the standard deviation of the edge values, with missing values replaced by 0.0.
- Return type:
tuple[np.ndarray, np.ndarray]
- footix.strategy.portfolio_management.stack_markowitz(bets)[source]
Computes the mean and standard deviation of the bet (and not from the model)
- footix.strategy.portfolio_management.optimise_portfolio(list_bets, bankroll, max_fraction=0.3, alpha=0.05, gamma=None)[source]
Optimizes bet stakes using SciPy’s constrained optimization to maximize return with risk control.
This function uses classical constrained optimization to find the optimal stake allocation that maximizes expected value while maintaining risk constraints. It incorporates Shannon entropy to encourage diversification.
- Parameters:
list_bets (list[Bet]) – List of bets to optimize. Each Bet must have edge_mean and edge_std.
bankroll (float) – Total available funds for betting.
max_fraction (float, optional) – Maximum fraction of bankroll to stake. Defaults to 0.30.
alpha (float, optional) – Risk threshold for chance constraint (probability of loss). Defaults to 0.05.
gamma (float | None, optional) – Entropy bonus weight. If None, defaults to 0.9 * stake_cap. Controls diversification strength.
- Returns:
Input bets with optimized stakes set in their stake attribute.
- Return type:
- Raises:
RuntimeError – If the optimization fails to converge to a valid solution.
Notes
Uses trust-region constrained optimization from SciPy
- Enforces two main constraints:
Total stakes ≤ max_fraction * bankroll
P(portfolio loss) ≤ alpha via chance constraint
- footix.strategy.portfolio_management.optimise_portfolio_torch(list_bets, bankroll, max_fraction=0.3, alpha=0.05, gamma=None, lr=0.05, iters=5000, penalty_lambda=1000.0, verbose=False, device='cpu')[source]
Optimizes bet stakes using PyTorch’s gradient descent with soft constraints.
This function implements portfolio optimization using automatic differentiation and gradient descent. Instead of hard constraints, it uses soft constraints via penalty terms in the loss function.
- Parameters:
list_bets (list[Bet]) – List of bets to optimize. Each Bet must have edge_mean and edge_std.
bankroll (float) – Total available funds for betting.
max_fraction (float, optional) – Maximum fraction of bankroll to stake. Defaults to 0.30.
alpha (float, optional) – Risk threshold for chance constraint. Defaults to 0.05.
gamma (float | None, optional) – Entropy bonus weight. If None, defaults to 0.9 * stake_cap.
lr (float, optional) – Learning rate for Adam optimizer. Defaults to 5e-2.
iters (int, optional) – Number of optimization iterations. Defaults to 5_000.
penalty_lambda (float, optional) – Weight of chance constraint penalty. Defaults to 1_000.0.
verbose (bool, optional) – Whether to print diagnostic information. Defaults to False.
device (str, optional) – PyTorch device to use (‘cpu’ or ‘cuda’). Defaults to “cpu”.
- Returns:
Input bets with optimized stakes set in their stake attribute.
- Return type:
Notes
Uses Adam optimizer with gradient descent
- Enforces constraints softly through penalties:
Stakes positivity via softplus
Total stakes via scaling
Risk control via quadratic penalty
Includes Shannon entropy term for diversification
Provides detailed diagnostics when verbose=True
- footix.strategy.portfolio_management.bayesian_portfolio_optim(list_bets, edge_samples, bankroll, max_fraction=0.3, gamma=None, lr=0.05, iters=3000, verbose=False, device='cpu')[source]
Optimizes bet stakes using Bayesian posterior samples of edge.
This function implements portfolio optimization by maximizing the expected gain marginalized over the uncertainty in edge estimates. It uses Monte Carlo samples from the posterior distribution of edge for each bet.
- The optimization maximizes:
E_θ[Gain] = (1/K) * Σ_k Σ_i edge_i^(k) * s_i
where edge_i^(k) is the k-th posterior sample of edge for bet i.
- Parameters:
list_bets (list[Bet]) – List of bets to optimize. Each Bet must have a match_id and market.
edge_samples (Mapping[Any, Any]) – Dictionary mapping (match_id, market) tuple or match_id to numpy arrays of posterior edge samples. Shape: (n_samples,) for each bet.
bankroll (float) – Total available funds for betting.
max_fraction (float) – Maximum fraction of bankroll to stake. Defaults to 0.30.
gamma (float | None) – Entropy bonus weight for diversification. If None, defaults to 0.5 * stake_cap.
lr (float) – Learning rate for Adam optimizer. Defaults to 5e-2.
iters (int) – Number of optimization iterations. Defaults to 3_000.
verbose (bool) – Whether to print diagnostic information. Defaults to False.
device (str) – PyTorch device to use (‘cpu’ or ‘cuda’). Defaults to “cpu”.
- Returns:
Input bets with optimized stakes set in their stake attribute.
- Return type:
Notes
Uses Adam optimizer with gradient descent
- Enforces constraints softly through scaling:
Stakes positivity via softplus
Total stakes via scaling to respect stake_cap
Includes Shannon entropy term for diversification
Marginalizes over posterior uncertainty in edge estimates
Example
>>> # edge_samples[bet.match_id] contains posterior samples for each outcome >>> edge_samples = { ... ("match1", "H"): np.random.normal(0.1, 0.05, 1000), ... ("match1", "D"): np.random.normal(-0.05, 0.03, 1000), ... } >>> optimized_bets = bayesian_portfolio_optim(bets, edge_samples, bankroll=1000)
footix.strategy.select_bets module
- class footix.strategy.select_bets.Thresholds(edge_floor, prob_edge)[source]
Bases:
NamedTuple
- class footix.strategy.select_bets.OddsRange(min_odds, max_odds, edge, prob_edge=None)[source]
Bases:
NamedTupleRepresents an odds range and its corresponding edge and probability thresholds.
- class footix.strategy.select_bets.EdgeFloorConfig(ranges: Sequence[footix.strategy.select_bets.OddsRange] = <factory>, default_edge_floor: float = 0.0, default_prob_edge: float | None = None)[source]
Bases:
object- Parameters:
- footix.strategy.select_bets.simple_select_bets(odds_input, probas, edge_floor=0.0, single_bet_per_game=True, outcomes=('H', 'D', 'A'))[source]
- footix.strategy.select_bets.select_matches_posterior(odds_input, lambda_samples, *, config=None, edge_floor=0.1, prob_edge_threshold=0.55, single_bet_per_game=True)[source]
Select bets based on posterior probabilities computed from the Skellam distribution.
For each match, posterior probabilities for the home-win, draw, and away-win outcomes are computed. The expected edge is calculated for each outcome. Bets are only selected if the mean edge exceeds the specified edge_floor and the probability of a positive edge is above the prob_edge_threshold. If single_bet_per_game is True, only the bet with the highest mean edge is kept per match.
- Parameters:
lambda_samples (dict[str, tuple[np.ndarray, np.ndarray]]) – Dictionary mapping match_id to lambda samples (home and away) used for posterior probability computation.
edge_floor (float, optional) – Minimum required mean edge to consider a bet.
0.1. (Defaults to)
prob_edge_threshold (float, optional) – Minimum probability of positive edge to consider a bet. Defaults to 0.55.
single_bet_per_game (bool, optional) – If True, only the best bet per match is
True. (selected. Defaults to)
config (EdgeFloorConfig | None)
- Returns:
A sorted list of selected Bet objects, ordered by descending edge_mean.
- Return type:
- footix.strategy.select_bets.select_bets_by_probability(odds_input, probas, prob_floor=0.55, single_bet_per_game=True)[source]
Select bets based on the highest predicted probabilities.
For each match, outcomes with predicted probability greater than or equal to prob_floor are considered. If single_bet_per_game is True, only the outcome with the highest probability (if it meets the threshold) is selected per match. Otherwise, every outcome meeting the threshold is selected.
- Parameters:
- Returns:
A list of Bet objects selected based on the highest probability.
- Return type:
footix.strategy.simple_strategy module
- footix.strategy.simple_strategy.flat_staking(list_bets, bankroll, fraction_bankroll)[source]
Allocate a fixed portion of the bankroll to each bet.
The stake for every bet in
list_betsis set tofraction_bankroll * bankroll. This simple staking strategy assumes that all bets are independent and that the same fraction of the bankroll is used for each one.- Parameters:
- Returns:
The input list with the
stakeattribute updated for each bet.- Return type:
- Raises:
ValueError – If the total required stake exceeds the available bankroll.
Module contents
Betting strategy and portfolio management utilities.
This module provides tools for developing, backtesting, and executing betting strategies based on model predictions and market odds.
- Submodules:
bets: Core betting and odds structures
select_bets: Bet selection and filtering logic
kelly_strategies: Kelly criterion-based strategies
portfolio_management: Portfolio optimization and management