Value betting com IA: como encontrar apostas
Value betting não é sobre acertar mais — é sobre encontrar odds que pagam mais do que deveriam. Com ML, dá pra fazer isso de forma sistemática e
Por que isso é importante
Value betting com IA: como encontrar apostas. Value betting não é sobre acertar mais — é sobre encontrar odds que pagam mais do que deveriam. Com ML, dá pra fazer isso de forma sistemática e escalável. Aqui está como funciona na prática.
A maioria das pessoas que aposta pensa errado sobre o objetivo. O objetivo não é acertar quem vai ganhar. O objetivo é encontrar apostas onde a odd oferecida pela casa paga mais do que a probabilidade real justificaria. Isso é value betting. E ML é uma ferramenta poderosa pra fazer isso de forma sistemática.
Conteúdo puramente educacional e técnico. Não é recomendação de apostas. Verifique as leis do seu país antes de qualquer aplicação prática.
O que é value betting
Imagina que você avalia que um time tem 60% de chance de vencer. A odd de 2.00 implica que a casa acredita que a probabilidade é de 50%. Se você está certo, essa aposta tem valor positivo esperado. Você vai perder muitas vezes — mas a longo prazo, com volume suficiente, as perdas são compensadas pelos retornos maiores quando acerta.
Dá pra fazer value betting sem ML, avaliando manualmente cada aposta. Mas ML escala isso pra centenas de jogos ao mesmo tempo, de forma consistente, sem viés emocional. O modelo analisa dados históricos e estima probabilidades — você compara com o que a casa oferece.
A diferença entre acertar e ter value
Acertar 60% das apostas em odds de 1.50 = ROI negativo (-10% por aposta)
Acertar 45% das apostas em odds de 2.50 = ROI positivo (+12.5% por aposta)
Odds altas com probabilidade real maior que a implícita = value
Value betting é uma prática de longo prazo: no curto prazo, resultados variam muito
A matemática por trás do valor esperado
Expected Value (EV) é a média ponderada do resultado de uma aposta levando em conta todas as possibilidades. EV = (probabilidade de ganho x lucro) - (probabilidade de perda x stake). Se EV for positivo, a aposta tem valor. Simples assim matematicamente, difícil na prática porque você precisa estimar a probabilidade real corretamente.
# Python 3.11+
# Cálculo de Expected Value e Value Betting
def expected_value(prob_win: float, odd: float, stake: float = 1.0) -> dict:
"""
Calcula o valor esperado de uma aposta.
Args:
prob_win: probabilidade estimada de vitória (0 a 1)
odd: odd decimal oferecida pela casa
stake: valor apostado (padrão: 1 unidade)
Returns:
Dict com EV e métricas relacionadas
"""
prob_lose = 1 - prob_win
lucro_se_ganhar = stake * (odd - 1)
perda_se_perder = stake
ev = (prob_win * lucro_se_ganhar) - (prob_lose * perda_se_perder)
prob_implicita = 1 / odd
edge = prob_win - prob_implicita
roi_esperado = ev / stake
return {
"ev": round(ev, 4),
"roi_esperado": f"{roi_esperado:.2%}",
"edge": f"{edge:.2%}",
"tem_value": ev > 0,
"prob_modelo": f"{prob_win:.2%}",
"prob_implicita": f"{prob_implicita:.2%}",
}
# Exemplos
print("=== Análise de Value ===")
exemplos = [
(0.60, 2.00, "Modelo 60%, Odd 2.00"),
(0.45, 2.50, "Modelo 45%, Odd 2.50"),
(0.50, 1.90, "Modelo 50%, Odd 1.90"), # sem value (vig)
(0.55, 2.10, "Modelo 55%, Odd 2.10"),
]
for prob, odd, descricao in exemplos:
resultado = expected_value(prob, odd)
status = "VALUE" if resultado["tem_value"] else "SEM VALUE"
print(f"\n{descricao}")
print(f" Status: {status}")
print(f" EV por R$1 apostado: R$ {resultado['ev']}")
print(f" ROI esperado: {resultado['roi_esperado']}")
print(f" Edge: {resultado['edge']}")Usando ML para detectar value
Treinando com dados históricos
O modelo precisa aprender a estimar probabilidades calibradas — não apenas classificar vencedor/perdedor, mas dar probabilidades que refletem a realidade. Um modelo que diz 70% de chance e acerta 70% das vezes é muito melhor do que um que diz 70% mas acerta só 55%. A calibração é tudo.
Para treinar, você precisa de histórico de resultados com as features dos times. Dados do football-data.co.uk têm mais de 20 anos de resultados de ligas europeias e brasileiras, com estatísticas básicas. Dá pra complementar com APIs pagas como StatsBomb para dados mais granulares.
Modelo de probabilidades implícitas
Um truque pouco discutido: usar as próprias odds das casas como feature no modelo. A odd do mercado já embute informação — é um consenso de muitos agentes com skin in the game. Mas as casas têm viés (margem/vig). Se você modela a probabilidade removendo o viés e adiciona suas próprias features, pode encontrar discrepâncias sistêmicas.
# Python 3.11+
# value_detector.py — detecta apostas com value usando modelo calibrado
import pandas as pd
import numpy as np
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.calibration import CalibratedClassifierCV
from sklearn.model_selection import TimeSeriesSplit
from sklearn.metrics import brier_score_loss
def remover_vig(odd_home: float, odd_draw: float, odd_away: float) -> tuple[float, float, float]:
"""
Remove a margem da casa (vig) das odds.
Retorna probabilidades verdadeiras sem overround.
"""
# Probabilidades brutas (com vig)
p_home = 1 / odd_home
p_draw = 1 / odd_draw
p_away = 1 / odd_away
overround = p_home + p_draw + p_away
# Normaliza pra remover a margem
return p_home / overround, p_draw / overround, p_away / overround
def detectar_value(
prob_modelo: float,
odd_mercado: float,
edge_minimo: float = 0.03
) -> dict:
"""
Verifica se uma aposta tem value.
Args:
prob_modelo: probabilidade estimada pelo modelo
odd_mercado: odd decimal atual
edge_minimo: edge mínimo para considerar value
"""
prob_implicita = 1 / odd_mercado
edge = prob_modelo - prob_implicita
ev = edge * (odd_mercado - 1) - (1 - prob_modelo)
return {
"tem_value": edge >= edge_minimo,
"edge": edge,
"ev_por_unidade": ev,
"prob_modelo": prob_modelo,
"prob_implicita": prob_implicita,
}
def treinar_modelo_calibrado(X: pd.DataFrame, y: pd.Series) -> CalibratedClassifierCV:
"""
Treina modelo com calibração de probabilidade.
Calibração garante que 70% de confiança = 70% de acerto real.
"""
base_model = GradientBoostingClassifier(
n_estimators=200,
learning_rate=0.05,
max_depth=4,
subsample=0.8,
random_state=42
)
# Platt scaling para calibração de probabilidades
calibrated = CalibratedClassifierCV(
base_model,
method="sigmoid",
cv=TimeSeriesSplit(n_splits=5)
)
calibrated.fit(X, y)
# Mede calibração com Brier Score (menor = melhor)
probs = calibrated.predict_proba(X)
brier = brier_score_loss(y == 2, probs[:, 2]) # classe 2 = vitória da casa
print(f"Brier Score (home win): {brier:.4f} (0.25 = random, 0 = perfeito)")
return calibratedImplementação prática em Python
O pipeline completo une coleta de odds, predição do modelo e detecção de value numa única função que você pode rodar periodicamente. A saída é uma lista de oportunidades ordenadas por edge, com todos os dados necessários para decidir se aposta ou não.
# Python 3.11+
# Pipeline completo de value betting
from dataclasses import dataclass
from typing import Any
@dataclass
class ValueBet:
evento: str
bookmaker: str
outcome: str
odd: float
prob_modelo: float
prob_implicita: float
edge: float
ev: float
def encontrar_value_bets(
odds_data: list[dict],
modelo: Any,
features_fn: callable,
edge_minimo: float = 0.03
) -> list[ValueBet]:
"""
Processa lista de odds e retorna apostas com value.
Args:
odds_data: lista de eventos com odds (formato The Odds API)
modelo: modelo treinado com predict_proba
features_fn: função que extrai features de um evento
edge_minimo: edge mínimo para considerar value
"""
oportunidades = []
for evento in odds_data:
# Extrai features do evento
try:
features = features_fn(evento)
probs = modelo.predict_proba([features])[0]
# Assumindo: 0=away, 1=draw, 2=home
mapa = {evento["home_team"]: probs[2], "Draw": probs[1], evento["away_team"]: probs[0]}
except (KeyError, ValueError):
continue
for bookmaker in evento.get("bookmakers", []):
for market in bookmaker.get("markets", []):
if market["key"] != "h2h":
continue
for outcome in market.get("outcomes", []):
prob_modelo = mapa.get(outcome["name"], 0)
odd = outcome["price"]
result = detectar_value(prob_modelo, odd, edge_minimo)
if result["tem_value"]:
oportunidades.append(ValueBet(
evento=f"{evento['home_team']} x {evento['away_team']}",
bookmaker=bookmaker["key"],
outcome=outcome["name"],
odd=odd,
prob_modelo=prob_modelo,
prob_implicita=result["prob_implicita"],
edge=result["edge"],
ev=result["ev_por_unidade"]
))
# Ordenar por edge decrescente
return sorted(oportunidades, key=lambda x: x.edge, reverse=True)Backtesting: funciona mesmo?
A resposta honesta: depende do modelo. Value betting com ML funciona quando o modelo está genuinamente bem calibrado e as features capturam informação que as odds de mercado não refletem completamente. O que não funciona é treinar numa janela e testar na mesma janela — isso é a receita pra backtesting bonito e resultados reais ruins.
Um backtesting honesto usa walk-forward validation: você treina em dados até uma data X, testa nas semanas seguintes, avança X, repete. O resultado é uma curva de equity realista que mostra como o modelo teria performado se fosse colocado em produção gradualmente ao longo do tempo.
Critérios para um backtesting confiável
- Dados de treino e teste separados sem sobreposição temporal
- Pelo menos 3 temporadas completas no conjunto de teste
- Simulação de custo de transação (spread/vig nas odds reais)
- Walk-forward validation em vez de hold-out simples
- Métricas de calibração (Brier score) além de ROI
- Análise de drawdown máximo e duração dos drawdowns
- Teste por liga e por tipo de mercado separadamente