Computing Kelly Bankrolls

Last changed 1/18/98
Copyright 1997-1998, Jazbo Enterprises

The Kelly method provides, for any gambling bet and a given bankroll, an amount that is optimal in the sense that the expected growth of your bankroll will be higher or lower than optimal if you bet more or less than the Kelly number. The Perl script given below will compute the Kelly number for any bet, assuming you have accurate numbers for the probabilities of each outcome.

Documentation is included in-line in the script, but basically you need to know what the probabilities are for each possible outcome for a gambling event. The assumption is that you are betting one unit. You need the probabilities for losing that unit, for tieing (pushing), winning 1 unit, winning 2 units, etc. A novel feature of the script is that it will also allow you to include any cash back you may be getting on the bet (most useful for video poker).

There is a sample of input and output at the end of the listing. (You can download the text of the script by FTP.)

#!/usr/local/bin/perl -w
# kelly.pl

#  Compute the Kelly bankroll for a given game and cash back

#  Jazbo, Copyright 10/25/97 Jazbo Enterprises, jazbo@jazbo.com
#  Free use of this software is granted with the stipulation
#  that this notice be included in any distribution.

# Usage:  kelly.pl [-ccashback,increment,numberi] [-nnumpl] ruinfile
#  cashback = cashback value in percent (0.5 = 0.5%)
#   increment = amount to add to cash back
#   numberi = number of increments
#  ruinfile: File containing the probability of each outcome from a unit bet.

# ruinfile file format:
# Comment lines beginning with "#" are ignored, but printed in the
#   output (unless they begin with "##")
# Each line contains a pair: payback probability
#   where payback is return for one unit bet and probability is in fractions.
#   If fractions sum to less than 1, remainder is taken as
#   a one unit loss.
# Note: For video poker, pay tables are given in term of units return
#   including the amount bet.  Subtract one from the paytable to get
#   the expected return values required here.  

$cashback = 0;
$increment = 0;
$numberi = 1;

while ($ARGV[0] =~ /^-/o) {
  if ($ARGV[0] =~ /^-c/o) {
    $argstr = substr($ARGV[0],2);
    ($cashback,$increment,$numberi) = split(",", $argstr);
    if (!defined($increment)) {
      $increment = 0;
      $numberi = 1;
    }
    elsif (!defined($numberi) || $numberi<1) {
      $numberi = 1;
    }
    #print "cb $cashback inc $increment numi $numberi\n";
    shift;
  }
}

# oval and prob hold the original values of result (oval) and
# probability of that result occuring (prob) for a unit bet
@oval  =();
@prob = ();
$probtot = 0;

while(<>) {
  if (/^#/ || /^[ \t]*$/) {
    if (! /^##/) { print $_; } 
	next;
  }
  chop;
  ($oval[$#oval+1],$prob[$#prob+1]) = split;
      $probtot += $prob[$#prob];
}

if ($probtot > 1.0 || $probtot <0.0) {
  printf "Probability: $probtot total out of range\n";
  exit 1;
}

# If the probabilities don't total to 1.0, assume the
# loss of one unit is the omitted case
if ($probtot < 1.0) {
  ($oval[$#oval+1],$prob[$#prob+1]) = (-1,1.0 - $probtot);
}


print "Cashback Expectatn Bankroll\n";

for ($c=0; $c<$numberi; $c++) {

  # $cb is the cashback value for this iteration
  # expressed as a fraction rather than a percent.
  $cb = ($cashback + $c*$increment)/100.0;

  # @val is the result for a bet including cash back
  @val = ();
  $exp = 0.0;
  for ($i=0; $i<=$#oval; $i++) {
    $val[$i] = $oval[$i] + $cb;
    $exp += $prob[$i]*$val[$i];
  }

  printf("%6.3f%% %10.6f ",100*$cb,$exp);

  if ($exp<=0.0) {
    print " \n";
    next;
  }

  $limit = 100;  # This is plenty in every case I've examined
  $f = 0;
  for ($i=0; $i<$limit; $i++) {
    $Hp = &Hprime($f);
    if ($Hp == 0) { last; }
    $Hdp = &Hdblprime($f);
    $f -= $Hp/$Hdp;
  }

  printf(" %9.2f\n",1.0/$f);

}

  # @val and @prob are globals used to pass the result/probability
  # pair to the subroutines below.

sub Hprime{
  local($f) = @_;
  local($i);
  local($tot) = 0;
  for ($i=0; $i<=$#val; $i++) {
    $tot += $prob[$i]*$val[$i]/(1 + $f*$val[$i]);
  }
  return $tot;
}

sub Hdblprime {
  local($f) = @_;
  local($i);
  local($tot) = 0;
  for ($i=0; $i<=$#val; $i++) {
    $tot += -$prob[$i]*$val[$i]*$val[$i]/((1 + $f*$val[$i])*(1 + $f*$val[$i]));
  }
  return $tot;
}

# ----- End of Perl Script ------

Sample command line:

kelly.pl -c.4,.2,7 JB96

Where the file JB96 is:

# Kelly data for 9/6 Jacks
0 0.214447552
1 0.129375019
2 0.074442481
3 0.011235259
5 0.010975201
8 0.011511187
24 0.002362495
49 0.000109511
799 0.000025168

Then the output is:

# Kelly data for 9/6 Jacks
Cashback Expectatn Bankroll
 0.400%  -0.000410   (Don't play)
 0.600%   0.001590   11791.41
 0.800%   0.003590    4874.92
 1.000%   0.005590    2916.15
 1.200%   0.007590    1997.01
 1.400%   0.009590    1467.79
 1.600%   0.011590    1127.20