Coverage for HARK / Calibration / Income / IncomeTools.py: 93%

111 statements  

« prev     ^ index     » next       coverage.py v7.12.0, created at 2025-12-07 05:16 +0000

1""" 

2Created on Sat Dec 19 15:08:54 2020 

3 

4@author: Mateo 

5""" 

6 

7# %% Preamble 

8 

9import numpy as np 

10 

11from HARK import _log 

12from HARK.Calibration.cpi.us.CPITools import cpi_deflator 

13from HARK.interpolation import LinearInterp 

14 

15__all__ = [ 

16 "parse_time_params", 

17 "Sabelhaus_Song_cohort_trend", 

18 "Sabelhaus_Song_all_years", 

19 "sabelhaus_song_var_profile", 

20 "Cagetti_income", 

21 "CGM_income", 

22 "parse_income_spec", 

23 "find_profile", 

24] 

25 

26 

27# %% Tools for setting time-related parameters 

28 

29 

30def parse_time_params(age_birth, age_death): 

31 """ 

32 Converts simple statements of the age at which an agent is born and the 

33 age at which he dies with certainty into the parameters that HARK needs 

34 for figuring out the timing of the model. 

35 

36 Parameters 

37 ---------- 

38 age_birth : int 

39 Age at which the agent enters the model, e.g., 21. 

40 age_death : int 

41 Age at which the agent dies with certainty, e.g., 100. 

42 

43 Returns 

44 ------- 

45 dict 

46 Dictionary with parameters "T_cycle" and "T_age" which HARK expects 

47 and which map to the birth and death ages specified by the user. 

48 

49 """ 

50 # T_cycle is the number of non-terminal periods in the agent's problem 

51 T_cycle = age_death - age_birth 

52 # T_age is the age at which the agents are killed with certainty in 

53 # simulations (at the end of the T_age-th period) 

54 T_age = age_death - age_birth 

55 

56 return {"T_cycle": T_cycle, "T_age": T_age} 

57 

58 

59# %% Tools for finding the mean profiles of permanent income. 

60 

61 

62def age_log_poly_to_growth_rates(coefs, age_min, age_max): 

63 """ 

64 The deterministic component of permanent income is often expressed as a 

65 log-polynomial of age. In multiple HARK models, this part of the income 

66 process is expressed in a sequence of growth factors 'PermGroFac'. 

67 

68 This function computes growth factors from the coefficients of a 

69 log-polynomial specification 

70 

71 The form of the polynomial is assumed to be 

72 alpha_0 + age/10 * alpha_1 + age^2/100 * alpha_2 + ... + (age/10)^n * alpha_n 

73 Be sure to adjust the coefficients accordingly. 

74 

75 Parameters 

76 ---------- 

77 coefs : numpy array or list of floats 

78 Coefficients of the income log-polynomial, in ascending degree order 

79 (starting with the constant). 

80 age_min : int 

81 Starting age at which the polynomial applies. 

82 age_max : int 

83 Final age at which the polynomial applies. 

84 

85 Returns 

86 ------- 

87 GrowthFac : [float] of length age_max - age_min + 1 

88 List of growth factors that replicate the polynomial. 

89 

90 P0 : float 

91 Initial level of income implied my the polynomial 

92 """ 

93 # Figure out the degree of the polynomial 

94 deg = len(coefs) - 1 

95 

96 # Create age matrices 

97 age_10 = np.arange(age_min, age_max + 1).reshape(age_max - age_min + 1, 1) / 10 

98 age_mat = np.hstack(list(map(lambda n: age_10**n, range(deg + 1)))) 

99 

100 # Fing the value of the polynomial 

101 lnYDet = np.dot(age_mat, np.array(coefs)) 

102 

103 # Find the starting level 

104 P0 = np.exp(lnYDet[0]) 

105 

106 # Compute growth factors 

107 GrowthFac = np.exp(np.diff(lnYDet)) 

108 # The last growth factor is nan: we do not know lnYDet(age_max+1) 

109 GrowthFac = np.append(GrowthFac, np.nan) 

110 

111 return GrowthFac.tolist(), P0 

112 

113 

114def find_PermGroFacs(age_min, age_max, age_ret, AgePolyCoefs, ReplRate): 

115 r""" 

116 Finds initial income and sequence of growth factors from a polynomial 

117 specification of log-income, an optional retirement age and a replacement 

118 rate. 

119 

120 Retirement income will be Income_{age_ret} * ReplRate. 

121 

122 Parameters 

123 ---------- 

124 age_min : int 

125 Initial age at which to compute the income specification. 

126 age_max : int 

127 Maximum age up to which the income process must be specified. 

128 age_ret : int 

129 Age of retirement. Note that retirement happens after labor income is 

130 received. For example, age_ret = 65 then the agent will receive labor 

131 income up to age 65 and retirement benefits starting at age 66. 

132 If age_ret is None, there will be no retirement. 

133 AgePolyCoefs : numpy array or list of floats 

134 Coefficients of the income log-polynomial, in ascending degree order 

135 (starting with the constant). Income follows the specification: 

136 ln(P)_age = \sum_{i=1}^{len(AgePolyCoefs)} (age/10)^i * AgePolyCoefs[i] 

137 ReplRate : float 

138 Replacement rate for retirement income. 

139 

140 Returns 

141 ------- 

142 GroFacs : list 

143 List of income growth factors. 

144 Y0 : float 

145 Level of income at age_min 

146 """ 

147 

148 if age_ret is None: 

149 # If there is no retirement, the age polynomial applies for the whole 

150 # lifetime 

151 GroFacs, Y0 = age_log_poly_to_growth_rates(AgePolyCoefs, age_min, age_max) 

152 

153 else: 

154 # First find working age growth rates and starting income 

155 WrkGroFacs, Y0 = age_log_poly_to_growth_rates(AgePolyCoefs, age_min, age_ret) 

156 

157 # Replace the last item, which must be NaN, with the replacement rate 

158 WrkGroFacs[-1] = ReplRate 

159 

160 # Now create the retirement phase 

161 n_ret_years = age_max - age_ret 

162 RetGroFacs = [1.0] * (n_ret_years - 1) + [np.nan] 

163 

164 # Concatenate 

165 GroFacs = WrkGroFacs + RetGroFacs 

166 

167 return GroFacs, Y0 

168 

169 

170def find_profile(GroFacs, Y0): 

171 """ 

172 Generates a sequence {Y_{t}}_{t=0}^N from an initial Y_0 and a sequence 

173 of growth factors GroFac[n] = Y_{n+1}/Y_n 

174 

175 Parameters 

176 ---------- 

177 GroFacs : list or numpy array 

178 Growth factors in chronological order. 

179 Y0 : float 

180 initial value of the series. 

181 

182 Returns 

183 ------- 

184 Y : numpy array 

185 Array with the values of the series. 

186 

187 """ 

188 factors = np.array([Y0] + GroFacs) 

189 Y = np.cumprod(factors) 

190 

191 return Y 

192 

193 

194# %% Tools for life-cycle profiles of income volatility 

195 

196# The raw results shared by John Sabelhaus contain the following two 

197# sets of estimates (with and without cohor trends), which we will 

198# use for constructing the age profiles. 

199 

200# The first specification contains a cohort trend. The variance of 

201# (transitory or permanent) shocks to income of a person born in year 

202# "cohort" and who is now age "age" is 

203# age_dummy(age) + beta * (cohort - 1926) 

204# Where we have dummies for ages 27 to 54 

205Sabelhaus_Song_cohort_trend = { 

206 "Ages": np.arange(27, 55), 

207 "AgeDummiesPrm": np.array( 

208 [ 

209 0.0837941, 

210 0.0706855, 

211 0.0638561, 

212 0.0603879, 

213 0.0554693, 

214 0.0532388, 

215 0.0515262, 

216 0.0486079, 

217 0.0455297, 

218 0.0456573, 

219 0.0417433, 

220 0.0420146, 

221 0.0391508, 

222 0.0395776, 

223 0.0369826, 

224 0.0387158, 

225 0.0365356, 

226 0.036701, 

227 0.0364236, 

228 0.0358601, 

229 0.0348528, 

230 0.0362901, 

231 0.0373366, 

232 0.0372724, 

233 0.0401297, 

234 0.0415868, 

235 0.0434772, 

236 0.046668, 

237 ] 

238 ), 

239 "AgeDummiesTrn": np.array( 

240 [ 

241 0.1412842, 

242 0.1477754, 

243 0.1510265, 

244 0.1512203, 

245 0.1516837, 

246 0.151412, 

247 0.1489388, 

248 0.148521, 

249 0.1470632, 

250 0.143514, 

251 0.1411806, 

252 0.1378733, 

253 0.135245, 

254 0.1318365, 

255 0.1299689, 

256 0.1255799, 

257 0.1220823, 

258 0.1178995, 

259 0.1148793, 

260 0.1107577, 

261 0.1073337, 

262 0.102347, 

263 0.0962066, 

264 0.0918819, 

265 0.0887777, 

266 0.0835057, 

267 0.0766663, 

268 0.0698848, 

269 ] 

270 ), 

271 "CohortCoefPrm": -0.0005966, 

272 "CohortCoefTrn": -0.0017764 / 2, 

273} 

274 

275# The second specification contains no cohort trend. The variance of 

276# (transitory or permanent) shocks to income of a person born in year 

277# "cohort" and who is now age "age" is: age_dummy(age) 

278# Where we have dummies for ages 27 to 54. We use this "aggregate" 

279# specification if no cohort is provided. 

280Sabelhaus_Song_all_years = { 

281 "Ages": np.arange(27, 55), 

282 "AgeDummiesPrm": np.array( 

283 [ 

284 0.0599296, 

285 0.0474176, 

286 0.0411848, 

287 0.0383132, 

288 0.0339912, 

289 0.0323573, 

290 0.0312414, 

291 0.0289196, 

292 0.0264381, 

293 0.0271623, 

294 0.0238449, 

295 0.0247128, 

296 0.0224456, 

297 0.0234691, 

298 0.0214706, 

299 0.0238005, 

300 0.0222169, 

301 0.0229789, 

302 0.0232982, 

303 0.0233312, 

304 0.0229205, 

305 0.0249545, 

306 0.0265975, 

307 0.02713, 

308 0.0305839, 

309 0.0326376, 

310 0.0351246, 

311 0.038912, 

312 ] 

313 ), 

314 "AgeDummiesTrn": np.array( 

315 [ 

316 0.1061999, 

317 0.1135794, 

318 0.1177187, 

319 0.1188007, 

320 0.1201523, 

321 0.1207688, 

322 0.1191838, 

323 0.1196542, 

324 0.1190846, 

325 0.1164236, 

326 0.1149784, 

327 0.1125594, 

328 0.1108192, 

329 0.1082989, 

330 0.1073195, 

331 0.1038188, 

332 0.1012094, 

333 0.0979148, 

334 0.0957829, 

335 0.0925495, 

336 0.0900136, 

337 0.0859151, 

338 0.0806629, 

339 0.0772264, 

340 0.0750105, 

341 0.0706267, 

342 0.0646755, 

343 0.0587821, 

344 ] 

345 ), 

346 "CohortCoefPrm": 0, 

347 "CohortCoefTrn": 0, 

348} 

349 

350 

351def sabelhaus_song_var_profile(age_min=27, age_max=54, cohort=None, smooth=True): 

352 """ 

353 This is a function to find the life-cycle profiles of the volatilities 

354 of transitory and permanent shocks to income using the estimates in 

355 [1] Sabelhaus and Song (2010). 

356 

357 Parameters 

358 ---------- 

359 age_min : int, optional 

360 Minimum age at which to construct volatilities. The default is 27. 

361 age_max : int, optional 

362 Maximum age at which to construct volatilities. The default is 54. 

363 cohort : int, optional 

364 Birth year of the hypothetical person for which the volatilities will 

365 be constructed. The default is None, and in this case the we will 

366 use the specification that does not have cohort trends. 

367 smooth: bool, optional 

368 Boolean indicating whether to smooth the variance profile estimates 

369 using third degree polynomials for the age dummies estimated by 

370 Sabelhaus and Song. If False, the original dummies are used. 

371 

372 Returns 

373 ------- 

374 profiles : dict 

375 Dictionary with entries: 

376 - Ages: array of ages for which we found income volatilities in 

377 ascending order 

378 - TranShkStd: array of standard deviations of transitory income 

379 shocks. Position n corresponds to Ages[n]. 

380 - PermShkStd: array of standard deviations of permanent income 

381 shocks. Position n corresponds to Ages[n]. 

382 

383 Note that TransShkStd[n] and PermShkStd[n] are the volatilities of 

384 shocks _experienced_ at age Age[n], (not those expected at Age[n+1] 

385 from the perspective of Age[n]). 

386 

387 Note that Sabelhaus and Song work in discrete time and with periods 

388 that represent one year. Therefore, the outputs must be interpreted 

389 at the yearly frequency. 

390 """ 

391 

392 assert age_max >= age_min, ( 

393 "The maximum age can not be lower than the " + "minimum age." 

394 ) 

395 

396 # Determine which set of estimates to use based on wether a cohort is 

397 # provided or not. 

398 if cohort is None: 

399 spec = Sabelhaus_Song_all_years 

400 cohort = 0 

401 _log.debug("No cohort was provided. Using aggregate specification.") 

402 

403 else: 

404 spec = Sabelhaus_Song_cohort_trend 

405 

406 # Extract coefficients 

407 beta_eps = spec["CohortCoefTrn"] 

408 beta_eta = spec["CohortCoefPrm"] 

409 tran_age_dummies = spec["AgeDummiesTrn"] 

410 perm_age_dummies = spec["AgeDummiesPrm"] 

411 

412 # Smooth out dummies using a 3rd degree polynomial if requested 

413 if smooth: 

414 # Fit polynomials 

415 tran_poly = np.poly1d(np.polyfit(spec["Ages"], tran_age_dummies, deg=3)) 

416 perm_poly = np.poly1d(np.polyfit(spec["Ages"], perm_age_dummies, deg=3)) 

417 

418 # Replace dummies 

419 tran_age_dummies = tran_poly(spec["Ages"]) 

420 perm_age_dummies = perm_poly(spec["Ages"]) 

421 

422 # Make interpolators for transitory and permanent dummies. Alter to use 

423 # flat extrapolation. 

424 

425 # We use Sabelhaus and Song (2010) dummies for ages 27-54 and extrapolate 

426 # outside of that just using the endpoints. 

427 tran_dummy_interp = LinearInterp( 

428 np.arange(min(spec["Ages"]) - 1, max(spec["Ages"]) + 2), 

429 np.concatenate( 

430 [[tran_age_dummies[0]], tran_age_dummies, [tran_age_dummies[-1]]] 

431 ), 

432 lower_extrap=True, 

433 ) 

434 

435 perm_dummy_interp = LinearInterp( 

436 np.arange(min(spec["Ages"]) - 1, max(spec["Ages"]) + 2), 

437 np.concatenate( 

438 [[perm_age_dummies[0]], perm_age_dummies, [perm_age_dummies[-1]]] 

439 ), 

440 lower_extrap=True, 

441 ) 

442 

443 if age_min < 27 or age_max > 54: 

444 _log.debug( 

445 "Sabelhaus and Song (2010) provide variance profiles for ages " 

446 + "27 to 54. Extrapolating variances using the extreme points." 

447 ) 

448 

449 if cohort < 1926 or cohort > 1980: 

450 _log.debug( 

451 "Sabelhaus and Song (2010) use data from birth cohorts " 

452 + "[1926,1980]. Extrapolating variances." 

453 ) 

454 

455 cohort = max(min(cohort, 1980), 1926) 

456 

457 # Construct variances 

458 # They use 1926 as the base year for cohort effects. 

459 ages = np.arange(age_min, age_max + 1) 

460 tran_var = tran_dummy_interp(ages) + (cohort - 1926) * beta_eps 

461 perm_var = perm_dummy_interp(ages) + (cohort - 1926) * beta_eta 

462 

463 profiles = { 

464 "Age": list(ages), 

465 "TranShkStd": list(np.sqrt(tran_var)), 

466 "PermShkStd": list(np.sqrt(perm_var)), 

467 } 

468 

469 return profiles 

470 

471 

472# %% Encompassing tool to parse full income specifications 

473 

474 

475def parse_income_spec( 

476 base_monet_year, 

477 age_min, 

478 age_max, 

479 age_ret=None, 

480 AgePolyCoefs=None, 

481 ReplRate=None, 

482 AgePolyRetir=None, 

483 YearTrend=None, 

484 start_year=None, 

485 PermShkStd=None, 

486 TranShkStd=None, 

487 SabelhausSong=False, 

488 adjust_infl_to=None, 

489): 

490 r""" 

491 A function that produces income growth rates and income shock volatilities 

492 

493 Parameters 

494 ---------- 

495 base_monet_year : int 

496 Base monetary year in which the income process is specified. Answer to 

497 "In what year's U.S. dollars was income expressed in the process that 

498 will be parsed?". 

499 age_min : int 

500 Age at which agents enter the model. 

501 age_max : int 

502 Age at whih agents die with certainty. E.g., if age_max = 100, the 

503 agent dies at the end of his 100th year of life. 

504 age_ret : int, optional 

505 Age of retirement. The default is None. 

506 AgePolyCoefs : numpy array or list of floats 

507 Coefficients of the income log-polynomial, in ascending degree order 

508 (starting with the constant). Permanent income follows the specification: 

509 ln(P)_age = \sum_{i=1}^{len(AgePolyCoefs)} (age/10)^i * AgePolyCoefs[i]. 

510 The default is None. 

511 ReplRate : float, optional 

512 Replacement rate for retirement income. Retirement income will be 

513 Income_{age_ret} * ReplRate. The default is None. 

514 AgePolyRetir : numpy array or list of floats 

515 Specifies a different age polynomial for income after retirement. It 

516 follows the same convention as AgePolyCoefs. The default is None. 

517 YearTrend : dict, optional 

518 Dictionary with entries "Coef" (float) and "ZeroYear" (int). Allows 

519 a time trend to be added to log-income. If provided, mean log-income at 

520 age a and year t will be: 

521 ln P = polynomial(a) + Coef * (t - ZeroYear) 

522 The default is None. 

523 start_year : int, optional 

524 Year at which the agent enters the model. This is important only for 

525 specifications with a time-trend for income profiles. 

526 The default is None. 

527 PermShkStd : float, optional 

528 Standard deviation of log-permanent-income shocks, if it is constant. 

529 The default is None. 

530 TranShkStd : float, optional 

531 Standard deviation of log-transitory-income shocks, if it is constant. 

532 The default is None. 

533 SabelhausSong : bool, optional 

534 Indicates whether to use transitory and permanent income shock 

535 volatilities from Sabelhaus & Song (2010) "The Great Moderation in 

536 Micro Labor Earnings". The default is False. 

537 adjust_infl_to : int, optional 

538 Year at which nominal quantities should be expressed. Answers the 

539 question "In what year's U.S. dollars should income be expressed". 

540 The default is None. In such case, base_monet_year will be used. 

541 

542 Returns 

543 ------- 

544 income_params : dict 

545 Dictionary with entries: 

546 - P0: initial level of permanent income. 

547 - pLogInitMean: mean of the distribution of log-permanent income. 

548 np.log(P0) = pLogInitMean 

549 - PermGroFac : list of deterministic growth factors for permanent 

550 income. 

551 - PermShkStd: list of standard deviations of shocks to 

552 log-permanent income. 

553 - TranShkStd: list of standard deviations of transitory shocks 

554 to income. 

555 - PermGroFacAgg: if a yearly trend in income is provided, this will 

556 be the aggregate level of growth in permanent incomes. 

557 - T_retire : period of the agent's problem after which they retire. 

558 

559 This dictionary has the names and formats that various models in HARK 

560 expect, so that it can be directly updated into other parameter 

561 dictionaries. 

562 """ 

563 

564 income_params = {} 

565 # How many non-terminal periods are there. 

566 N_periods = age_max - age_min 

567 

568 if age_ret is not None: 

569 # How many non terminal periods are spent working 

570 N_work_periods = age_ret - age_min + 1 

571 # How many non terminal periods are spent in retirement 

572 N_ret_periods = age_max - age_ret - 1 

573 

574 # Growth factors 

575 if AgePolyCoefs is not None: 

576 if AgePolyRetir is None: 

577 PermGroFac, P0 = find_PermGroFacs( 

578 age_min, age_max, age_ret, AgePolyCoefs, ReplRate 

579 ) 

580 

581 else: 

582 # Working period 

583 PermGroWrk, P0 = find_PermGroFacs( 

584 age_min, age_ret, None, AgePolyCoefs, ReplRate 

585 ) 

586 PLast = find_profile(PermGroWrk[:-1], P0)[-1] 

587 

588 # Retirement period 

589 PermGroRet, R0 = find_PermGroFacs( 

590 age_ret + 1, age_max, None, AgePolyRetir, ReplRate 

591 ) 

592 

593 # Input the replacement rate into the Work grow factors 

594 PermGroWrk[-1] = R0 / PLast 

595 PermGroFac = PermGroWrk + PermGroRet 

596 

597 # In any case, PermGroFac[-1] will be np.nan, signaling that there is 

598 # no expected growth in the terminal period. Discard it, as HARK expect 

599 # list of growth rates for non-terminal periods 

600 PermGroFac = PermGroFac[:-1] 

601 

602 # Apply the yearly trend if it is given 

603 if YearTrend is not None: 

604 # Compute and apply the compounding yearly growth factor 

605 YearGroFac = np.exp(YearTrend["Coef"]) 

606 PermGroFac = [x * YearGroFac for x in PermGroFac] 

607 

608 # Aggregate growth 

609 income_params["PermGroFacAgg"] = YearGroFac 

610 

611 # Adjust P0 with the year trend 

612 if start_year is not None: 

613 P0 = P0 * np.power(YearGroFac, start_year - YearTrend["ZeroYear"]) 

614 

615 income_params["PermGroFac"] = PermGroFac 

616 

617 else: 

618 # Placeholder for future ways of storing income calibrations 

619 raise NotImplementedError() 

620 

621 # Volatilities 

622 # In this section, it is important to keep in mind that IncomeDstn[t] 

623 # is the income distribution from period t to t+1, as perceived in period 

624 # t. 

625 # Therefore (assuming an annual model with agents entering at age 0), 

626 # IncomeDstn[3] would contain the distribution of income shocks that occur 

627 # at the start of age 4. 

628 if SabelhausSong: 

629 if age_ret is None: 

630 IncShkStds = sabelhaus_song_var_profile( 

631 cohort=1950, age_min=age_min + 1, age_max=age_max 

632 ) 

633 PermShkStd = IncShkStds["PermShkStd"] 

634 TranShkStd = IncShkStds["TranShkStd"] 

635 

636 else: 

637 IncShkStds = sabelhaus_song_var_profile( 

638 cohort=1950, age_min=age_min + 1, age_max=age_ret 

639 ) 

640 PermShkStd = IncShkStds["PermShkStd"] + [0.0] * (N_ret_periods + 1) 

641 TranShkStd = IncShkStds["TranShkStd"] + [0.0] * (N_ret_periods + 1) 

642 

643 else: 

644 if isinstance(PermShkStd, float) and isinstance(TranShkStd, float): 

645 if age_ret is None: 

646 PermShkStd = [PermShkStd] * N_periods 

647 TranShkStd = [TranShkStd] * N_periods 

648 

649 else: 

650 PermShkStd = [PermShkStd] * (N_work_periods - 1) + [0.0] * ( 

651 N_ret_periods + 1 

652 ) 

653 TranShkStd = [TranShkStd] * (N_work_periods - 1) + [0.0] * ( 

654 N_ret_periods + 1 

655 ) 

656 

657 else: 

658 # Placeholder for future ways of specifying volatilities 

659 raise NotImplementedError() 

660 

661 income_params["PermShkStd"] = PermShkStd 

662 income_params["TranShkStd"] = TranShkStd 

663 

664 # Apply inflation adjustment if requested 

665 if adjust_infl_to is not None: 

666 # Deflate using the CPI september measurement, which is what the SCF 

667 # uses. 

668 defl = cpi_deflator( 

669 from_year=base_monet_year, to_year=adjust_infl_to, base_month="SEP" 

670 )[0] 

671 

672 else: 

673 defl = 1 

674 

675 P0 = P0 * defl 

676 income_params["P0"] = P0 

677 income_params["pLogInitMean"] = np.log(P0) 

678 income_params["T_retire"] = N_work_periods 

679 

680 return income_params 

681 

682 

683# %% Income specifications from various papers 

684 

685# Processes from Cocco, Gomes, Maenhout (2005): 

686# Cocco, J. F., Gomes, F. J., & Maenhout, P. J. (2005). Consumption and 

687# portfolio choice over the life cycle. The Review of Financial Studies, 

688# 18(2), 491-533. 

689# - The profiles are provided as presented in the original paper. 

690# - It seem to us that income peaks at very young ages. 

691# - We suspect this might be due to the author's treatment of trends in income 

692# growth. 

693# - This can be adressed using the YearTrend and pLvlGroFacAgg options. 

694CGM_income = { 

695 "NoHS": { 

696 "AgePolyCoefs": [-2.1361 + 2.6275, 0.1684 * 10, -0.0353 * 10, 0.0023 * 10], 

697 "age_ret": 65, 

698 "ReplRate": 0.8898, 

699 "PermShkStd": np.sqrt(0.0105), 

700 "TranShkStd": np.sqrt(0.1056), 

701 "base_monet_year": 1992, 

702 }, 

703 "HS": { 

704 "AgePolyCoefs": [-2.1700 + 2.7004, 0.1682 * 10, -0.0323 * 10, 0.0020 * 10], 

705 "age_ret": 65, 

706 "ReplRate": 0.6821, 

707 "PermShkStd": np.sqrt(0.0106), 

708 "TranShkStd": np.sqrt(0.0738), 

709 "base_monet_year": 1992, 

710 }, 

711 "College": { 

712 "AgePolyCoefs": [-4.3148 + 2.3831, 0.3194 * 10, -0.0577 * 10, 0.0033 * 10], 

713 "age_ret": 65, 

714 "ReplRate": 0.9389, 

715 "PermShkStd": np.sqrt(0.0169), 

716 "TranShkStd": np.sqrt(0.0584), 

717 "base_monet_year": 1992, 

718 }, 

719} 

720 

721# Processes from Cagetti (2003) 

722# Cagetti, M. (2003). Wealth accumulation over the life cycle and precautionary 

723# savings. Journal of Business & Economic Statistics, 21(3), 339-353. 

724# - The author generously provided estimates from which the age polynomials 

725# and yearly trends were recovered. 

726# - He uses volatilities from Carroll-Samwick (1997) 

727# - He expresses income in dollars. It is more amicable to express it in 

728# thousands of dollars, also making it comparable to CGM. Thus, we substract 

729# ln(1e3) = 3*ln(10) from intercepts, which is equivalent to dividing income 

730# by a thousand. 

731Cagetti_income = { 

732 "NoHS": { 

733 "AgePolyCoefs": [ 

734 7.99641616 - 3.0 * np.log(10), 

735 1.06559456, 

736 -0.14449728, 

737 0.00048128, 

738 0.0004096, 

739 ], 

740 "AgePolyRetir": [10.84636791 - 3.0 * np.log(10), -0.24562326], 

741 "YearTrend": {"Coef": 0.016, "ZeroYear": 1980}, 

742 "age_ret": 65, 

743 "PermShkStd": np.sqrt(0.0214), # Take 9-12 from CS 

744 "TranShkStd": np.sqrt(0.0658), # Take 9-12 from CS 

745 "base_monet_year": 1992, 

746 }, 

747 "HS": { 

748 "AgePolyCoefs": [ 

749 10.01333075 - 3.0 * np.log(10), 

750 -0.563234304, 

751 0.348710528, 

752 -0.059442176, 

753 0.002947072, 

754 ], 

755 "AgePolyRetir": [11.21721558 - 3.0 * np.log(10), -0.26820465], 

756 "YearTrend": {"Coef": 0.016, "ZeroYear": 1980}, 

757 "age_ret": 65, 

758 "PermShkStd": np.sqrt(0.0277), # Take HS diploma from CS 

759 "TranShkStd": np.sqrt(0.0431), # Take HS diploma from CS 

760 "base_monet_year": 1992, 

761 }, 

762 "College": { 

763 "AgePolyCoefs": [ 

764 9.916855488 - 3.0 * np.log(10), 

765 -0.057984416, 

766 0.146196992, 

767 -0.027623424, 

768 0.001282048, 

769 ], 

770 "AgePolyRetir": [10.81011279 - 3.0 * np.log(10), -0.16610233], 

771 "YearTrend": {"Coef": 0.016, "ZeroYear": 1980}, 

772 "age_ret": 65, 

773 "PermShkStd": np.sqrt(0.0146), # Take College degree from CS 

774 "TranShkStd": np.sqrt(0.0385), # Take College degree from CS 

775 "base_monet_year": 1992, 

776 }, 

777}