Un bug silenzioso si nasconde in molti sistemi di rilevamento del value: l'EV che mostri dipende da una scelta che nessuno ha mai scritto da qualche parte. Quella scelta è il modello usato per rimuovere il margine del bookmaker. Cambialo, e la stessa scommessa passa da +1,2% a +2,6% di EV — senza che un solo prezzo si sia mosso.
Non è un dettaglio implementativo. È l'assunzione centrale di tutto il tuo stack di pricing: come distribuisce il book la propria commissione tra gli esiti?
Il punto di partenza: la somma supera il 100%
Su una moneyline a 1.55 / 2.55, l'inverso di ogni prezzo dà 64,5% e 39,2%. Totale: 103,7%. Quei 3,7 punti sono il margine. Ogni modello mira a tornare al 100%; differiscono solo nel modo in cui tolgono il surplus.
odds = [1.55, 2.55]
raw = [1 / o for o in odds]
print(f"overround: {sum(raw) - 1:.2%}") # 3.70 %Additivo: togliere la stessa quantità a tutti
Il modello più ingenuo: sottrae una quota uguale del surplus da ogni probabilità. Facile da spiegare, ma tratta un favorito al 90% e un outsider al 5% come se portassero lo stesso carico di margine — cosa vera in nessun bookmaker.
def additive(odds):
raw = [1 / o for o in odds]
excess = (sum(raw) - 1) / len(raw)
return [p - excess for p in raw]Su un mercato molto sbilanciato, l'additivo può restituire una probabilità negativa sul prezzo più alto. Se il tuo codice non ha un controllo per questo caso, produrrà fair odds assurde invece di un errore visibile.
Moltiplicativo: proporzionale
Dividi ogni probabilità per la somma. Veloce, senza parametri, il default nella maggior parte degli strumenti. Su un mercato a due vie stretto è difficile fare meglio. La sua ipotesi — margine distribuito come percentuale uguale — è comunque sbagliata non appena il mercato diventa asimmetrico.
def multiplicative(odds):
raw = [1 / o for o in odds]
total = sum(raw)
return [p / total for p in raw]
# 1.55 / 2.55 → probabilità 62.22 % / 37.78 %Power: piegare la curva
Trova un esponente k tale che la somma delle probabilità elevate a k sia esattamente 1. Invece di spostare le probabilità, deformi la curva: poco effetto sui favoriti, molto sulla coda. Questo comportamento è il più adatto per i mercati a molti esiti.
from scipy.optimize import brentq
def power(odds):
raw = [1 / o for o in odds]
k = brentq(lambda k: sum(p ** k for p in raw) - 1, 0.5, 1.5)
return [p ** k for p in raw]Shin: il margine come premio assicurativo
Shin aggiunge un'ipotesi economica: il book fissa il proprio margine per coprirsi da una proporzione z di scommettitori più informati di lui. Quella proporzione viene stimata dai prezzi stessi, poi rimossa — il che carica più margine sugli outsider, esattamente come fanno i book nella pratica.
def shin(odds, iterations=100):
raw = [1 / o for o in odds]
total = sum(raw)
z = 0.0
for _ in range(iterations):
probs = [
(((z ** 2 + 4 * (1 - z) * p ** 2 / total) ** 0.5) - z) / (2 * (1 - z))
for p in raw
]
s = sum(probs)
z += (s - 1) / 2
return [p / s for p in probs]Odds ratio: un solo parametro di distorsione
Il modello odds-ratio cerca un unico fattore applicato al rapporto di quota (l'"odds" piuttosto che la probabilità) di ogni esito. Spesso arriva vicino a Shin, con un'intuizione più semplice: il book non distorce le probabilità, distorce i rapporti.
Dove i modelli divergono davvero
Su un mercato a due vie equilibrato sono tutti a un soffio: lo scarto tra i cinque modelli resta sotto 0,3 punti di probabilità — dentro il rumore della tua stessa stima. È lontano dalla parità che le decisioni cambiano:
- Favorito netto (1.10 contro 9.00): il moltiplicativo sottostima il favorito e sovrastima l'outsider; lo scarto rispetto a Shin supera un punto pieno sull'outsider.
- 1X2 con un pareggio mal prezzato: power e Shin concordano, il moltiplicativo genera value fittizio sul pareggio.
- Mercati a molti esiti (outright, risultato esatto, marcatori): il moltiplicativo diventa davvero scadente sulle quote alte. Power o Shin, mai lui da solo.
- Handicap asiatici e totals: due vie molto liquide, margine sottile — la scelta del modello conta a malapena, prendi il più veloce.
Un modello di devig non è un'impostazione cosmetica: è la tua ipotesi su come si comporta il bookmaker. Meglio sceglierlo di proposito.
La regola più importante del modello stesso
Qualunque scelta tu faccia, mantienila. La trappola più costosa non è scegliere il modello "sbagliato", è cambiarlo tra backtest e produzione: il tuo EV storico diventa incomparabile con il tuo EV live, e concluderai che il tuo edge è crollato quando si è mosso solo il righello.
- Blocca un modello per famiglia di mercato, e scrivilo da qualche parte.
- Salva il modello usato insieme a ogni EV che registri — altrimenti la tua storia smette di essere interpretabile.
- Prima di regolare la tua soglia di EV, verifica che non sia stato il tuo devig a cambiare.
Farlo lato server
Su apinn i cinque modelli sono implementati lato server e applicati al momento del tick: ogni linea arriva con il suo prezzo di mercato e il suo prezzo fair, secondo il modello che richiedi. Scegli la tua ipotesi per richiesta — o una volta per tutte nelle preferenze del tuo account — e i tuoi backtest usano esattamente la stessa matematica del tuo bot.
curl -H "X-API-Key: $APINN_KEY" \
"https://api.apinn.io/api/odds?event_id=1610000123&model=shin"
# odds1/odds2 = prezzi di mercato
# todds1/todds2 = prezzi fair
# model = power (default) | multiplicative | additive | shin | odds_ratioIl tuo EV si riduce quindi a una divisione — e il dibattito sul devig si chiude una volta, con calma, invece che a ogni tick.
Questi calcoli, su dati reali
Quote Pinnacle in tempo reale con true odds incluse, più storico di apertura e chiusura — accesso self-serve, API key in pochi minuti.