Simultaneous Event Kelly Calculator Beta

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Ganchrow
    SBR Hall of Famer
    • 08-28-05
    • 5011

    #1
    Simultaneous Event Kelly Calculator Beta
    To all those interested, I'm looking for comments on the beta version of my Simultaneous Event Kelly Calculator.

    Unfortunately, no documentation is yet available.

    Go to SBR Betting Tools and click "Kelly Calculator (Simultaneous Events)".
    Last edited by SBR Jonelyn; 04-16-15, 02:18 PM. Reason: link does not work
  • jjgold
    SBR Aristocracy
    • 07-20-05
    • 388179

    #2
    It looks sharp but what the fuk is it? How does it work?

    Thanks Ganch
    Comment
    • Ganchrow
      SBR Hall of Famer
      • 08-28-05
      • 5011

      #3
      Originally posted by jjgold
      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:
      1. # of Simultaneous Events on which you're considering placing bets.
      2. 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.
      3. Consecutive Series: This represents the number of times you anticipate placing bets similar to these consecutively. See example below.
      4. 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.
      5. Calculate Kelly button calculates true Kelly stakes.
      6. 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.
      7. Expected Profit shows expected dollar or percentage profit from making the bet one time.
      8. Expected Growth shows the theoretical expected dollar or percentage bankroll growth from making the bet one time.
      9. 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.
      10. 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.
      Last edited by SBR Jonelyn; 04-16-15, 02:18 PM. Reason: image does not exist
      Comment
      • jokerjoe
        SBR Rookie
        • 05-29-08
        • 10

        #4
        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!
        Comment
        • Ganchrow
          SBR Hall of Famer
          • 08-28-05
          • 5011

          #5
          Originally posted by jokerjoe
          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;
          
          [COLOR="Red"]	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);
          	}[/COLOR]
          	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".

          What part exactly are you stuck on?
          Comment
          • jokerjoe
            SBR Rookie
            • 05-29-08
            • 10

            #6
            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?

            Thanks again.
            Comment
            • Ganchrow
              SBR Hall of Famer
              • 08-28-05
              • 5011

              #7
              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.
              1. Sort all bets by edge, from highest to lowest.
              2. Calculate the fair implied probability for each bet. This is just the reciprocal of the decimal odds.
              3. 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.
              4. 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.
              5. 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).
              6. 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.
              7. 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:
              • actual prob=50%, odds=1.99
              • actual prob=25%, odds=4
              • actual prob=15%, odds=6.5
              • actual prob=10%, odds=10.5


              Sorting by edge yields:
              1. p=10%, odds=10.5, edge=5%, implied prob=9.5238%
              2. p=25%, odds=4, edge=0%, implied prob=25.0000%
              3. p=50%, odds=1.99, edge=-0.5%, implied prob=50.2513%
              4. p=15%, odds=6.5, edge=-2.5%, implied prob=15.3846%


              The running implied probabilities totals are:
              1. 9.5238%
              2. 34.5238%
              3. 84.7751%
              4. 100.1597%


              Because the sum of implied probabilities is 100.1597% > 100%, no true arb exists and we proceed.

              The running actual probabilities totals are:
              1. 10%
              2. 35%
              3. 85%
              4. 100%


              The quotients are then:
              1. 0.994736842
              2. 0.992727273
              3. 0.985225933
              4. 0


              The minimum quotient greater than 0 is 0.985225933.

              Hence the stakes for each bet are:
              1. stake=max(10% - 0.985225933 * 9.5238%,0) ≈ 0.6169%
              2. stake=max(25% - 0.985225933 * 25.000%,0) ≈ 0.3694%
              3. stake=max(50% - 0.985225933 * 50.2513%,0) ≈ 0.4912%
              4. stake=max(15% - 0.985225933 * 15.3846%,0) = 0%


              Consider the following bets on 4 mutually exclusive outcomes:
              • actual prob=50%, odds=2
              • actual prob=25%, odds=4
              • actual prob=15%, odds=6.5
              • actual prob=10%, odds=10.5


              Sorting by edge yields:
              1. p=10%, odds=10.5, edge=5%, implied prob=9.5238%
              2. p=25%, odds=4, edge=0%, implied prob=25.0000%
              3. p=50%, odds=2, edge=0%, implied prob=50.0000%
              4. p=15%, odds=6.5, edge=-2.5%, implied prob=15.3848%


              The running implied probabilities totals are:
              1. 9.5238%
              2. 34.5238%
              3. 84.5238%
              4. 99.9084%


              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.
              1. stake = 10%
              2. stake = 25%
              3. stake = 50%
              4. stake = 15%
              Comment
              • jokerjoe
                SBR Rookie
                • 05-29-08
                • 10

                #8
                Thanks a lot Ganchrow, just sorting out a few issues but looks like it's working!
                Comment
                • handikapa
                  SBR Rookie
                  • 05-30-11
                  • 4

                  #9
                  Hi, Is this example code available? When I click the "Show Code" buttons it does not work.

                  Thanks for your help.
                  Comment
                  • durito
                    SBR Posting Legend
                    • 07-03-06
                    • 13173

                    #10
                    Originally posted by handikapa
                    Hi, Is this example code available? When I click the "Show Code" buttons it does not work.

                    Thanks for your help.
                    If you view the source of this page you can get at it (not formatted properly):

                    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;

                    <font color="Red"> 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 &amp;&amp; dProposedMinResult < dMinResult) **
                    dMinResult = dProposedMinResult ;
                    **
                    **
                    for (var i = 0; i<=lSingles-1; i++) **
                    if (dOverround < 1 &amp;&amp; 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);
                    **</font>
                    g_arrStakes = a_dRealKellyStakes;
                    return {arrNames: a_sParlayNames, arrStakes: a_dRealKellyStakes**;
                    Comment
                    • MonkeyF0cker
                      SBR Posting Legend
                      • 06-12-07
                      • 12144

                      #11
                      The javascript source for the Kelly Calculator is located here:
                      Last edited by SBR Jonelyn; 04-16-15, 02:19 PM. Reason: image does not exist
                      Comment
                      • handikapa
                        SBR Rookie
                        • 05-30-11
                        • 4

                        #12
                        Thanks very much to both of you for the quick reply.
                        Comment
                        • Ganchrow
                          SBR Hall of Famer
                          • 08-28-05
                          • 5011

                          #13
                          Originally posted by handikapa
                          Hi, Is this example code available? When I click the "Show Code" buttons it does not work.

                          Thanks for your help.
                          The calcMutExKelly() function posted by durito is only for mutually exclusive events (i.e., multi-way contests).

                          The calcKelly() function in the .js to which MonkeyF0cker linked handles (sloppily) simultaneous independent events.

                          A much better algorithm (described here) for independent event Kelly staking is implemented in the following C snippet:
                          Code:
                          // Author: ganchrow@heritagesports.com
                          
                          #define ODDS_ARE_DECIMAL 0
                          #define ODDS_ARE_US 1
                          #define ODDS_ARE_MIXED 2
                          
                          double KellyVector(
                          	double *dProbs,		// array of independent event probabilities (input not changed)
                          	double *dOdds,		// array of independent event odds (input not changed)
                          	double *dKellyOutVector,// array of Kelly stakes (output)
                          	long lEvents,		// number of events (input not changed)
                          	double dKellyMult,	// Kelly multiplier > 0 (input not changed)
                          	long lOddsType		/* odds type (input not changed)
                          						0 ==> decimal odds
                          						1 ==> US odds
                          						2 ==> US odds if [hcc]lt[/hcc] 0 or [hcc]ge[/hcc]100
                          				*/
                          )[hcc]#123[/hcc]
                          	long i, j;
                          	long lParlaySize, lParlayNum, lThisAND, lOutcomes, lBetIdx, lResIdx;
                          
                          	lOutcomes = 1[hcc]lt[/hcc][hcc]lt[/hcc]lEvents;
                          
                          	long *lCombins = (long*)malloc( (lEvents+1) * sizeof(long));
                          	long *lBetsPerSize = (long*)malloc( (lEvents+1) * sizeof(long));
                          	long *lMapV = (long*)malloc( lOutcomes * sizeof(long));
                          	double *dSingKellyV = (double*)malloc(lEvents * sizeof(double));
                          
                          	if(lCombins==NULL || lBetsPerSize==NULL || lMapV==NULL || dSingKellyV==NULL)
                          		// memory allocation error
                          		goto END;
                          
                          	
                          	for(i=0; i[hcc]lt[/hcc]lEvents; i++) [hcc]#123[/hcc]
                          		if(i) [hcc]#123[/hcc]
                          			[color=red]lBetsPerSize[i] = (lEvents-i+1)/i * (lBetsPerSize[i-1] || 1);[/color]
                          			lCombins[i] = lCombins[i-1] + lBetsPerSize[i];
                          		[hcc]#125[/hcc] else [hcc]#123[/hcc]
                          			lCombins[0] = lBetsPerSize[0] = 0;
                          		[hcc]#125[/hcc]
                          
                          		lMapV[i] = 1[hcc]lt[/hcc][hcc]lt[/hcc](lEvents - i - 1);
                          
                          		if (dOdds[i] [hcc]lt[/hcc] 0) [hcc]#123[/hcc]
                          			dOdds[i] = g_US2DEC(dOdds[i]);
                          		[hcc]#125[/hcc] else [hcc]#123[/hcc]
                          			switch(lOddsType) [hcc]#123[/hcc]
                          				case ODDS_ARE_DECIMAL :
                          					break;
                          				case ODDS_ARE_US :
                          					dOdds[i] = g_US2DEC(dOdds[i]);
                          					break;
                          				case ODDS_ARE_MIXED :
                          				default :
                          					if(dOdds[i] >= 100)
                          						dOdds[i] = g_US2DEC(dOdds[i]);
                          			[hcc]#125[/hcc]
                          		[hcc]#125[/hcc]
                          		if(dOdds[i] == NULL) goto END;
                                  	dSingKellyV[i] = SBKelly(dProbs[i], dOdds[i], dKellyMult);
                          	[hcc]#125[/hcc]
                          
                          	lMapV[lOutcomes-1] = 0;
                          	lBetsPerSize[lEvents] = 1;
                          	lCombins[lEvents] = lOutcomes-1;
                          	for(i=1; i[hcc]lt[/hcc]lOutcomes; i++) [hcc]#123[/hcc]
                          	        lParlaySize = lParlayNum = 0;
                          		for(j=0; j[hcc]lt[/hcc]lEvents; j++) [hcc]#123[/hcc]
                          			lThisAND = i & lMapV[j];
                          			lParlayNum += lThisAND;
                          			lParlaySize += lThisAND ? 1 : 0;
                          		[hcc]#125[/hcc]
                          
                          		lResIdx = lCombins[lParlaySize-1] + lBetsPerSize[lParlaySize] - 1;
                          		lMapV[lResIdx] = lParlayNum;
                          		lBetsPerSize[lParlaySize]--;
                          		dKellyOutVector[lResIdx] = 1;
                          	[hcc]#125[/hcc]
                          
                          	for(lResIdx=0;lResIdx[hcc]lt[/hcc]lOutcomes-1;lResIdx++) [hcc]#123[/hcc]
                          		for(i=0; i[hcc]lt[/hcc]lEvents; i++) [hcc]#123[/hcc]
                          			lBetIdx = 1[hcc]lt[/hcc][hcc]lt[/hcc](lEvents - i - 1);
                          			if(lMapV[lResIdx] & lBetIdx)
                                          		dKellyOutVector[lResIdx] *= dSingKellyV[i];
                          			else
                                          		dKellyOutVector[lResIdx] *= (1 - dSingKellyV[i]);
                          		[hcc]#125[/hcc]
                          	[hcc]#125[/hcc]
                          
                          END:
                          	// clean up
                          	free(lCombins);
                          	free(lBetsPerSize);
                          	free(lMapV);
                          	free(dSingKellyV);
                          
                          	return dKellyOutVector;
                          [hcc]#125[/hcc]
                          
                          inline double SBKelly(double dWinProb, double dDecOdds, double dKellyMult)[hcc]#123[/hcc]
                          	double dFracOdds, dFairOdds, dOddsRatio;
                          	if(dDecOdds [hcc]lt[/hcc]= 1 || dWinProb > 1 || dWinProb [hcc]lt[/hcc] 0 || dKellyMult [hcc]lt[/hcc]= 0)
                          		return NULL;
                          	else if(dDecOdds * dWinProb [hcc]lt[/hcc]= 1)	// non-positive edge ==> no bet
                          		return 0;
                          
                          	dFracOdds = dDecOdds - 1;
                          	dFairOdds = 1/dWinProb - 1;
                          	dOddsRatio = pow(dFairOdds/dFracOdds, dKellyMult);
                          
                          	return (1 - dOddsRatio) / (1 + dFracOdds * dOddsRatio);
                          [hcc]#125[/hcc]
                          
                          inline double g_US2DEC(double dUSOdds)[hcc]#123[/hcc]
                          	if(dUSOdds[hcc]lt[/hcc]0)
                          		return 1-100/dUSOdds;
                          	else if(dUSOdds>0)
                          		return 1+dUSOdds/100;
                          	else
                          		return 1;
                          [hcc]#125[/hcc]
                          Last edited by Ganchrow; 05-11-12, 07:43 PM. Reason: removed call to missing combinatorial function
                          Comment
                          • MonkeyF0cker
                            SBR Posting Legend
                            • 06-12-07
                            • 12144

                            #14
                            Hey Ganch,

                            You mind if I post a C# port of your function?
                            Comment
                            • Ganchrow
                              SBR Hall of Famer
                              • 08-28-05
                              • 5011

                              #15
                              Originally posted by MonkeyF0cker
                              You mind if I post a C# port of your function?
                              Not in the slightest.
                              Comment
                              • MonkeyF0cker
                                SBR Posting Legend
                                • 06-12-07
                                • 12144

                                #16
                                Cool. Good to see you around, man.

                                Hope all is well.
                                Comment
                                • MonkeyF0cker
                                  SBR Posting Legend
                                  • 06-12-07
                                  • 12144

                                  #17
                                  Here is the code (a C# port of Ganch's function above). Doesn't format very well on here but oh well...

                                  Code:
                                  	public const ushort ODDS_ARE_DECIMAL = 0;
                                          public const ushort ODDS_ARE_US = 1;
                                          public const ushort ODDS_ARE_MIXED = 2;
                                  
                                          private List[hcc]lt[/hcc]double> KellyVector(List[hcc]lt[/hcc]double> dProbs, List[hcc]lt[/hcc]double> dOdds, int lEvents, double dKellyMult, ushort lOddsType)
                                          [hcc]#123[/hcc]
                                  	        int lParlaySize, lParlayNum, lThisAND, lOutcomes, lBetIdx, lResIdx;
                                              List[hcc]lt[/hcc]double> dKellyOutVector = new List[hcc]lt[/hcc]double>();
                                  	        lOutcomes = 1 [hcc]lt[/hcc][hcc]lt[/hcc] lEvents;
                                  
                                  	        int[] lCombins = new int[lEvents + 1];
                                  	        int[] lBetsPerSize = new int[lEvents + 1];
                                  	        int[] lMapV = new int[lOutcomes];
                                  	        double[] dSingKellyV = new double[lEvents];
                                  
                                              for(int i = 0; i < lEvents; i++)
                                              [hcc]#123[/hcc]
                                                  if (i > 0)
                                                  [hcc]#123[/hcc]
                                  		            lBetsPerSize[i] = combin(lEvents, i);
                                  			        lCombins[i] = lCombins[i-1] + lBetsPerSize[i];
                                                  [hcc]#125[/hcc]
                                                  else
                                                  [hcc]#123[/hcc]
                                  			        lCombins[0] = 0;
                                  			        lBetsPerSize[0] = 0;
                                  		        [hcc]#125[/hcc]
                                  		        lMapV[i] = 1 << (lEvents - i - 1);
                                  		        if (dOdds[i] < 0)
                                                  [hcc]#123[/hcc]
                                  			        dOdds[i] = g_US2DEC(dOdds[i]);
                                  		        [hcc]#125[/hcc]
                                                  else
                                                  [hcc]#123[/hcc]
                                  			        switch(lOddsType)
                                                      [hcc]#123[/hcc]
                                  				        case ODDS_ARE_DECIMAL :
                                  					        break;
                                  				        case ODDS_ARE_US :
                                  					        dOdds[i] = g_US2DEC(dOdds[i]);
                                  					        break;
                                  				        default :
                                  					        if(dOdds[i] >= 100)
                                  						        dOdds[i] = g_US2DEC(dOdds[i]);
                                                              break;
                                  			        [hcc]#125[/hcc]
                                  		        [hcc]#125[/hcc]
                                  		        dSingKellyV[i] = SBKelly(dProbs[i], dOdds[i], dKellyMult);
                                  	        [hcc]#125[/hcc]
                                              
                                  
                                  	        lMapV[lOutcomes-1] = 0;
                                  	        lBetsPerSize[lEvents] = 1;
                                  	        lCombins[lEvents] = lOutcomes-1;
                                  	        for(int i = 1; i < lOutcomes; i++)
                                              [hcc]#123[/hcc]
                                  	            lParlaySize = lParlayNum = 0;
                                  		        for(int j = 0; j < lEvents; j++)
                                                  [hcc]#123[/hcc]
                                  			        lThisAND = i & lMapV[j];
                                  			        lParlayNum += lThisAND;
                                  			        lParlaySize += lThisAND > 0 ? 1 : 0;
                                  		        [hcc]#125[/hcc]
                                                  lResIdx = lCombins[lParlaySize-1] + lBetsPerSize[lParlaySize] - 1;
                                  		        lMapV[lResIdx] = lParlayNum;
                                  		        lBetsPerSize[lParlaySize]--;
                                  		        dKellyOutVector.Add(1);
                                  	        [hcc]#125[/hcc]
                                  
                                  	        for(lResIdx = 0; lResIdx < lOutcomes - 1; lResIdx++)
                                              [hcc]#123[/hcc]
                                  		        for(int i = 0; i < lEvents; i++)
                                                  [hcc]#123[/hcc]
                                  			        lBetIdx = 1 << (lEvents - i - 1);
                                                      long lMapAnd = lMapV[lResIdx] & lBetIdx;
                                  			        if( lMapAnd > 0)
                                                      [hcc]#123[/hcc]
                                                          dKellyOutVector[lResIdx] *= dSingKellyV[i];
                                                      [hcc]#125[/hcc]
                                  			        else
                                                      [hcc]#123[/hcc]
                                                          dKellyOutVector[lResIdx] *= (1 - dSingKellyV[i]);
                                                      [hcc]#125[/hcc]
                                  		        [hcc]#125[/hcc]
                                  	        [hcc]#125[/hcc]
                                              return dKellyOutVector;
                                          [hcc]#125[/hcc]
                                  
                                          private double SBKelly(double dWinProb, double dDecOdds, double dKellyMult)
                                          [hcc]#123[/hcc]
                                  	        double dFracOdds, dFairOdds, dOddsRatio;
                                  	        if(dDecOdds <= 1 || dWinProb > 1 || dWinProb < 0 || dKellyMult <= 0)
                                  		        return 0;
                                  	        else if(dDecOdds * dWinProb <= 1)	// non-positive edge ==> no bet
                                  		        return 0;
                                  
                                  	        dFracOdds = dDecOdds - 1;
                                  	        dFairOdds = 1/dWinProb - 1;
                                  	        dOddsRatio = Math.Pow(dFairOdds/dFracOdds, dKellyMult);
                                  
                                  	        return (1 - dOddsRatio) / (1 + dFracOdds * dOddsRatio);
                                          [hcc]#125[/hcc]
                                  
                                          private double g_US2DEC(double dUSOdds)
                                          [hcc]#123[/hcc]
                                  	        if(dUSOdds<0)
                                  		        return 1 - 100 / dUSOdds;
                                  	        else if(dUSOdds>0)
                                  		        return 1 + dUSOdds / 100;
                                  	        else
                                  		        return 1;
                                          [hcc]#125[/hcc]
                                  
                                          private int combin(int n, int k)
                                          [hcc]#123[/hcc]
                                              if (k > n)
                                              [hcc]#123[/hcc]
                                                  return 0;
                                              [hcc]#125[/hcc]
                                              long a, b;
                                              a = 1;
                                              b = 1;
                                              int v = n - k;
                                              for (int i = v + 1; i < n + 1; i++)
                                              [hcc]#123[/hcc]
                                                  a *= i;
                                              [hcc]#125[/hcc]
                                              b = factorial(k);
                                              a = a / b;
                                              return (int)a;
                                          [hcc]#125[/hcc]
                                  
                                          private long factorial(int n)
                                          [hcc]#123[/hcc]
                                              int i;
                                              long a = 1;
                                              if (n > 1)
                                              [hcc]#123[/hcc]
                                                  for (i = 2; i < n + 1; i++)
                                                      a *= i;
                                              [hcc]#125[/hcc]
                                              return a;
                                          [hcc]#125[/hcc]
                                  Last edited by MonkeyF0cker; 05-11-12, 02:19 AM.
                                  Comment
                                  • Ganchrow
                                    SBR Hall of Famer
                                    • 08-28-05
                                    • 5011

                                    #18
                                    Originally posted by MonkeyF0cker
                                    Here is the code (a C# port of Ganch's function above).
                                    Well ported.

                                    Looking over your code I realized my snippet omitted the definition of the combinatorial function (which you helpfully included).

                                    It dawned on me, however, that the function calls are actually unnecessary (and wasteful) as the combinatorial progression can be evaluated recursively by:
                                    combin(n,r) = 1 for r = 0
                                    combin(n,r) = combin(n,r-1) * (n-r+1)/r for r > 0


                                    Modification to C code above shown in red.
                                    Comment
                                    • statnerds
                                      SBR MVP
                                      • 09-23-09
                                      • 4047

                                      #19
                                      Originally posted by Ganchrow
                                      1. Sort all bets by edge, from highest to lowest.

                                      [/Extra]
                                      Great to see you back and am a huge fan of your work. however, you just eliminated 99%+ of the board with that one. additionally, and i fully accept that i am a loser and keep bookies and books in business, but i humble suggest that Kelly is flawed as it is built on the assumption that one can accurately gauge his edge.

                                      keep up the solid work Ganch, asset to the board. I still refer back to your thread defending Parlays, loved it.
                                      Comment
                                      • MonkeyF0cker
                                        SBR Posting Legend
                                        • 06-12-07
                                        • 12144

                                        #20
                                        Originally posted by Ganchrow
                                        Well ported.

                                        Looking over your code I realized my snippet omitted the definition of the combinatorial function (which you helpfully included).

                                        It dawned on me, however, that the function calls are actually unnecessary (and wasteful) as the combinatorial progression can be evaluated recursively by:
                                        combin(n,r) = 1 for r = 0
                                        combin(n,r) = combin(n,r-1) * (n-r+1)/r for r > 0


                                        Modification to C code above shown in red.
                                        Good call. Here's the newly ported C# code...

                                        Code:
                                                public const ushort ODDS_ARE_DECIMAL = 0;
                                                public const ushort ODDS_ARE_US = 1;
                                                public const ushort ODDS_ARE_MIXED = 2;
                                        
                                                private List[hcc]lt[/hcc]double> KellyVector(List[hcc]lt[/hcc]double> dProbs, List[hcc]lt[/hcc]double> dOdds, int lEvents, double dKellyMult, ushort lOddsType)
                                                [hcc]#123[/hcc]
                                        	    int lParlaySize, lParlayNum, lThisAND, lOutcomes, lBetIdx, lResIdx;
                                        	    List[hcc]lt[/hcc]double> dKellyOutVector = new List[hcc]lt[/hcc]double>();
                                        	    lOutcomes = 1 [hcc]lt[/hcc][hcc]lt[/hcc] lEvents;
                                        
                                        	    int[] lCombins = new int[lEvents + 1];
                                        	    int[] lBetsPerSize = new int[lEvents + 1];
                                        	    int[] lMapV = new int[lOutcomes];
                                        	    double[] dSingKellyV = new double[lEvents];
                                        
                                                    for(int i = 0; i [hcc]lt[/hcc] lEvents; i++)
                                                    [hcc]#123[/hcc]
                                                        if (i == 0)
                                                        [hcc]#123[/hcc]
                                        		    lCombins[0] = 0;
                                        		    lBetsPerSize[0] = 0;
                                        		[hcc]#125[/hcc]
                                                        else if (i == 1)
                                                        [hcc]#123[/hcc]
                                                            lBetsPerSize[i] = (lEvents - i + 1) / i;
                                                            lCombins[i] = lCombins[i - 1] + lBetsPerSize[i];
                                                        [hcc]#125[/hcc]
                                                        else
                                                        [hcc]#123[/hcc]
                                                            lBetsPerSize[i] = (lEvents - i + 1) / i * lBetsPerSize[i - 1];
                                                            lCombins[i] = lCombins[i - 1] + lBetsPerSize[i];
                                                        [hcc]#125[/hcc]
                                        		lMapV[i] = 1 [hcc]lt[/hcc][hcc]lt[/hcc] (lEvents - i - 1);
                                        		if (dOdds[i] [hcc]lt[/hcc] 0)
                                                        [hcc]#123[/hcc]
                                        		    dOdds[i] = g_US2DEC(dOdds[i]);
                                        		[hcc]#125[/hcc]
                                                        else
                                                        [hcc]#123[/hcc]
                                        	            switch(lOddsType)
                                                            [hcc]#123[/hcc]
                                        			case ODDS_ARE_DECIMAL :
                                        			    break;
                                        			case ODDS_ARE_US :
                                        			    dOdds[i] = g_US2DEC(dOdds[i]);
                                        			    break;
                                        			default :
                                        			    if(dOdds[i] >= 100)
                                        			       dOdds[i] = g_US2DEC(dOdds[i]);
                                                                    break;
                                        		    [hcc]#125[/hcc]
                                        		[hcc]#125[/hcc]
                                        		dSingKellyV[i] = SBKelly(dProbs[i], dOdds[i], dKellyMult);
                                        	    [hcc]#125[/hcc]
                                                    
                                                    lMapV[lOutcomes-1] = 0;
                                        	    lBetsPerSize[lEvents] = 1;
                                        	    lCombins[lEvents] = lOutcomes-1;
                                        	        
                                                    for(int i = 1; i [hcc]lt[/hcc] lOutcomes; i++)
                                                    [hcc]#123[/hcc]
                                        	        lParlaySize = lParlayNum = 0;
                                        		for(int j = 0; j [hcc]lt[/hcc] lEvents; j++)
                                                        [hcc]#123[/hcc]
                                        		     lThisAND = i & lMapV[j];
                                        		     lParlayNum += lThisAND;
                                        		     lParlaySize += lThisAND > 0 ? 1 : 0;
                                        		[hcc]#125[/hcc]
                                                        lResIdx = lCombins[lParlaySize-1] + lBetsPerSize[lParlaySize] - 1;
                                        		lMapV[lResIdx] = lParlayNum;
                                        		lBetsPerSize[lParlaySize]--;
                                        		dKellyOutVector.Add(1);
                                        	    [hcc]#125[/hcc]
                                                    
                                                    for(lResIdx = 0; lResIdx [hcc]lt[/hcc] lOutcomes - 1; lResIdx++)
                                                    [hcc]#123[/hcc]
                                        		for(int i = 0; i [hcc]lt[/hcc] lEvents; i++)
                                                        [hcc]#123[/hcc]
                                        		    lBetIdx = 1 [hcc]lt[/hcc][hcc]lt[/hcc] (lEvents - i - 1);
                                                            long lMapAnd = lMapV[lResIdx] & lBetIdx;
                                        		    if( lMapAnd > 0)
                                                            [hcc]#123[/hcc]
                                                                dKellyOutVector[lResIdx] *= dSingKellyV[i];
                                                            [hcc]#125[/hcc]
                                        		    else
                                                            [hcc]#123[/hcc]
                                                                dKellyOutVector[lResIdx] *= (1 - dSingKellyV[i]);
                                                            [hcc]#125[/hcc]
                                        		[hcc]#125[/hcc]
                                        	    [hcc]#125[/hcc]
                                                    return dKellyOutVector;
                                                [hcc]#125[/hcc]
                                        
                                                private double SBKelly(double dWinProb, double dDecOdds, double dKellyMult)
                                                [hcc]#123[/hcc]
                                        	        double dFracOdds, dFairOdds, dOddsRatio;
                                        	        if(dDecOdds [hcc]lt[/hcc]= 1 || dWinProb > 1 || dWinProb [hcc]lt[/hcc] 0 || dKellyMult [hcc]lt[/hcc]= 0)
                                        		        return 0;
                                        	        else if(dDecOdds * dWinProb [hcc]lt[/hcc]= 1)	// non-positive edge ==> no bet
                                        		        return 0;
                                        
                                        	        dFracOdds = dDecOdds - 1;
                                        	        dFairOdds = 1/dWinProb - 1;
                                        	        dOddsRatio = Math.Pow(dFairOdds/dFracOdds, dKellyMult);
                                        
                                        	        return (1 - dOddsRatio) / (1 + dFracOdds * dOddsRatio);
                                                [hcc]#125[/hcc]
                                        
                                                private double g_US2DEC(double dUSOdds)
                                                [hcc]#123[/hcc]
                                        	        if(dUSOdds[hcc]lt[/hcc]0)
                                        		        return 1 - 100 / dUSOdds;
                                        	        else if(dUSOdds>0)
                                        		        return 1 + dUSOdds / 100;
                                        	        else
                                        		        return 1;
                                                [hcc]#125[/hcc]
                                        Comment
                                        • handikapa
                                          SBR Rookie
                                          • 05-30-11
                                          • 4

                                          #21
                                          Thanks Ganchrow and MonkeyF0cker for the additional code.

                                          I am trying to add Kelly to a program I am doing for horse racing. Would you have a .net example for mutually exclusing results. I am using VB.net but any .net would be great.

                                          Thanks in advance!
                                          Comment
                                          • Dash2in1
                                            SBR Rookie
                                            • 12-31-11
                                            • 11

                                            #22
                                            c# is part of .net .. also, why wouldn't you do it yourself to any other language? Seems straightforward enough with the code examples above.
                                            Comment
                                            • MonkeyF0cker
                                              SBR Posting Legend
                                              • 06-12-07
                                              • 12144

                                              #23
                                              Here's a C# port of the mutually exclusive Kelly staking function. You should be able to port it over to VB pretty easily. There are a couple of classes at the end - the SortableEdge class just makes it easier to sort the edges and the MutualExKellyStakes class combines the string and double (Bet Number and Stakes) variables so both can be returned by the function.

                                              I removed the 2^n parlay ordering so you don't have to sift through null events.

                                              Code:
                                                      private MutualExKellyStakes calcMutExKelly(List[hcc]lt[/hcc]double> a_dEdge, List[hcc]lt[/hcc]double> a_dOdds, double dKellyMult)
                                                      [hcc]#123[/hcc]
                                                          if (a_dEdge.Count != a_dOdds.Count)
                                                          [hcc]#123[/hcc]
                                                              MessageBox.Show("Edges and Odds mismatch: The arrays must be the same length.");
                                                              return null;
                                                          [hcc]#125[/hcc]
                                                          if (dKellyMult [hcc]lt[/hcc]= 0)
                                                          [hcc]#123[/hcc]
                                                              dKellyMult = 1;
                                                          [hcc]#125[/hcc]
                                                          
                                                          int lSingles = a_dOdds.Count;
                                                          string[] a_sParlayNames = new string[lSingles];
                                              	    double[] a_dRealKellyStakes = new double[lSingles];
                                                          List[hcc]lt[/hcc]SortableEdge> oSortedByEdge = new List[hcc]lt[/hcc]SortableEdge>();
                                                          MutualExKellyStakes mutStakes = new MutualExKellyStakes();
                                              	    double dTotProb = 0;
                                              	        
                                                          for (int i = 0; i [hcc]lt[/hcc] lSingles; i++)
                                                          [hcc]#123[/hcc]
                                              		double mydProb = edge2prob(a_dEdge[i],  a_dOdds[i]);
                                              		dTotProb += mydProb ;
                                                              SortableEdge sEdge = new SortableEdge();
                                                              sEdge.Id = i;
                                                              sEdge.Edge = a_dEdge[i];
                                                              sEdge.Odds = a_dOdds[i];
                                                              sEdge.Probability = mydProb;
                                                              oSortedByEdge.Add(sEdge);
                                              	    [hcc]#125[/hcc]
                                                          if (dTotProb > 1 + 1e-6)
                                                          [hcc]#123[/hcc]
                                                              MessageBox.Show("Sum of probabilities of mutually exclusive outcomes (" + dTotProb + ") may not be > 1");
                                                              return null;
                                                          [hcc]#125[/hcc]
                                                          oSortedByEdge.Sort();
                                              
                                              	    double dMinResult = 1, dOverround = 0, dSumProb = 0;
                                                          for (int i = 0; i [hcc]lt[/hcc] lSingles; i++)
                                                          [hcc]#123[/hcc]
                                              		dSumProb += oSortedByEdge[i].Probability;
                                                              if ( dSumProb > 1 )
                                                              [hcc]#123[/hcc]
                                                                  dSumProb = 1;
                                                              [hcc]#125[/hcc]
                                              		dOverround += 1 / oSortedByEdge[i].Odds;
                                              		var dProposedMinResult = (1-dSumProb) / (1-dOverround );
                                              		if (dProposedMinResult > 0 && dProposedMinResult [hcc]lt[/hcc] dMinResult)
                                                              [hcc]#123[/hcc]
                                              			dMinResult = dProposedMinResult;
                                              		[hcc]#125[/hcc]
                                                          [hcc]#125[/hcc]
                                              	    for (int i = 0; i [hcc]lt[/hcc] lSingles; i++)
                                                          [hcc]#123[/hcc]
                                                              if (dOverround [hcc]lt[/hcc] 1 && dSumProb >= 1 - 1e-7 )
                                                              [hcc]#123[/hcc]
                                                                  a_dRealKellyStakes[i] = oSortedByEdge[i].Probability;
                                              		[hcc]#125[/hcc]
                                                              else
                                                              [hcc]#123[/hcc]
                                                                  a_dRealKellyStakes[i] = Math.Max(0, oSortedByEdge[i].Probability - dMinResult / oSortedByEdge[i].Odds);
                                              		[hcc]#125[/hcc]
                                                              a_sParlayNames[i] = "" + (1 + oSortedByEdge[i].Id);
                                              	    [hcc]#125[/hcc]
                                                          
                                                          mutStakes.Names = a_sParlayNames;
                                                          mutStakes.KellyStakes = a_dRealKellyStakes;
                                                          return mutStakes;
                                                      [hcc]#125[/hcc]
                                              
                                                      private double edge2prob(double edge, double odds)
                                                      [hcc]#123[/hcc]
                                                          return (1 + edge) / odds;
                                                      [hcc]#125[/hcc]
                                              
                                              
                                              
                                              
                                              
                                              
                                              
                                                  public class MutualExKellyStakes
                                                  [hcc]#123[/hcc]
                                                      public string[] Names;
                                                      public double[] KellyStakes;
                                                  [hcc]#125[/hcc]
                                              
                                                  public class SortableEdge : IComparable
                                                  [hcc]#123[/hcc]
                                                      public int Id;
                                                      public double Edge, Odds, Probability;
                                              
                                                      public SortableEdge()
                                                      [hcc]#123[/hcc]
                                              
                                                      [hcc]#125[/hcc]
                                                      
                                                      public int CompareTo(object obj)
                                                      [hcc]#123[/hcc]
                                                          if (obj == null) return 1;
                                                          SortableEdge a = obj as SortableEdge;
                                                          if (a != null) 
                                                              return -(this.Edge.CompareTo(a.Edge));
                                                          else
                                                             throw new ArgumentException("Object is not a SortableEdge class member.");
                                              
                                                      [hcc]#125[/hcc]
                                              
                                                  [hcc]#125[/hcc]
                                              Last edited by MonkeyF0cker; 05-18-12, 01:34 AM.
                                              Comment
                                              • MonkeyF0cker
                                                SBR Posting Legend
                                                • 06-12-07
                                                • 12144

                                                #24
                                                That was written in .NET4. So, if you're porting to an earlier version of .NET, you may have to change the IComparable routine.
                                                Comment
                                                • handikapa
                                                  SBR Rookie
                                                  • 05-30-11
                                                  • 4

                                                  #25
                                                  Thanks very much, you have saved me a lot of work and frustration. I tried to give you some additional points but was not able to (sorry).
                                                  Comment
                                                  • LoneStar
                                                    Restricted User
                                                    • 07-11-09
                                                    • 190

                                                    #26
                                                    Ganchrow I came across your thread and see that your well adverse in excel. Do you happen to have a -1 RL calculator or know where I can find the formula to produce such calculation as such? Greatly appreciated!

                                                    This website is for sale! sportsobjective.com is your first and best source for all of the information you&#8217;re looking for. From general topics to more of what you would expect to find here, sportsobjective.com has it all. We hope you find what you are searching for!
                                                    Comment
                                                    • Ganchrow
                                                      SBR Hall of Famer
                                                      • 08-28-05
                                                      • 5011

                                                      #27
                                                      Originally posted by LoneStar
                                                      Ganchrow I came across your thread and see that your well adverse in excel. Do you happen to have a -1 RL calculator or know where I can find the formula to produce such calculation as such? Greatly appreciated!

                                                      http://sportsobjective.com/wordpress/?page_id=3167
                                                      ....
                                                      Last edited by SBR Jonelyn; 04-16-15, 02:19 PM. Reason: link does not work
                                                      Comment
                                                      • Paddy
                                                        SBR Rookie
                                                        • 05-31-12
                                                        • 3

                                                        #28
                                                        Originally posted by Ganchrow
                                                        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.

                                                        What if Chuck is betting those games at reduced lines and the -107 is only available on single games?

                                                        Any advice on how to calculate how much Chuck should bet if the odds for parlays are actually -112 per game?
                                                        Comment
                                                        • Paddy
                                                          SBR Rookie
                                                          • 05-31-12
                                                          • 3

                                                          #29
                                                          Another way to look at it.....How do I bet the following 3 game correctly using kelly correctly while including parlays.

                                                          Marlins -102 (55%)
                                                          Mets +102 (55%)
                                                          Rangers -114 (60%)

                                                          Knowing that the odds for parlay will be.

                                                          Marlins -106
                                                          Mets -102
                                                          Rangers -117
                                                          Comment
                                                          • Paddy
                                                            SBR Rookie
                                                            • 05-31-12
                                                            • 3

                                                            #30
                                                            ^

                                                            bump
                                                            Comment
                                                            • uva3021
                                                              SBR Wise Guy
                                                              • 03-01-07
                                                              • 537

                                                              #31
                                                              To avoid having to manually go through and make 2^n - 1 possible wagers, I created a little piece of code in Octave that navigates through a grid of parlay combinations and outputs the parlays and corresponding stakes to a text file, which you could then use with a script to wager with. Don't know many books that will take 1023 wagers on 10 simutaneous events, perhaps if you spread the wagers across multiple books such actions won't seem overly conspicuous

                                                              In octave you can use "dec2bin" to output a sequence of numbers to their corresponding binary form, which has the added convenience of also being every possible combination of the indexes for those numbers. After creating a grid from all these combinations, then you can start to loop through and populate an array:

                                                              stakes is a vector of single game stakes calculated basically by product((1-stakesk:n))/(1-stakesk ) * stakesk

                                                              Code:
                                                              A=()
                                                              for i = 2:length(grid)
                                                                  f = find(grid(i,:)==1);
                                                                  g = find(grid(i,:)==0);
                                                                  if length(f') == 1
                                                                      A(i) = ([f, stakes(f)]);
                                                                  else
                                                                      A(i) = ([f, prod(stakes(f))*prod(1-stakes(g))]);
                                                                  end
                                                              end
                                                              
                                                              save parlay_combs A
                                                              The variable 'A' should be encapsulated by braces rather than parenthesis, but the braces automatically got replaced by '**' so I just put parenthesis.

                                                              Now you have a file named 'parlay_combs' that you can call with a betting script
                                                              Last edited by uva3021; 07-03-12, 12:58 PM.
                                                              Comment
                                                              • Arbinator
                                                                SBR Rookie
                                                                • 01-20-11
                                                                • 2

                                                                #32
                                                                Originally posted by MonkeyF0cker
                                                                Good call. Here's the newly ported C# code...
                                                                Sorry for waking up this very old thread, but I want to save future programmers some pain. The second C# port has a bug. The first port works fine

                                                                To reproduce, test four odds with 2.0 and 52%. Expected output is 3.5% for all odds, but 0.14% is returned for the fourth odds.

                                                                (I didn't locate the exact bug, but one reason is that mapV[resIdx] are getting invalid numbers).Anyway, thanks to Ganchrow and MonkeyF0cker. Your code helped me tremendously!
                                                                Comment
                                                                • deeppckts
                                                                  SBR Wise Guy
                                                                  • 12-19-12
                                                                  • 830

                                                                  #33
                                                                  Kelly is extremely overrated.
                                                                  Comment
                                                                  • Skull City
                                                                    SBR Rookie
                                                                    • 08-16-20
                                                                    • 8

                                                                    #34
                                                                    Hello everyone,

                                                                    I remember have reading somewhere that Ganchrow shared an excel format of his simultaneous event Kelly calculator. Do someone still have it or know where it can be found ?

                                                                    Any informations would be appreciated.
                                                                    Comment
                                                                    • EveryMothersSon
                                                                      SBR Rookie
                                                                      • 09-12-15
                                                                      • 44

                                                                      #35
                                                                      Originally posted by Ganchrow
                                                                      To all those interested, I'm looking for comments on the beta version of my Simultaneous Event Kelly Calculator.

                                                                      Unfortunately, no documentation is yet available.

                                                                      Go to SBR Betting Tools and click "Kelly Calculator (Simultaneous Events)".
                                                                      hello, sorry I cannot help you with quesiton, but this piqued my interest, and I am going to look into it. Mason Malmuth had a book many years ago on something similar. I have it, but cannot find it
                                                                      Comment
                                                                      SBR Contests
                                                                      Collapse
                                                                      Top-Rated US Sportsbooks
                                                                      Collapse
                                                                      Working...