Spending uses financial resources to purchase benefits and becomes an automatable decision when wealth, time, and investment returns are uncertain. A goals-based agent can choose both its stock allocation and spending each period to maximize expected discounted utility. section 6.3.2
The model treats spending and consumption as equivalent. With wealth W_t, consumption c_t, stock allocation a_t, random stock return r̃_t, and risk-free return r_f, wealth evolves as W_{t+1} = (W_t − c_t)(a_t r̃_t + (1 − a_t)r_f). The objective maximizes E[Σ γ^t U(c_t)], where γ discounts future utility. section 6.3.2
A practical spending optimizer typically proceeds as follows:
- Discretize wealth and time into a state-space grid. section 6.3.2
- Represent stock allocation and spending choices as discrete actions. section 6.3.2
- Specify utility, such as logarithmic or CRRA utility, and discount future rewards. section 6.3.2
- Estimate transition probabilities for next-period wealth and solve by dynamic programming or Q-learning. section 6.3.2
Dynamic programming example
A ten-year grid begins with W0 = 1,000,000, models stock returns with an 8% mean and 20% volatility, and uses 11 allocation choices and 40 spending choices. Backward induction evaluates each action’s expected utility plus discounted continuation value, then records the best allocation and spending choice for every wealth–time state. section 6.3.2
Listing 6.7 Creating a state space grid for the spending example
W0 = 1000000
T = 10
nW = 101
mu_stock = 0.08
mu_bond = 0.045
sig_stock = 0.20
sig_bond = 0.0
Cbar = np.zeros(T+1)
Cbar[0] = 0
for t in range(1, T+1):
Cbar[t] = Cbar[t-1] + 1/(T-t+1)
lnW = np.zeros((nW,T+1))
W = np.zeros((nW, T+1))
for t in range(T+1):
lnW_min = log(W0) - t*log(3) #1
lnW_max = log(W0) - Cbar[t] + (mu_stock-0.5*sig_stock**2)*t
+ 2.5*sig_stock*sqrt(t)
lnW[:,t] = np.linspace(lnW_min, lnW_max, nW)
W = np.exp(lnW)
Use the state-space listing to inspect how wealth bounds and a time-indexed grid support numerical spending decisions. section 6.3.2
Listing 6.8 DP solution for the spending example
nA = 11
nC = 40
V = np.zeros((nW, T+1))
A = np.zeros((nW, T))
C = np.zeros((nW, T)) #1
EV = np.zeros((nA, nC))
W_midpts = compute_midpoints(W)
gamma = 0.95 #2
CRRA = 3 #3
def utility(c): #4
if (CRRA == 1):
util = log(c)
else:
util = (c**(1-CRRA))/(1-CRRA)
return util
for j in range(nW):
V[j, T] = utility(W[j,T]) #5
for t in range(T-1, -1, -1):
for j in range(nW):
for a in range(nA):
for c in range(nC):
cons = (c+1)/(1.5*nC)*W[j,t] #6
W_tplus1_dist = compute_transition_probs(W[j,t]-cons, t, #7
a W_midpts)
EV[a,c] = np.dot(W_tplus1_dist, utility(cons)+gamma*V[:,t+1]) #8
V[j,t] = EV.max()
A[j,t], C[j,t] = np.unravel_index(EV.argmax(), EV.shape) #9
Use the dynamic-programming listing to trace utility evaluation, wealth transitions, action comparison, and policy extraction. section 6.3.2
The optimization is deliberately incomplete: it omits labor income, medical expenses, taxes, withdrawal sequencing, bequests, and distinctions between durable and nondurable goods. These omissions can materially change spending behavior and model realism. section 6.5
