This package contains functions that convert between bookmaker odds and probabilities. The function implied_probabilities() convert bookmaker odds into proper probabilities. The function implied_odds() does the inverse conversion, it turns proper probabilities into bookmaker odds. Several methods are available, with different assumptions regarding the underlying mechanism the bookmakers convert their probabilities into odds. The main focus of this introduction is present how the package works and the methods that convert bookmaker odds into probabilities and. Towards the end is a small demonstration on how to convert probabilities to bookmaker odds.
A naive conversion of bookmaker odds into probabilities has two main problems. The first is that the probabilities are not proper probabilities, since they sum to more than 1. The excess probability is called the bookmakers margin. The second problem is that the probabilities, even if the margin is removed, will be biased in several ways, usually because of what is called the favorite-longshot bias. The methods in this package remove the bookmaker margin and some of them also adjust for favorite-longshot bias.
In version 0.5 a new feature was introduced. It is now possible to convert odds to probabilities with multiple winners, which means that the probabilities should sum to something greater than 1. One example of this is when you have odds for different teams/players to finish top 3 in a league, in which case the probabilities should sum to 3 instead of 1. The details are explained towards the end of this document.
The default method used by the function implied_probabilities() is called the basic method. This is the simplest and most common method for converting bookmaker odds into probabilities, and is obtained by dividing the naive probabilities (the inverted odds) by the sum of the inverted odds. If pi is the true underlying probability for outcome i, and ri is the corresponding inverted odds, then the probabilities are computed as
pi = ri / sum(r)
This method tend to be the least accurate of the methods in this package. I have also seen this normalization method been referred to as the multiplicative method.
The implied_probabilities() function return a list with the proper probabilities (as a matrix) and the bookmaker margins.
In the examples below are three sets of bookmaker odds from three football matches.
library(implied)
# One column for each outcome, one row for each race or match.
<- rbind(c(4.20, 3.70, 1.95),
my_odds c(2.45, 3.70, 2.90),
c(2.05, 3.20, 3.80))
colnames(my_odds) <- c('Home', 'Draw', 'Away')
<- implied_probabilities(my_odds)
res1
$probabilities
res1#> Home Draw Away
#> [1,] 0.2331556 0.2646631 0.5021813
#> [2,] 0.3988848 0.2641264 0.3369888
#> [3,] 0.4586948 0.2938514 0.2474538
$margin
res1#> [1] 0.02118602 0.02326112 0.06346277
This method is from Joseph Buchdahl’s Wisom of the Crowds document, and assumes that the margin applied by the bookmaker for each of the outcome is proprtional to the probabilitiy of the outcome. In other words, the excessive probabilties are unevenly applied in a way that is reflects the favorite-longshot bias.
The probabilities are calculated from the bookmaker odds O using the following formula
pi = (n - M * Oi) / n * Oi
where n is the number of outcomes, and M is the bookmaker margin.
<- implied_probabilities(my_odds, method = 'wpo')
res2
$probabilities
res2#> Home Draw Away
#> [1,] 0.2310332 0.2632083 0.5057585
#> [2,] 0.4004096 0.2625166 0.3370739
#> [3,] 0.4666506 0.2913457 0.2420036
# The margins applied to each outcome.
$specific_margins
res2#> Home Draw Away
#> [1,] 0.03056706 0.02683049 0.01396320
#> [2,] 0.01936444 0.02953607 0.02300299
#> [3,] 0.04533211 0.07260878 0.08741297
The odds ratio method is also from the Wisdom of the Crowds document, but is originally from an article by Keith Cheung. This method models the relationship between the proper probabilities and the improper bookmaker probabilties using the odds ratio (OR) function:
OR = pi (1 - ri) / ri (1 - pi)
This gives the probabilities
pi = ri / OR + ri - (OR * ri)
where the odds ratio OR is selected so that sum(pi) = 1.
<- implied_probabilities(my_odds, method = 'or')
res3
$probabilities
res3#> Home Draw Away
#> [1,] 0.2320045 0.2636413 0.5043542
#> [2,] 0.3996913 0.2633868 0.3369219
#> [3,] 0.4634417 0.2919028 0.2446556
# The odds ratios converting the proper probablities to bookmaker probabilities.
$odds_ratios
res3#> [1] 1.034456 1.035814 1.102631
The power method models the bookmaker probabilities as a power function of the proper probabilities. This method is also described in the Wisdom of the Crowds document, where it is referred to as the logarithmic method.
pi = ri(1/k)
where k is selected so that sum(pi) = 1.
<- implied_probabilities(my_odds, method = 'power')
res4
$probabilities
res4#> Home Draw Away
#> [1,] 0.2311414 0.2630644 0.5057941
#> [2,] 0.4003156 0.2627189 0.3369655
#> [3,] 0.4667137 0.2908986 0.2423877
# The inverse exponents (n) used to convert the proper probablities to bookmaker probabilities.
$exponents
res4#> [1] 0.9797666 0.9788117 0.9419759
The additive method removes the margin from the naive probabilities by subtracting an equal amount of of the margin from each outcome. The formula used is
pi = ri - ((sum(r) - 1) / n)
If there are only two outcomes, the additive method and Shin’s method are equivalent.
<- implied_probabilities(my_odds, method = 'additive')
res5
$probabilities
res5#> Home Draw Away
#> [1,] 0.2310332 0.2632083 0.5057585
#> [2,] 0.4004096 0.2625166 0.3370739
#> [3,] 0.4666506 0.2913457 0.2420036
One problem with the additive method is that it can produce negative probabilities, escpecially for outcomes with low probabilties. This can often be the case when there are many outcomes, for example in racing sports. If this happens, you will be given a warning. Here is an example taken from Clarke et al (2017):
<- t(matrix(1/c(0.870, 0.2, 0.1, 0.05, 0.02, 0.01)))
my_odds2 colnames(my_odds2) <- paste('X', 1:6, sep='')
<- implied_probabilities(my_odds2, method = 'additive')
res6 #> Warning in implied_probabilities(my_odds2, method = "additive"): Probabilities outside the 0-1 range produced at 1 instances.
$probabilities
res6#> X1 X2 X3 X4 X5 X6
#> [1,] 0.8283333 0.1583333 0.05833333 0.008333333 -0.02166667 -0.03166667
The two methods referred to as “balanced book” and Shin’s method are based on the assumption that there is a small proportion of bettors that actually knows the outcome (called inside traders), and the rest of the bettors reflect the otherwise “true” uncertainty about the outcome. The proportion of inside traders is denoted Z.
The two methods differ in what assumptions they make about how the bookmakers react to the pressence of inside traders. Shin’s method is derived from the assumption that the bookmakers tries to maximize their profits when there are inside traders. The balanced books method assumes the bookmakers tries to minimize their losses in the worst case scenario if the least likely outcome were to acctually occur.
We can not know what the insiders know, but both methods gives an estimate of the proportion of insiders.
<- implied_probabilities(my_odds, method = 'shin')
res7
$probabilities
res7#> Home Draw Away
#> [1,] 0.2315811 0.2635808 0.5048382
#> [2,] 0.4000160 0.2629336 0.3370505
#> [3,] 0.4645977 0.2919757 0.2434266
# The estimated proportion of inside traders.
$zvalues
res7#> [1] 0.01054734 0.01157314 0.03187455
# Balanced books
<- implied_probabilities(my_odds, method = 'bb')
res8
$probabilities
res8#> Home Draw Away
#> [1,] 0.2299380 0.2624575 0.5076046
#> [2,] 0.4011989 0.2616832 0.3371179
#> [3,] 0.4710196 0.2899698 0.2390106
# The estimated proportion of inside traders.
$zvalues
res8#> [1] 0.01059301 0.01163056 0.03173139
This method sees the improper bookmaker probabilities as a noisy version of the true underlying probabilities, and uses the Jensen–Shannon (JS) distance as a measure of how noisy the bookmaker probabilities are.
For the sake of finding the denoised probabilities pi, each outcome i is modeled as a binomial variable, with outcomes i and NOT i. These have probabilities pi and 1-pi, with corresponding improper bookmaker probabilities ri and 1-ri. For a given noise-level D, as measued by the symmetric JS distance, the underlying probabilities can be found by solving the JS distance equation for pi:
D = 0.5 * BKL(pi, mi) + 0.5 * BKL(ri, mi)
where mi = (pi + ri) / 2
and
BKL(x, y) = x * log(x/y) + (1-x) * log((1-x)/(1-y))) + y * log(y/x) + (1-y) * log((1-y)/(1-y))
is the “binomial” Kullback–Leibler divergence.
The solution is found numerically by finding the value of of D so that sum(pi) = 1.
The method was developed by Christopher D. Long (twitter: @octonion), and described in a series of Twitter postings.
# Balanced books
<- implied_probabilities(my_odds, method = 'jsd')
res9
$probabilities
res9#> Home Draw Away
#> [1,] 0.2315189 0.2634117 0.5050694
#> [2,] 0.4000505 0.2629589 0.3369906
#> [3,] 0.4650456 0.2915675 0.2433869
# The estimated noise (JS distance)
$distance
res9#> [1] 0.005485371 0.005849245 0.016099204
In the examples above it has been assumed that the probabilities should sum to 1. This is the correct approach when only 1 of the possible outcomes occur, but this is not correct when multiple outcomes occur. One example of this are odds for players/teams to reach the final in a tournament. In this case the probabilities should sum to 2, as two of the outcomes will be considered a win. Another example is placing in the top 5 in a league, in which case the probabilities should sum to 5.
You can change the target_probability to something other than 1, and this works for most methods.
# Example odds.
<- c(1.6, 2.63, 3.3, 3.7, 5.6, 7.1, 12.5, 16.5, 25)
odds_reach_final
<- implied_probabilities(odds_reach_final, method = 'or', target_probability = 2)
res10
$probabilities
res10#> [,1] [,2] [,3] [,4] [,5] [,6] [,7]
#> [1,] 0.6107334 0.3660944 0.2904215 0.258519 0.169879 0.1336902 0.07566384
#> [,8] [,9]
#> [1,] 0.05725567 0.03774298
sum(res10$probabilities)
#> [1] 2
There is also a function that can do the opposite what the implied_probabilities() function does, namely the implied_odds() function. This function converts probabilities to odds, for a given margin, the inverse of the methods as described above. Not all methods have been implemented yet. Take a look at the help file for the function for more details.
In the code example below we use take the results of converting the odds to probabilities using the power method, and convert them back to odds again, with the same margin. We pretty much recover the original odds, except for some small numerical inaccuracy.
<- implied_odds(res4$probabilities[1,],
res_odds1 margin = res4$margin[1],
method = 'power')
$odds
res_odds1#> Home Draw Away
#> [1,] 4.2 3.700001 1.950005
# The exponents.
$exponents
res_odds1#> [1] 0.9797634
# Compare to the exponent from the odds-to-probability conversion.
$exponents[1]
res4#> [1] 0.9797666
The odds.converter package can convert between different odds formats, including to decimal odds, that this package requires.
Here are some relevant references and links:
Joseph Buchdahl - USING THE WISDOM OF THE CROWD TO FIND VALUE IN A FOOTBALL MATCH BETTING MARKET Link
Keith Cheung (2015) Fixed-odds betting and traditional odds Link
Stephen Clarke, Stephanie Kovalchik & Martin Ingram (2017) Adjusting Bookmaker’s Odds to Allow for Overround Link
Hyun Song Shin (1992) Prices of State Contingent Claims with Insider Traders, and the Favourite-Longshot Bias Link
Hyun Song Shin (1993) Measuring the Incidence of Insider Trading in a Market for State-Contingent Claims Link
Bruno Jullien & Bernard Salanié (1994) Measuring the incidence of insider trading: A comment on Shin Link
John Fingleton & Patrick Waldron (1999) Optimal Determination of Bookmakers’ Betting Odds: Theory and Tests.Link