I am trying to calculate the logarithmic maximum of n
different bets. However, for this example, I have 2 independent simultaneous bets.
To calculate the logarithmic maximum of 2 independent simultaneous bets, I need to work out the probability of all 4 combinations:
Assuming x0
is the amount between 0% and 100% of my portfolio on Bet 1 and x1
is the amount between 0% and 100% of my portfolio on Bet 2, the mathematically optimum stakes on both bets can be solved by maximising the following expression:
0.09log(1 + 11.8x0 + 11.8x1) + 0.21log(1 + 11.8x0 - x1) + 0.21log(1 - x0 + 11.8x1) + 0.49log(1 - x0 - x1)
which equals x0: 0.214648, x1: 0.214648
(The 11.8 is not a typo, it is simply 12.8 - 1, the profit).
I have tried to implement this calculation in python, with little success. Here is my current code that I need assistance with:
from scipy.optimize import minimize
from math import log
from itertools import product
from sympy import symbols
Bets = [[0.3, 12.8], [0.3, 12.8]]
Odds = [([i[0], 1 - i[0]]) for i in Bets]
OddsList = list(product(Odds[0], Odds[1]))
#Output [(0.3, 0.3), (0.3, 0.7), (0.7, 0.3), (0.7, 0.7)]
Probability = []
for i in range(0, len(OddsList)):
Probability.append(OddsList[i][0] * OddsList[i][1])
#Output [0.09, 0.21, 0.21, 0.49]
Win = [([i[1] - 1, - 1]) for i in Bets]
WinList = list(product(Win[0], Win[1]))
#Output [(11.8, 11.8), (11.8, -1), (-1, 11.8), (-1, -1)]
xValues = []
for j in range(0, len(Bets)):
xValues.append(symbols('x' + str(j)))
#Output [x0, x1]
def logarithmic_return(xValues, Probability, WinList):
Sum = 0
for i in range(0, len(Probability)):
Sum += Probability[i] * log (1 + (WinList[i][0] * xValues[0]) + ((WinList[i][1] * xValues[1])))
return Sum
minimize(logarithmic_return(xValues, Probability, WinList))
#Error TypeError: Cannot convert expression to float
# However, when I do this, it works perfectly:
logarithmic_return([0.214648, 0.214648], Probability, WinList)
#Output 0.3911621722324154
Seems like this is your first time mixing numerical Python with symbolic. In short, you cannot use numerical functions (like math.log
or scipy.optimize.minimize
) on symbolic expressions. You need to convert your symbolic expressions to lambda function first.
Let's try to fix it:
from scipy.optimize import minimize
from itertools import product
from sympy import symbols, lambdify, log
import numpy as np
Bets = [[0.3, 12.8], [0.3, 12.8]]
Odds = [([i[0], 1 - i[0]]) for i in Bets]
OddsList = list(product(Odds[0], Odds[1]))
#Output [(0.3, 0.3), (0.3, 0.7), (0.7, 0.3), (0.7, 0.7)]
Probability = []
for i in range(0, len(OddsList)):
Probability.append(OddsList[i][0] * OddsList[i][1])
#Output [0.09, 0.21, 0.21, 0.49]
Win = [([i[1] - 1, - 1]) for i in Bets]
WinList = list(product(Win[0], Win[1]))
#Output [(11.8, 11.8), (11.8, -1), (-1, 11.8), (-1, -1)]
xValues = []
for j in range(0, len(Bets)):
xValues.append(symbols('x' + str(j)))
#Output [x0, x1]
def logarithmic_return(xValues, Probability, WinList):
Sum = 0
for i in range(0, len(Probability)):
Sum += Probability[i] * log (1 + (WinList[i][0] * xValues[0]) + ((WinList[i][1] * xValues[1])))
return Sum
# this is the symbolic expression
expr = logarithmic_return(xValues, Probability, WinList)
# convert the symbolic expression to a lambda function for
# numerical evaluation
f = lambdify(xValues, expr)
# minimize expect a function of the type f(x), not f(x0, x1).
# hence, we create a wrapper function
func_to_minimize = lambda x: f(x[0], x[1])
initial_guess = [0.5, 0.5]
minimize(func_to_minimize, initial_guess)
# fun: -inf
# hess_inv: array([[1, 0],
# [0, 1]])
# jac: array([nan, nan])
# message: 'NaN result encountered.'
# nfev: 3
# nit: 0
# njev: 1
# status: 3
# success: False
# x: array([0.5, 0.5])
As you can see, the minimization works. However it didn't find any solution. This is your problem to fix. Here, I just hint you the shape of the function you are trying to minimize.