Coverage for HARK / ConsumptionSaving / ConsWealthPortfolioModel.py: 96%
188 statements
« prev ^ index » next coverage.py v7.12.0, created at 2025-12-07 05:16 +0000
« prev ^ index » next coverage.py v7.12.0, created at 2025-12-07 05:16 +0000
1from copy import deepcopy
3import numpy as np
4from HARK.ConsumptionSaving.ConsPortfolioModel import (
5 PortfolioConsumerType,
6 PortfolioSolution,
7 make_portfolio_solution_terminal,
8)
9from HARK.distributions import expected
10from HARK.interpolation import (
11 BilinearInterp,
12 ConstantFunction,
13 CubicInterp,
14 LinearInterp,
15 MargValueFuncCRRA,
16 ValueFuncCRRA,
17)
18from HARK.Calibration.Assets.AssetProcesses import (
19 make_lognormal_RiskyDstn,
20 combine_IncShkDstn_and_RiskyDstn,
21 calc_ShareLimit_for_CRRA,
22)
23from HARK.Calibration.Income.IncomeProcesses import (
24 construct_lognormal_income_process_unemployment,
25 get_PermShkDstn_from_IncShkDstn,
26 get_TranShkDstn_from_IncShkDstn,
27)
28from HARK.ConsumptionSaving.ConsRiskyAssetModel import (
29 make_simple_ShareGrid,
30 make_AdjustDstn,
31)
32from HARK.ConsumptionSaving.ConsIndShockModel import (
33 make_lognormal_kNrm_init_dstn,
34 make_lognormal_pLvl_init_dstn,
35)
36from HARK.rewards import UtilityFuncCRRA
37from HARK.utilities import NullFunc, make_assets_grid
40class ChiFromOmegaFunction:
41 """
42 A class for representing a function that takes in values of omega = EndOfPrdvP / aNrm
43 and returns the corresponding optimal chi = cNrm / aNrm. The only parameters
44 that matter for this transformation are the coefficient of relative risk
45 aversion (rho) and the share of wealth in the Cobb-Douglas aggregator (delta).
47 Parameters
48 ----------
49 CRRA : float
50 Coefficient of relative risk aversion.
51 WealthShare : float
52 Share for wealth in the Cobb-Douglas aggregator in CRRA utility function.
53 N : int, optional
54 Number of interpolating gridpoints to use (default 501).
55 z_bound : float, optional
56 Absolute value on the auxiliary variable z's boundary (default 15).
57 z represents values that are input into a logit transformation
58 scaled by the upper bound of chi, which yields chi values.
59 """
61 def __init__(self, CRRA, WealthShare, N=501, z_bound=15):
62 self.CRRA = CRRA
63 self.WealthShare = WealthShare
64 self.N = N
65 self.z_bound = z_bound
66 self.update()
68 def f(self, x):
69 """
70 Define the relationship between chi and omega, and evaluate on the vector
71 """
72 r = self.CRRA
73 d = self.WealthShare
74 return x ** (1 - d) * ((1 - d) * x ** (-d) - d * x ** (1 - d)) ** (-1 / r)
76 def update(self):
77 """
78 Construct the underlying interpolation of log(omega) on z.
79 """
80 # Make vectors of chi and z
81 chi_limit = (1.0 - self.WealthShare) / self.WealthShare
82 z_vec = np.linspace(-self.z_bound, self.z_bound, self.N)
83 exp_z = np.exp(z_vec)
84 chi_vec = chi_limit * exp_z / (1 + exp_z)
86 omega_vec = self.f(chi_vec)
87 log_omega_vec = np.log(omega_vec)
89 # Construct the interpolant
90 zFromLogOmegaFunc = LinearInterp(log_omega_vec, z_vec, lower_extrap=True)
92 # Store the function and limit as attributes
93 self.func = zFromLogOmegaFunc
94 self.limit = chi_limit
96 def __call__(self, omega):
97 """
98 Calculate optimal values of chi = cNrm / aNrm from values of omega.
100 Parameters
101 ----------
102 omega : np.array
103 One or more values of omega = EndOfPrdvP / aNrm.
105 Returns
106 -------
107 chi : np.array
108 Identically shaped array with optimal chi values.
109 """
110 z = self.func(np.log(omega))
111 exp_z = np.exp(z)
112 chi = self.limit * exp_z / (1 + exp_z)
113 return np.nan_to_num(chi)
116# Trivial constructor function
117def make_ChiFromOmega_function(CRRA, WealthShare, ChiFromOmega_N, ChiFromOmega_bound):
118 if WealthShare == 0.0:
119 return NullFunc()
120 return ChiFromOmegaFunction(
121 CRRA, WealthShare, N=ChiFromOmega_N, z_bound=ChiFromOmega_bound
122 )
125###############################################################################
128def utility(c, a, CRRA, share=0.0, intercept=0.0):
129 w = a + intercept
130 return (c ** (1 - share) * w**share) ** (1 - CRRA) / (1 - CRRA)
133def dudc(c, a, CRRA, share=0.0, intercept=0.0):
134 u = utility(c, a, CRRA, share, intercept)
135 return u * (1 - CRRA) * (1 - share) / c
138def calc_m_nrm_next(shocks, b_nrm, perm_gro_fac):
139 """
140 Calculate future realizations of market resources mNrm from the income
141 shock distribution S and normalized bank balances b.
142 """
143 return b_nrm / (shocks["PermShk"] * perm_gro_fac) + shocks["TranShk"]
146def calc_dvdm_next(shocks, b_nrm, perm_gro_fac, crra, vp_func):
147 """
148 Evaluate realizations of marginal value of market resources next period,
149 based on the income distribution S and values of bank balances bNrm
150 """
151 m_nrm = calc_m_nrm_next(shocks, b_nrm, perm_gro_fac)
152 perm_shk_fac = shocks["PermShk"] * perm_gro_fac
153 return perm_shk_fac ** (-crra) * vp_func(m_nrm)
156def calc_end_dvdx(shocks, a_nrm, share, rfree, dvdb_func):
157 ex_ret = shocks - rfree # Excess returns
158 rport = rfree + share * ex_ret # Portfolio return
159 b_nrm = rport * a_nrm
161 # Calculate and return dvds (second term is all zeros)
162 dvdb = dvdb_func(b_nrm)
163 dvda = rport * dvdb
164 dvds = ex_ret * a_nrm * dvdb
165 return dvda, dvds
168def calc_med_v(shocks, b_nrm, perm_gro_fac, crra, v_func):
169 """
170 Calculate "intermediate" value from next period's bank balances, the
171 income shocks S, and the risky asset share.
172 """
173 m_nrm = calc_m_nrm_next(shocks, b_nrm, perm_gro_fac)
174 v_next = v_func(m_nrm)
175 return (shocks["PermShk"] * perm_gro_fac) ** (1.0 - crra) * v_next
178def calc_end_v(shocks, a_nrm, share, rfree, v_func):
179 # Calculate future realizations of bank balances bNrm
180 ex_ret = shocks - rfree
181 rport = rfree + share * ex_ret
182 b_nrm = rport * a_nrm
183 return v_func(b_nrm)
186###############################################################################
189def solve_one_period_WealthPortfolio(
190 solution_next,
191 IncShkDstn,
192 RiskyDstn,
193 LivPrb,
194 DiscFac,
195 CRRA,
196 Rfree,
197 PermGroFac,
198 BoroCnstArt,
199 aXtraGrid,
200 ShareGrid,
201 ShareLimit,
202 vFuncBool,
203 WealthShare,
204 WealthShift,
205 ChiFunc,
206):
207 """
208 TODO: Fill in this missing docstring.
210 Parameters
211 ----------
212 solution_next : TYPE
213 DESCRIPTION.
214 IncShkDstn : TYPE
215 DESCRIPTION.
216 RiskyDstn : TYPE
217 DESCRIPTION.
218 LivPrb : TYPE
219 DESCRIPTION.
220 DiscFac : TYPE
221 DESCRIPTION.
222 CRRA : TYPE
223 DESCRIPTION.
224 Rfree : TYPE
225 DESCRIPTION.
226 PermGroFac : TYPE
227 DESCRIPTION.
228 BoroCnstArt : TYPE
229 DESCRIPTION.
230 aXtraGrid : TYPE
231 DESCRIPTION.
232 ShareGrid : TYPE
233 DESCRIPTION.
234 ShareLimit : TYPE
235 DESCRIPTION.
236 vFuncBool : TYPE
237 DESCRIPTION.
238 WealthShare : TYPE
239 DESCRIPTION.
240 WealthShift : TYPE
241 DESCRIPTION.
242 ChiFunc : TYPE
243 DESCRIPTION.
245 Returns
246 -------
247 solution_now : TYPE
248 DESCRIPTION.
250 """
251 # Make sure the individual is liquidity constrained. Allowing a consumer to
252 # borrow *and* invest in an asset with unbounded (negative) returns is a bad mix.
253 if BoroCnstArt != 0.0:
254 raise ValueError("PortfolioConsumerType must have BoroCnstArt=0.0!")
256 # Define the current period utility function and effective discount factor
257 uFunc = UtilityFuncCRRA(CRRA)
258 DiscFacEff = DiscFac * LivPrb # "effective" discount factor
260 # Unpack next period's solution for easier access
261 vp_func_next = solution_next.vPfuncAdj
262 v_func_next = solution_next.vFuncAdj
264 # Set a flag for whether the natural borrowing constraint is zero, which
265 # depends on whether the smallest transitory income shock is zero
266 BoroCnstNat_iszero = (np.min(IncShkDstn.atoms[1]) == 0.0) or (
267 WealthShare != 0.0 and WealthShift == 0.0
268 )
270 # Prepare to calculate end-of-period marginal values by creating an array
271 # of market resources that the agent could have next period, considering
272 # the grid of end-of-period assets and the distribution of shocks he might
273 # experience next period.
275 # Unpack the risky return shock distribution
276 Risky_next = RiskyDstn.atoms
277 RiskyMax = np.max(Risky_next)
278 RiskyMin = np.min(Risky_next)
280 # bNrm represents R*a, balances after asset return shocks but before income.
281 # This just uses the highest risky return as a rough shifter for the aXtraGrid.
282 if BoroCnstNat_iszero:
283 aNrmGrid = aXtraGrid
284 bNrmGrid = np.insert(RiskyMax * aXtraGrid, 0, RiskyMin * aXtraGrid[0])
285 else:
286 # Add an asset point at exactly zero
287 aNrmGrid = np.insert(aXtraGrid, 0, 0.0)
288 bNrmGrid = RiskyMax * np.insert(aXtraGrid, 0, 0.0)
290 # Get grid and shock sizes, for easier indexing
291 aNrmCount = aNrmGrid.size
293 # Make tiled arrays to calculate future realizations of mNrm and Share when integrating over IncShkDstn
294 bNrmNext = bNrmGrid
296 # Calculate end-of-period marginal value of assets and shares at each point
297 # in aNrm and ShareGrid. Does so by taking expectation of next period marginal
298 # values across income and risky return shocks.
300 # Calculate intermediate marginal value of bank balances by taking expectations over income shocks
301 med_dvdb = expected(
302 calc_dvdm_next,
303 IncShkDstn,
304 args=(bNrmNext, PermGroFac, CRRA, vp_func_next),
305 )
306 med_dvdb_nvrs = uFunc.derinv(med_dvdb, order=(1, 0))
307 med_dvdb_nvrs_func = LinearInterp(bNrmGrid, med_dvdb_nvrs)
308 med_dvdb_func = MargValueFuncCRRA(med_dvdb_nvrs_func, CRRA)
310 # Make tiled arrays to calculate future realizations of bNrm and Share when integrating over RiskyDstn
311 aNrmNow, ShareNext = np.meshgrid(aNrmGrid, ShareGrid, indexing="ij")
313 # Evaluate realizations of value and marginal value after asset returns are realized
314 end_dvda, end_dvds = DiscFacEff * expected(
315 calc_end_dvdx,
316 RiskyDstn,
317 args=(aNrmNow, ShareNext, Rfree, med_dvdb_func),
318 )
319 end_dvda_nvrs = uFunc.derinv(end_dvda)
321 # Now find the optimal (continuous) risky share on [0,1] by solving the first
322 # order condition end_dvds == 0.
323 focs = end_dvds # Relabel for convenient typing
325 # For each value of aNrm, find the value of Share such that focs == 0
326 crossing = np.logical_and(focs[:, 1:] <= 0.0, focs[:, :-1] >= 0.0)
327 share_idx = np.argmax(crossing, axis=1)
328 # This represents the index of the segment of the share grid where dvds flips
329 # from positive to negative, indicating that there's a zero *on* the segment
331 # Calculate the fractional distance between those share gridpoints where the
332 # zero should be found, assuming a linear function; call it alpha
333 a_idx = np.arange(aNrmCount)
334 bot_s = ShareGrid[share_idx]
335 top_s = ShareGrid[share_idx + 1]
336 bot_f = focs[a_idx, share_idx]
337 top_f = focs[a_idx, share_idx + 1]
338 bot_c = end_dvda_nvrs[a_idx, share_idx]
339 top_c = end_dvda_nvrs[a_idx, share_idx + 1]
340 bot_dvda = end_dvda[a_idx, share_idx]
341 top_dvda = end_dvda[a_idx, share_idx + 1]
342 alpha = 1.0 - top_f / (top_f - bot_f)
344 # Calculate the continuous optimal risky share and optimal consumption
345 Share_now = (1.0 - alpha) * bot_s + alpha * top_s
346 end_dvda_nvrs_now = (1.0 - alpha) * bot_c + alpha * top_c
347 end_dvda_now = (1.0 - alpha) * bot_dvda + alpha * top_dvda
349 # If agent wants to put more than 100% into risky asset, he is constrained.
350 # Likewise if he wants to put less than 0% into risky asset, he is constrained.
351 constrained_top = focs[:, -1] > 0.0
352 constrained_bot = focs[:, 0] < 0.0
354 # Apply those constraints to both risky share and consumption (but lower
355 # constraint should never be relevant)
356 Share_now[constrained_top] = 1.0
357 Share_now[constrained_bot] = 0.0
358 end_dvda_nvrs_now[constrained_top] = end_dvda_nvrs[constrained_top, -1]
359 end_dvda_nvrs_now[constrained_bot] = end_dvda_nvrs[constrained_bot, 0]
360 end_dvda_now[constrained_top] = end_dvda[constrained_top, -1]
361 end_dvda_now[constrained_bot] = end_dvda[constrained_bot, 0]
363 # When the natural borrowing constraint is *not* zero, then aNrm=0 is in the
364 # grid, but there's no way to "optimize" the portfolio if a=0, and consumption
365 # can't depend on the risky share if it doesn't meaningfully exist. Apply
366 # a small fix to the bottom gridpoint (aNrm=0) when this happens.
367 if not BoroCnstNat_iszero:
368 Share_now[0] = 1.0
369 end_dvda_nvrs_now[0] = end_dvda_nvrs[0, -1]
370 end_dvda_now[0] = end_dvda[0, -1]
372 # Now this is where we look for optimal C
373 # for each a in the agrid find corresponding c that satisfies the euler equation
375 if WealthShare == 0.0:
376 cNrm_now = end_dvda_nvrs_now
377 else:
378 omega = end_dvda_nvrs_now / (aNrmGrid + WealthShift)
379 cNrm_now = ChiFunc(omega) * (aNrmGrid + WealthShift)
381 # Calculate the endogenous mNrm gridpoints when the agent adjusts his portfolio,
382 # then construct the consumption function when the agent can adjust his share
383 mNrm_now = np.insert(aNrmGrid + cNrm_now, 0, 0.0)
384 cNrm_now = np.insert(cNrm_now, 0, 0.0)
385 cFuncNow = LinearInterp(mNrm_now, cNrm_now)
387 dudc_now = dudc(cNrm_now, mNrm_now - cNrm_now, CRRA, WealthShare, WealthShift)
388 dudc_nvrs_now = uFunc.derinv(dudc_now, order=(1, 0))
389 dudc_nvrs_func_now = LinearInterp(mNrm_now, dudc_nvrs_now)
391 # Construct the marginal value (of mNrm) function
392 vPfuncNow = MargValueFuncCRRA(dudc_nvrs_func_now, CRRA)
394 # If the share choice is continuous, just make an ordinary interpolating function
395 if BoroCnstNat_iszero:
396 Share_lower_bound = ShareLimit
397 else:
398 Share_lower_bound = 1.0
399 Share_now = np.insert(Share_now, 0, Share_lower_bound)
400 ShareFuncNow = LinearInterp(mNrm_now, Share_now, ShareLimit, 0.0)
402 # Add the value function if requested
403 if vFuncBool:
404 # Calculate intermediate value by taking expectations over income shocks
405 med_v = expected(
406 calc_med_v, IncShkDstn, args=(bNrmNext, PermGroFac, CRRA, v_func_next)
407 )
409 # Construct the "intermediate value function" for this period
410 med_v_nvrs = uFunc.inv(med_v)
411 med_v_nvrs_func = LinearInterp(bNrmGrid, med_v_nvrs)
412 med_v_func = ValueFuncCRRA(med_v_nvrs_func, CRRA)
414 # Calculate end-of-period value by taking expectations
415 end_v = DiscFacEff * expected(
416 calc_end_v,
417 RiskyDstn,
418 args=(aNrmNow, ShareNext, Rfree, med_v_func),
419 )
420 end_v_nvrs = uFunc.inv(end_v)
422 # Now make an end-of-period value function over aNrm and Share
423 end_v_nvrs_func = BilinearInterp(end_v_nvrs, aNrmGrid, ShareGrid)
424 end_v_func = ValueFuncCRRA(end_v_nvrs_func, CRRA)
425 # This will be used later to make the value function for this period
427 # Create the value functions for this period, defined over market resources
428 # mNrm when agent can adjust his portfolio, and over market resources and
429 # fixed share when agent can not adjust his portfolio.
431 # Construct the value function
432 mNrm_temp = aXtraGrid # Just use aXtraGrid as our grid of mNrm values
433 cNrm_temp = cFuncNow(mNrm_temp)
434 aNrm_temp = np.maximum(mNrm_temp - cNrm_temp, 0.0) # Fix tiny violations
435 Share_temp = ShareFuncNow(mNrm_temp)
436 v_temp = uFunc(cNrm_temp) + end_v_func(aNrm_temp, Share_temp)
437 vNvrs_temp = uFunc.inv(v_temp)
438 vNvrsP_temp = uFunc.der(cNrm_temp) * uFunc.inverse(v_temp, order=(0, 1))
439 vNvrsFunc = CubicInterp(
440 np.insert(mNrm_temp, 0, 0.0), # x_list
441 np.insert(vNvrs_temp, 0, 0.0), # f_list
442 np.insert(vNvrsP_temp, 0, vNvrsP_temp[0]), # dfdx_list
443 )
444 # Re-curve the pseudo-inverse value function
445 vFuncNow = ValueFuncCRRA(vNvrsFunc, CRRA)
447 else: # If vFuncBool is False, fill in dummy values
448 vFuncNow = NullFunc()
450 # Package and return the solution
451 solution_now = PortfolioSolution(
452 cFuncAdj=cFuncNow,
453 ShareFuncAdj=ShareFuncNow,
454 vPfuncAdj=vPfuncNow,
455 vFuncAdj=vFuncNow,
456 )
457 return solution_now
460###############################################################################
462# Make a dictionary of constructors for the wealth-in-utility portfolio choice consumer type
463WealthPortfolioConsumerType_constructors_default = {
464 "IncShkDstn": construct_lognormal_income_process_unemployment,
465 "PermShkDstn": get_PermShkDstn_from_IncShkDstn,
466 "TranShkDstn": get_TranShkDstn_from_IncShkDstn,
467 "aXtraGrid": make_assets_grid,
468 "RiskyDstn": make_lognormal_RiskyDstn,
469 "ShockDstn": combine_IncShkDstn_and_RiskyDstn,
470 "ShareLimit": calc_ShareLimit_for_CRRA,
471 "ShareGrid": make_simple_ShareGrid,
472 "ChiFunc": make_ChiFromOmega_function,
473 "AdjustDstn": make_AdjustDstn,
474 "kNrmInitDstn": make_lognormal_kNrm_init_dstn,
475 "pLvlInitDstn": make_lognormal_pLvl_init_dstn,
476 "solution_terminal": make_portfolio_solution_terminal,
477}
479# Default parameters to make IncShkDstn using construct_lognormal_income_process_unemployment
480WealthPortfolioConsumerType_IncShkDstn_default = {
481 "PermShkStd": [0.1], # Standard deviation of log permanent income shocks
482 "PermShkCount": 7, # Number of points in discrete approximation to permanent income shocks
483 "TranShkStd": [0.1], # Standard deviation of log transitory income shocks
484 "TranShkCount": 7, # Number of points in discrete approximation to transitory income shocks
485 "UnempPrb": 0.05, # Probability of unemployment while working
486 "IncUnemp": 0.3, # Unemployment benefits replacement rate while working
487 "T_retire": 0, # Period of retirement (0 --> no retirement)
488 "UnempPrbRet": 0.005, # Probability of "unemployment" while retired
489 "IncUnempRet": 0.0, # "Unemployment" benefits when retired
490}
492# Default parameters to make aXtraGrid using make_assets_grid
493WealthPortfolioConsumerType_aXtraGrid_default = {
494 "aXtraMin": 0.001, # Minimum end-of-period "assets above minimum" value
495 "aXtraMax": 100, # Maximum end-of-period "assets above minimum" value
496 "aXtraNestFac": 1, # Exponential nesting factor for aXtraGrid
497 "aXtraCount": 200, # Number of points in the grid of "assets above minimum"
498 "aXtraExtra": None, # Additional other values to add in grid (optional)
499}
501# Default parameters to make RiskyDstn with make_lognormal_RiskyDstn (and uniform ShareGrid)
502WealthPortfolioConsumerType_RiskyDstn_default = {
503 "RiskyAvg": 1.08, # Mean return factor of risky asset
504 "RiskyStd": 0.18362634887, # Stdev of log returns on risky asset
505 "RiskyCount": 5, # Number of integration nodes to use in approximation of risky returns
506}
508WealthPortfolioConsumerType_ShareGrid_default = {
509 "ShareCount": 25 # Number of discrete points in the risky share approximation
510}
512# Default parameters to make ChiFunc with make_ChiFromOmega_function
513WealthPortfolioConsumerType_ChiFunc_default = {
514 "ChiFromOmega_N": 501, # Number of gridpoints in chi-from-omega function
515 "ChiFromOmega_bound": 15, # Highest gridpoint to use for it
516}
518# Make a dictionary with parameters for the default constructor for kNrmInitDstn
519WealthPortfolioConsumerType_kNrmInitDstn_default = {
520 "kLogInitMean": -12.0, # Mean of log initial capital
521 "kLogInitStd": 0.0, # Stdev of log initial capital
522 "kNrmInitCount": 15, # Number of points in initial capital discretization
523}
525# Make a dictionary with parameters for the default constructor for pLvlInitDstn
526WealthPortfolioConsumerType_pLvlInitDstn_default = {
527 "pLogInitMean": 0.0, # Mean of log permanent income
528 "pLogInitStd": 0.0, # Stdev of log permanent income
529 "pLvlInitCount": 15, # Number of points in initial capital discretization
530}
532# Make a dictionary to specify a risky asset consumer type
533WealthPortfolioConsumerType_solving_default = {
534 # BASIC HARK PARAMETERS REQUIRED TO SOLVE THE MODEL
535 "cycles": 1, # Finite, non-cyclic model
536 "T_cycle": 1, # Number of periods in the cycle for this agent type
537 "constructors": WealthPortfolioConsumerType_constructors_default, # See dictionary above
538 # PRIMITIVE RAW PARAMETERS REQUIRED TO SOLVE THE MODEL
539 "CRRA": 5.0, # Coefficient of relative risk aversion
540 "Rfree": [1.03], # Return factor on risk free asset
541 "DiscFac": 0.90, # Intertemporal discount factor
542 "LivPrb": [0.98], # Survival probability after each period
543 "PermGroFac": [1.01], # Permanent income growth factor
544 "BoroCnstArt": 0.0, # Artificial borrowing constraint
545 "WealthShare": 0.5, # Share of wealth in Cobb-Douglas aggregator in utility function
546 "WealthShift": 0.1, # Shifter for wealth in utility function
547 "DiscreteShareBool": False, # Whether risky asset share is restricted to discrete values
548 "PortfolioBool": True, # Whether there is portfolio choice
549 "PortfolioBisect": False, # This is a mystery parameter
550 "IndepDstnBool": True, # Whether income and return shocks are independent
551 "vFuncBool": False, # Whether to calculate the value function during solution
552 "CubicBool": False, # Whether to use cubic spline interpolation when True
553 # (Uses linear spline interpolation for cFunc when False)
554 "AdjustPrb": 1.0, # Probability that the agent can update their risky portfolio share each period
555 "RiskyShareFixed": None, # This just needs to exist because of inheritance, does nothing
556 "sim_common_Rrisky": True, # Whether risky returns have a shared/common value across agents
557}
558WealthPortfolioConsumerType_simulation_default = {
559 # PARAMETERS REQUIRED TO SIMULATE THE MODEL
560 "AgentCount": 10000, # Number of agents of this type
561 "T_age": None, # Age after which simulated agents are automatically killed
562 "aNrmInitMean": 0.0, # Mean of log initial assets
563 "aNrmInitStd": 1.0, # Standard deviation of log initial assets
564 "pLvlInitMean": 0.0, # Mean of log initial permanent income
565 "pLvlInitStd": 0.0, # Standard deviation of log initial permanent income
566 "PermGroFacAgg": 1.0, # Aggregate permanent income growth factor
567 # (The portion of PermGroFac attributable to aggregate productivity growth)
568 "NewbornTransShk": False, # Whether Newborns have transitory shock
569 # ADDITIONAL OPTIONAL PARAMETERS
570 "PerfMITShk": False, # Do Perfect Foresight MIT Shock
571 # (Forces Newborns to follow solution path of the agent they replaced if True)
572 "neutral_measure": False, # Whether to use permanent income neutral measure (see Harmenberg 2021)
573}
575# Assemble the default dictionary
576WealthPortfolioConsumerType_default = {}
577WealthPortfolioConsumerType_default.update(WealthPortfolioConsumerType_solving_default)
578WealthPortfolioConsumerType_default.update(
579 WealthPortfolioConsumerType_simulation_default
580)
581WealthPortfolioConsumerType_default.update(
582 WealthPortfolioConsumerType_aXtraGrid_default
583)
584WealthPortfolioConsumerType_default.update(
585 WealthPortfolioConsumerType_ShareGrid_default
586)
587WealthPortfolioConsumerType_default.update(
588 WealthPortfolioConsumerType_IncShkDstn_default
589)
590WealthPortfolioConsumerType_default.update(
591 WealthPortfolioConsumerType_RiskyDstn_default
592)
593WealthPortfolioConsumerType_default.update(WealthPortfolioConsumerType_ChiFunc_default)
594WealthPortfolioConsumerType_default.update(
595 WealthPortfolioConsumerType_kNrmInitDstn_default
596)
597WealthPortfolioConsumerType_default.update(
598 WealthPortfolioConsumerType_pLvlInitDstn_default
599)
600init_wealth_portfolio = WealthPortfolioConsumerType_default
602###############################################################################
605class WealthPortfolioConsumerType(PortfolioConsumerType):
606 """
607 TODO: This docstring is missing and needs to be written.
608 """
610 time_inv_ = deepcopy(PortfolioConsumerType.time_inv_)
611 time_inv_ = time_inv_ + [
612 "WealthShare",
613 "WealthShift",
614 "ChiFunc",
615 "RiskyDstn",
616 ]
617 default_ = {
618 "params": init_wealth_portfolio,
619 "solver": solve_one_period_WealthPortfolio,
620 "model": "ConsRiskyAsset.yaml",
621 }
623 def pre_solve(self):
624 self.construct("solution_terminal")
625 self.solution_terminal.ShareFunc = ConstantFunction(1.0)