It often helps to illustrate a (theoretical) result with a numerical or a graphical example. Here, we consider Rabin's (2000) famous calibration theorem.
Rabin and Thaler (2001) also use an example. On page 220, they write: "Suppose we know that Johnny is a risk-averse expected utility maximizer, and that he will always turn down the 50-50 gamble of losing $\$$10 or gaining $\$$11. What else can we say about Johnny? Specifically, can we say anything about bets Johnny will be willing to accept in which there is a 50 percent chance of losing $\$$100 and a 50 percent chance of winning some amount $\$$Y?"
The surprising answer: "Johnny will reject the bet no matter what y is."
In our example, we consider exponential utility $u(x)=1-e^{-cx}$, where $c$ is the risk aversion coefficient. If Johnny turns down a 50-50 gamble of losing $\$$10 or gaining $\$$11 at wealth level $W$, then $u(W)>0.5\cdot u(W+11) + 0.5 \cdot u(W-10)$; with exponential utility, we have $1-e^{-cW} > 0.5\cdot \left( 1-e^{-c(W+11)} \right) + 0.5 \cdot \left( 1-e^{-c(W-10)} \right)$.
scipy's fsolve can be used to solve $1-e^{-cW} > 0.5\cdot \left( 1-e^{-c(W+11)} \right) + 0.5 \cdot \left( 1-e^{-c(W-10)} \right)$ for $c$ numerically. (Your starting value should be smart.)
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import scipy
from scipy.optimize import fsolve
print(np.__version__)
print(scipy.__version__)
print(matplotlib.__version__)
1.19.2 1.6.2 3.5.0
def utility_diff(c, W):
return (1 - np.exp(-c*W) - 0.5 * ( 1 - np.exp(-c*(W+11)) + 1 - np.exp(-c*(W-10)) ) )
root = fsolve(lambda x: utility_diff(c=x, W=150), 0.01)
root
array([0.00908404])
We end up with consistent values for the expected utilities.
W = 150
print( 1 - np.exp(-root*W) )
print( 0.5 * ( 1 - np.exp(-root*(W+11)) + 1 - np.exp(-root*(W-10)) ) )
[0.74400704] [0.74400704]
Following many textbooks, we illustrate the initial choice with a risk aversion coefficient larger than
root[0]
0.009084035578388291
Such a decision maker will turn down the 50:50-bet at any wealth level (CARA!). We choose $c=0.04$.
c = 0.04
W = 150
x = np.linspace(start=W-20, stop=W+20)
y = 1 - np.exp(-c*x)
# function
plt.plot(x, y)
# lines connecting (W-10, u(W-10))
plt.plot([W-10, W+11], [1 - np.exp(-c*(W-10)), 1 - np.exp(-c*(W+11))], linestyle = 'dotted', marker='o', color='g')
plt.plot([W-10, W-10], [1 - np.exp(-c*(W-10)), 1 - np.exp(-c*(W-20))], linestyle = 'dotted', color='g')
plt.plot([W-10, W-20], [1 - np.exp(-c*(W-10)), 1 - np.exp(-c*(W-10))], linestyle = 'dotted', color='g')
# lines connecting (W+11, u(W+11))
plt.plot([W+11, W+11], [1 - np.exp(-c*(W+11)), 1 - np.exp(-c*(W-20))], linestyle = 'dotted', color='g')
plt.plot([W+11, W-20], [1 - np.exp(-c*(W+11)), 1 - np.exp(-c*(W+11))], linestyle = 'dotted', color='g')
plt.plot([W+11, W-20], [1 - np.exp(-c*(W+11)), 1 - np.exp(-c*(W+11))], linestyle = 'dotted', color='g')
# lines showing the expected utility and the certainty equivalent of the lottery
eu = 0.5 * ( 1 - np.exp(-c*(W+11)) + 1 - np.exp(-c*(W-10)) )
ce = fsolve(lambda x: eu - (1 - np.exp(-c*x)), W)[0]
plt.scatter(ce, eu)
plt.plot([W-20, ce], [eu, eu], linestyle = 'dotted', color='g')
plt.plot([ce, ce], [eu, 1 - np.exp(-c*(W-20))], linestyle = 'dotted', color='g')
# lines showing the expected value of the lottery
ev = 0.5 * (W - 10) + 0.5 * (W + 11)
plt.scatter(ev, eu)
plt.plot([ev, ev], [eu, 1 - np.exp(-c*(W-20))], linestyle = 'dotted', color='g')
plt.plot([ev, ce], [eu, eu], linestyle = 'dotted', color='g')
# custom labels
plt.yticks([1 - np.exp(-c*(W-10)), eu, 1 - np.exp(-c*(W+11))],
labels=['u(W-10)=' + str(round(1 - np.exp(-c*(W-10)),4)),
'u(CE)=' + str(round(eu,4)),
'u(W+11)=' + str(round(1 - np.exp(-c*(W+11)),4))])
plt.xticks([W-10, ce, ev, W+11], [str(round(W-10,2)), "CE", "EV", str(round(W+11,2))])
plt.show()
CE stands for certainty equivalent and EV for expected value. The risk premium is positive.
Let's talk about bigger risks. The next graph plots the same function, but for wealth levels going from $W-110$ to $W+110$.
c = 0.04
W = 150
x = np.linspace(start=W-110, stop=W+110)
y = 1 - np.exp(-c*x)
# function
plt.plot(x, y)
# custom labels
plt.yticks([1 - np.exp(-c*(W-10)), 1 - np.exp(-c*(W-100))],
labels=['u(W)=' + str(round(1 - np.exp(-c*(W)),4)),
'u(W-100)=' + str(round(1 - np.exp(-c*(W-100)),4))])
plt.xticks([W-100, W], [str(round(W-100,2)), str(round(W,2))])
# lines connecting (W, u(W))
plt.plot([W-110, W], [1 - np.exp(-c*(W)), 1 - np.exp(-c*(W))], linestyle = 'dotted', color='g')
plt.plot([W, W], [1 - np.exp(-c*(W)), 1 - np.exp(-c*(W-110))], linestyle = 'dotted', color='g')
plt.scatter(W, 1 - np.exp(-c*(W)))
# lines connecting (W-100, u(W-100))
plt.plot([W-110, W-100], [1 - np.exp(-c*(W-100)), 1 - np.exp(-c*(W-100))], linestyle = 'dotted', color='g')
plt.plot([W-100, W-100], [1 - np.exp(-c*(W-100)), 1 - np.exp(-c*(W-110))], linestyle = 'dotted', color='g')
plt.scatter(W-100, 1 - np.exp(-c*(W-100)))
plt.show()
The utility function $u(x)=1-e^{-cx}$ is bounded from above and will never reach $1$. Looking at both plots, it is immediately clear that no increase in wealth can ever compensate the decision maker for the threat of falling in wealth from $W$ to $W-100$.
The intuition does not depend on small wealth levels, where $u(W)$ is sufficiently far away from $1$. In the following, we use the code from above, increase the initial wealth from 150 to 500, and round utilities to ten decimal points. (Optional exercise: Define a function that we can call repeatedly.)
c = 0.04
W = 500
x = np.linspace(start=W-110, stop=W+110)
y = 1 - np.exp(-c*x)
# function
plt.plot(x, y)
# custom labels
plt.yticks([1 - np.exp(-c*(W-10)), 1 - np.exp(-c*(W-100))],
labels=['u(W)=' + str(round(1 - np.exp(-c*(W)),10)),
'u(W-100)=' + str(round(1 - np.exp(-c*(W-100)),10))])
plt.xticks([W-100, W], [str(round(W-100,2)), str(round(W,2))])
# lines connecting (W, u(W))
plt.plot([W-110, W], [1 - np.exp(-c*(W)), 1 - np.exp(-c*(W))], linestyle = 'dotted', color='g')
plt.plot([W, W], [1 - np.exp(-c*(W)), 1 - np.exp(-c*(W-110))], linestyle = 'dotted', color='g')
plt.scatter(W, 1 - np.exp(-c*(W)))
# lines connecting (W-100, u(W-100))
plt.plot([W-110, W-100], [1 - np.exp(-c*(W-100)), 1 - np.exp(-c*(W-100))], linestyle = 'dotted', color='g')
plt.plot([W-100, W-100], [1 - np.exp(-c*(W-100)), 1 - np.exp(-c*(W-110))], linestyle = 'dotted', color='g')
plt.scatter(W-100, 1 - np.exp(-c*(W-100)))
plt.show()
Main takeaway: Modest risk aversion for small risks implies absurdly high risk aversion for larger risks!
If you write a thesis, it helps to develop intuitions with numerical or with graphical examples. Some students fear that simple examples are not "hard science" and avoid them. I recommend the opposite; even if your examples do not end up in the final version of your thesis, they help you develop better intuitions (which, in turn, allows you to write a better thesis).
More details, clarifications, and explanations on Rabin's theorem can be found in Balter, Chau, and Schweizer (2022). The supplementary material of Balter, Chau, and Schweizer (2022) includes Python code.
Finally, if we plot the utility function we used in the examples over a broader range of wealth levels, it looks like this:
x = np.linspace(start=10, stop=1000)
y = 1 - np.exp(-c*x)
# function
plt.plot(x, y)
plt.show()
Literature: