Kelly Calculator for Simultaneous Bets

This python script is designed to calculate the optimal bet sizes for multiple simultaneous bets, utilizing the Kelly Criterion as a methodology. By inputting a set of given bets and bet sizes, the script calculates the expected log wealth, and employs Stochastic Gradient Descent to adjust the bet sizes in a way that improves pay off. This process is repeated for a specified number of iterations.

Additionally, the script offers the option to discount the payoff by a “risk-free rate” for scenarios where bets will be resolved at different dates.

To experiment with the script, set the following variables:

import torch
from datetime import datetime

t = torch.tensor

provided_odds = t([0.95,0.2,0.1])
fair_odds_win = t([0.9,0.5,0.9])
number_of_bets = len(fair_odds_win)

payout = 1/provided_odds
risk_free_rate = 0.06
resolve_date = [datetime(2023,1,30),datetime(2024,1,26),datetime(2030,1,26)]
discount_rate = t([(1+risk_free_rate)**((datetime.now()-date).days/365.25) for date in resolve_date])
discount = True

if discount:
    payout = payout*discount_rate

#def exp_wealth(fair_odds_win, payout, bet_size): results = torch.mul(fair_odds_win, torch.mul(payout,bet_size)); return results.sum()

def exp_wealth_log(bet_size):

    win_prob = torch.cartesian_prod(*([t([odd, 1-odd]) for odd in fair_odds_win]))
    win_status = torch.cartesian_prod(*([t([1, 0]) for i in range(0,number_of_bets)]))
    event_prob = torch.prod(win_prob, 1)
    log_payout_matrix = torch.log(torch.sum(win_status*bet_size*payout, 1)+1-torch.sum(bet_size))
    log_wealth = torch.mul(event_prob,log_payout_matrix).sum()
    return log_wealth

bet_size = t([0.0] * number_of_bets, requires_grad = True)
lr = 0.005

def apply_step(bet_size):
    #print(bet_size.data)
    result = exp_wealth_log(bet_size)
    result.backward()
    bet_size.data += lr * bet_size.grad.data
    bet_size.data = torch.clamp(bet_size.data, min=0, max=1)
    if bet_size.data.sum() > 1:
      bet_size.data = bet_size.data/bet_size.data.sum()
    bet_size.grad = None

for i in range(1000): apply_step(bet_size)

print(bet_size.data)

Further Reading: