Value Bet Identification¶
Summary¶
A value bet is a wager where the bettor's estimated probability of an outcome exceeds the bookmaker's implied probability, creating positive expected value (+EV). The identification of value bets is the central skill in profitable sports betting — the bettor must be more accurate than the market in estimating true probabilities.
Value bet identification requires: (1) a predictive model that produces better probabilities than the market, (2) de-vigged odds to get fair market probabilities, and (3) a filter/threshold for placing bets based on minimum EV or edge requirements.
The process works as follows: the model produces probabilities → odds are de-vigged → EV = model_prob × bookie_odds - 1 → if EV > threshold, bet is placed.
The challenge is that bookmakers are generally efficient — especially for high-profile events like the World Cup. Finding consistent value requires either better models, faster information access, or specialized data sources.
Key Concepts¶
- True probability: The actual likelihood of an outcome (never known exactly). The model's job is to estimate this better than the market.
- Implied probability: The probability embedded in bookmaker odds = 1/decimal_odds. Must be de-vigged to get fair market estimate.
- Overlay: When bookmaker odds are higher than fair odds → the bet is "overlaid" or has positive edge.
- Minimum edge threshold: Most professional bettors only bet when edge exceeds 3-5%. Lower thresholds generate too many low-edge bets that don't cover transaction costs.
- Closing line value as validator: If a bettor consistently finds value (gets positive CLV), it confirms genuine predictive edge.
- Market efficiency hierarchy: Sharp books (Pinnacle) are more efficient than soft books (DraftKings). Finding value is easier against soft books.
Formulas¶
Value / Edge:
$$\text{edge} = \frac{\text{bookie_odds}}{\text{fair_odds}} - 1$$
Or equivalently: edge = (model_prob × bookie_odds) - 1
Minimum edge filter:
$$\text{bet_if}: \left(\frac{\text{model_prob}}{\text{implied_prob}} - 1\right) > \text{threshold}$$
Example: model estimates Brazil 60% win (fair odds = 1.667), bookie offers 1.85 (implied = 54.1%). Edge = 60/54.1 - 1 = 10.9%. This exceeds a 5% threshold → bet.
Value bet probability:
$$P(\text{value bet}) = \frac{\text{odds}}{\text{fair_odds}} = \frac{p_{\text{model}}}{p_{\text{implied}}}$$
Python Implementation¶
import pandas as pd
import numpy as np
def find_value_bets(matches_df, min_edge=0.05, bookie_col='odds'):
"""
Identify value bets from model predictions and bookmaker odds.
Args:
matches_df: DataFrame with model_prob and odds columns
min_edge: Minimum edge threshold to place bet (default 5%)
bookie_col: Column name with bookmaker decimal odds
Returns:
DataFrame of value bets with edge and Kelly stake
"""
matches = matches_df.copy()
# Implied probability (de-vigged)
matches['implied_prob'] = 1 / matches[bookie_col]
# Overround removal (multiplicative)
matches['prob_sum'] = matches['implied_prob'] # For multi-outcome: sum over all
# For 2-way: simple approach
matches['fair_prob'] = matches['implied_prob'] / matches['prob_sum']
# Edge calculation
matches['edge'] = (matches['model_prob'] / matches['fair_prob']) - 1
# Filter for value bets
value_bets = matches[matches['edge'] >= min_edge].copy()
value_bets['ev'] = matches['model_prob'] * matches[bookie_col] - 1
# Sort by edge (highest first)
value_bets = value_bets.sort_values('edge', ascending=False)
return value_bets
def simulate_value_betting(bets_df, bankroll=10000, kelly_fraction=0.5, min_edge=0.03):
"""
Simulate value betting strategy over historical bets.
"""
results = []
current_bankroll = bankroll
for _, bet in bets_df.iterrows():
edge = bet['edge']
if edge < min_edge:
continue
# Kelly stake
b = bet['odds'] - 1
p = bet['model_prob']
f_full = max((p * b - (1-p)) / b, 0)
stake = current_bankroll * f_full * kelly_fraction
# Outcome
result = 1 if np.random.random() < p else 0
pnl = stake * (bet['odds'] - 1) if result == 1 else -stake
current_bankroll += pnl
results.append({
'bankroll': current_bankroll,
'stake': stake,
'pnl': pnl,
'edge': edge
})
return pd.DataFrame(results)
# Real usage: combine model predictions with The Odds API
# 1. Fetch odds from The Odds API
# 2. De-vig to get fair probabilities
# 3. Compare model output to fair probabilities
# 4. Place bets where edge > threshold (e.g., 5%)
Notes¶
- Value betting requires discipline: bet only when edge exceeds threshold, not based on "feeling" or intuition
- Market efficiency varies: World Cup odds are highly efficient due to public attention; less prominent leagues have more inefficiency and more value opportunity
- The key question for the World Cup model: does it produce probabilities that are consistently more accurate than the closing line? If yes, value betting is profitable. If not, even +EV bets lose money.
- OddsJam and similar tools automate value bet finding by comparing odds across dozens of sportsbooks
- For the MVP: the pipeline should score all matches, compute EV vs. de-vigged odds, filter for positive EV, then rank by EV magnitude before sending Telegram notifications