It looks sharp but what the fuk is it? How does it work?
Thanks Ganch
The Kelly formula as traditionally stated (K = [% Edge]/[Decimal Odds-1]) is only correct in the case of single, non-simultaneous bets. This Simultaneous Event Kelly Calculator, as the name implies, calculates exact Kelly-style stakes for up to 15 simultaneous events (bets). It does so by implementing the recursive methodology I outlined in this post.
Inputs:
# of Simultaneous Events on which you're considering placing bets.
Kelly Multiplier: A Kelly multiplier of ½ would imply half-Kelly, of 1 would imply full Kelly, and 2 would imply double Kelly. Note that results will true Kelly fractions, a concept I explain to discuss in Part II of my Kelly article series, and as half-Kelly won't always be exactly one-half of full Kelly.
Consecutive Series: This represents the number of times you anticipate placing bets similar to these consecutively. See example below.
Bankroll: The size of your betting bankroll. Setting to 1 or 100% will give reasults as percentage of bankroll. Setting to a dollar value with no decimal point will give integer results. With 2 decimal points, results would be given to the nearest penny.
Calculate Kelly button calculates true Kelly stakes.
The textarea shows the Kelly weights as a set of multiple parlays. The given weights may be edited compare the Kelly expectations with those of another staking plan.
Expected Profit shows expected dollar or percentage profit from making the bet one time.
Expected Growth shows the theoretical expected dollar or percentage bankroll growth from making the bet one time.
Expected Bankroll shows the expected bankroll value after placing the bets the number of times show in the "Consecutive Series" box above. Most of time you'll do worse than this, but a small percentage of the time you'll do much better.
Median Bankroll shows the bankroll you'd be most likely to see after placing the bets the number of times show in the "Consecutive Series" box above (assuming it's sufficiently large). It also represents the outcome such that you're just as likely to underperfom as you'd be to outperform.
<hr> Example:
Playing full Kelly, Chuck has a bankroll of $10,000.00. During NFL season, he typically makes 5 bets each of the 17 regular season NFL weeks at -107, on which you identify an edge of 5% on each, you'd set Simult. Events to 5, Consecutive Series to 17, enter -107 in the five US text boxes, and 5% in the five Edge/Probability text boxes.
Click the "Calculate Kelly" button.
Optimal Kelly bets are $432.47 on each of the 5 singles, $24.69 on each of the 10 2-team parlays that can be made on from the 5 singles, $1.41 on each of the 10 3-team parlays, $0.08 on the 5 4-team parlays, and nothing on the one 5-team parlay.
Chuck's expected profit the first week is $135.73 and his expected bankroll growth is $67.85.
After 17 weeks, Chuck's expectation bankroll is $12,575.82. His most likely bankroll is $11,218.23.
However, because Chuck only has limited time, he's not going to bother with the 16 larger parlays (3-teams or more), but is worried how much it's going to hurt him. So clicking in each of 3-team, 4-team and 5-team parlays he changes the weights to $0 for each one. He click "Calculate Expectations" and sees by limiting himself only to single bets and 2-team parlays, he reduces his expected end-of-season bankroll by $34.58 to $12,541.24, and his most-likely end-of-season bankroll by $0.25 to $11,217.98.
Chuck decides he can live with it and sticks with the singles and 2-team parlays only.
Hi, I'm trying to understand how the calculator works for mutually exclusive events but can't work it out from the post linked (nor from the java, don't really know it unfortunately...).
Hi, I'm trying to understand how the calculator works for mutually exclusive events but can't work it out from the post linked (nor from the java, don't really know it unfortunately...).
Would be really grateful of an explanation!
This is the relevant function in the JavaScript:
Code:
function calcMutExKelly(a_dEdge, a_dOdds, dKellyMult) {
var lSingles;
var a_sParlayNames;
var a_dRealKellyStakes;
if (dKellyMult == undefined || dKellyMult <= 0 || isNaN(dKellyMult)) dKellyMult = 1;
dKellyMult = parseFloat(dKellyMult);
if (!isArray(a_dEdge) || !isArray(a_dOdds) ) {
var err = "calcMutExKelly: Odds and Edge arguments must both be arrays";
alert(err);
return err;
}
lSingles = a_dOdds.length;
if(lSingles != a_dEdge.length) {
var err = "calcMutExKelly: Edge (size=" + a_dEdge.length + ") and odds (size=" + lSingles + ") arrays are different sizes";
alert(err);
return err;
}
a_dRealKellyStakes = new Array(Math.pow(2,lSingles)-1);
a_sParlayNames = new Array(Math.pow(2,lSingles)-1);
var oSortedByEdge = new Array(lSingles-1);
var dTotProb = 0;
for (var i=0; i<=lSingles-1;i++) {
var mydProb = edge2prob(a_dEdge[i], a_dOdds[i]);
dTotProb += mydProb ;
oSortedByEdge[i] = { n: i, dEdge: a_dEdge[i], dOdds: a_dOdds[i], dProb: mydProb};
}
if(dTotProb > 1 + 1e-6) {
var err = "calcMutExKelly: Sum of probabilities of mutually exclusive outcomes (" + dTotProb + ") may not be > 1";
alert(err);
return err;
}
var fnSortByEdge = function(a,b) { return(b.dEdge - a.dEdge); } ;
oSortedByEdge.sort(fnSortByEdge);
var dMinResult = 1, dOverround = 0, dSumProb = 0, dSumOddsRecip = 0;
for (var i = 0; i<=lSingles-1; i++) {
dSumProb += oSortedByEdge[i].dProb;
if ( dSumProb > 1 ) dSumProb = 1; // due to rounding error probability may erroneously be slightly > 1
dOverround += 1 / oSortedByEdge[i].dOdds;
var dProposedMinResult = (1-dSumProb) / (1-dOverround );
if (dProposedMinResult > 0 && dProposedMinResult < dMinResult) {
dMinResult = dProposedMinResult ;
}
}
for (var i = 0; i<=lSingles-1; i++) {
if (dOverround < 1 && dSumProb >= 1 - 1e-7 ) {
a_dRealKellyStakes[Math.pow(2,oSortedByEdge[i].n)] = oSortedByEdge[i].dProb;
} else {
a_dRealKellyStakes[Math.pow(2,oSortedByEdge[i].n)] = Math.max(0, oSortedByEdge[i].dProb - dMinResult / oSortedByEdge[i].dOdds);
}
a_sParlayNames[Math.pow(2,oSortedByEdge[i].n)] = ''+(1+oSortedByEdge[i].n);
}
g_arrStakes = a_dRealKellyStakes;
return {arrNames: a_sParlayNames, arrStakes: a_dRealKellyStakes};
}
With the long variable names it's pretty straightforward to the point of almost being pseudo code.
I highlighted in red the two loops that do the real "work".
Thanks, was just looking at the html but still can't work out how to get kelly.js, just comes up as gibberish. I must be missing a trick somewhere...
Trying to convert the code into VBA, couple of things I don't get, perhaps I need to see the rest. What's the purpose of fnSortByEdge and how is it sorted? And why are dRealKellyStakes and sParlayNames dimensioned 2^n when it the loops only run to n?
They're dimensioned by 2n because the same structure used for mutually exclusive outcome bets is also used for independent outcome bets. For the latter, there are 2n - 1 possible bets when we include parlays. This is obviously irrelevant for mutually exclusive outcome bets, but it still needs to fit in to the existing programmatic structure.
In other words, it's a pure programming issued that can be completely ignored when considering the problem algorithmically.
Anyway, here's a plain-English description of the algorithm to calculate Kelly stakes on mutually exclusive events.
Sort all bets by edge, from highest to lowest.
Calculate the fair implied probability for each bet. This is just the reciprocal of the decimal odds.
Starting with the highest edge bet, calculate a running total of the the implied probability and the actual probability. The running total for each bet includes the sum of the implied and actual probabilities for that bet and every bet with a higher edge.
If the sum of all the implied probabilities is less than 1 (i.e., a true arb exists), then for each bet the stake will be the actual probability. If this is the case, we can stop here.
If the sum of all the implied probabilities is greater than 1, then for each bet calculate the quotient (1 – the sum of actual probabilities) / (1- sum of implied probabilities).
Find the smallest value of this quotient that’s greater than zero. If no quotient is greater than zero then no bets will be made.
Then for each bet the stake will be the actual probability minus the minimum quotient from 6) above multiplied by the fair implied probability.
Consider the following bets on 4 mutually exclusive outcomes:
Because the sum of implied probabilities is 99.908% < 100% a true arb exists and the optimal stakes are just equal to the actual outcome probabilities.