Time-Varying Returns





Kerry Back

Retirement planning again

  • Array of returns \((r_1, \ldots, r_T)\), different return each month
  • To avoid zero indexing, put them in a dictionary
import numpy as np

T = 60*12
mn = 0.005
sd = 0.04

r = np.random.normal(loc=mn, scale=sd, size=T)
r = dict(zip(range(1, T+1), r))

Previous example

R = 30*12      # 30 years until retirement
T = 60*12      # 60 total years
B0 = 100000    # initial balance is $100,000
D1 = 1000      # initial savings is $1,000 (per month)
W1 = 10000     # withdraw $10,000 first month in retirement
g = 0.002      # deposit is 0.2% larger each month
h = 0          # withdrawals are constant

D = D1 * (1+g)**np.arange(R)
D = dict(zip(range(1, R+1), D))

W = W1 * (1+h)**np.arange(T-R)
W = dict(zip(range(R, T), W))

Account balance in a loop

Only change is r[t].

B = np.zeros(T+1)
B[0] = B0

for t in range(1, R+1) :               
    B[t] = (1+r[t])*B[t-1] + D[t] 

B[R] -= W[R]

for t in range(R+1, T):
    B[t] = (1+r[t])*B[t-1] - W[t]

B[T] = (1+r[T])*B[T-1]

account balance with Future value factors

  • FV factor for \(B_0\) is \((1+r_1)\cdots (1+r_T)\)
  • FV factor for \(D_1\) is \((1+r_2) \cdots (1+r_T)\)
  • FV factor for any deposit or withdrawal at any date \(t\) is \((1+r_{t+1}) \cdots (1+r_T)\)
  • To compute the array of FV factors for dates 0, 1, …, T-1, use
    np.flip(np.cumprod(np.flip(1+r)))

r = np.random.normal(loc=mn, scale=sd, size=T)
D = D1 * (1+g)**np.arange(R)
W = W1 * (1+h)**np.arange(T-R)

fvFactors = np.flip(np.cumprod(np.flip(1+r)))
fvFactors = np.concatenate((fvFactors, [1]))

B0 = np.concatenate(([B0], np.zeros(T)))
D = np.concatenate(([0], D, np.zeros(T-R)))
W = np.concatenate((np.zeros(R), W, [0]))
CF = B0 + D - W
BT = np.sum(CF*fvFactors)