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<double> KellyVector(List<double> dProbs, List<double> dOdds, int lEvents, double dKellyMult, ushort lOddsType)
{
int lParlaySize, lParlayNum, lThisAND, lOutcomes, lBetIdx, lResIdx;
List<double> dKellyOutVector = new List<double>();
lOutcomes = 1 << 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++)
{
if (i > 0)
{
lBetsPerSize[i] = combin(lEvents, i);
lCombins[i] = lCombins[i-1] + lBetsPerSize[i];
}
else
{
lCombins[0] = 0;
lBetsPerSize[0] = 0;
}
lMapV[i] = 1 << (lEvents - i - 1);
if (dOdds[i] < 0)
{
dOdds[i] = g_US2DEC(dOdds[i]);
}
else
{
switch(lOddsType)
{
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;
}
}
dSingKellyV[i] = SBKelly(dProbs[i], dOdds[i], dKellyMult);
}
lMapV[lOutcomes-1] = 0;
lBetsPerSize[lEvents] = 1;
lCombins[lEvents] = lOutcomes-1;
for(int i = 1; i < lOutcomes; i++)
{
lParlaySize = lParlayNum = 0;
for(int j = 0; j < lEvents; j++)
{
lThisAND = i & lMapV[j];
lParlayNum += lThisAND;
lParlaySize += lThisAND > 0 ? 1 : 0;
}
lResIdx = lCombins[lParlaySize-1] + lBetsPerSize[lParlaySize] - 1;
lMapV[lResIdx] = lParlayNum;
lBetsPerSize[lParlaySize]--;
dKellyOutVector.Add(1);
}
for(lResIdx = 0; lResIdx < lOutcomes - 1; lResIdx++)
{
for(int i = 0; i < lEvents; i++)
{
lBetIdx = 1 << (lEvents - i - 1);
long lMapAnd = lMapV[lResIdx] & lBetIdx;
if( lMapAnd > 0)
{
dKellyOutVector[lResIdx] *= dSingKellyV[i];
}
else
{
dKellyOutVector[lResIdx] *= (1 - dSingKellyV[i]);
}
}
}
return dKellyOutVector;
}
private double SBKelly(double dWinProb, double dDecOdds, double dKellyMult)
{
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);
}
private double g_US2DEC(double dUSOdds)
{
if(dUSOdds<0)
return 1 - 100 / dUSOdds;
else if(dUSOdds>0)
return 1 + dUSOdds / 100;
else
return 1;
}
private int combin(int n, int k)
{
if (k > n)
{
return 0;
}
long a, b;
a = 1;
b = 1;
int v = n - k;
for (int i = v + 1; i < n + 1; i++)
{
a *= i;
}
b = factorial(k);
a = a / b;
return (int)a;
}
private long factorial(int n)
{
int i;
long a = 1;
if (n > 1)
{
for (i = 2; i < n + 1; i++)
a *= i;
}
return a;
}