# IndShockConsumerType Documentation¶

## Consumption-Saving model with Idiosyncratic Income Shocks¶

[1]:

# Initial imports and notebook setup, click arrow to show
from HARK.ConsumptionSaving.ConsIndShockModel import IndShockConsumerType
from HARK.utilities import plot_funcs_der, plot_funcs
import matplotlib.pyplot as plt
import numpy as np
mystr = lambda number : "{:.4f}".format(number)

/home/sb/projects/econ-ark/HARK/HARK/Calibration/Income/IncomeTools.py:449: UserWarning: Sabelhaus and Song (2010) provide variance profiles for ages 27 to 54. Extrapolating variances using the extreme points.
warn(
/home/sb/projects/econ-ark/HARK/HARK/datasets/SCF/WealthIncomeDist/SCFDistTools.py:79: UserWarning: Returning SCF summary statistics for ages (20,25].
warn("Returning SCF summary statistics for ages " + age_bracket + ".")


The module HARK.ConsumptionSaving.ConsIndShockModel concerns consumption-saving models with idiosyncratic shocks to (non-capital) income. All of the models assume CRRA utility with geometric discounting, no bequest motive, and income shocks are fully transitory or fully permanent.

ConsIndShockModel includes: 1. A very basic “perfect foresight” model with no uncertainty. 2. A model with risk over transitory and permanent income shocks. 3. The model described in (2), with an interest rate for debt that differs from the interest rate for savings.


## Statement of idiosyncratic income shocks model¶

Suppose we want to solve a model like the one analyzed in BufferStockTheory, which has all the same features as the perfect foresight consumer, plus idiosyncratic shocks to income each period. Agents with this kind of model are represented by the class IndShockConsumerType.


\begin{eqnarray*} v_t(m_t) &=& \max_{c_t} {~} u(c_t) + \DiscFac (1-\DiePrb_{t+1}) \mathbb{E}_{t} \left[ (\PermGroFac_{t+1}\psi_{t+1})^{1-\CRRA} v_{t+1}(m_{t+1}) \right], \\ a_t &=& m_t - c_t, \\ a_t &\geq& \text{$\underline{a}$}, \\ m_{t+1} &=& \Rfree/(\PermGroFac_{t+1} \psi_{t+1}) a_t + \theta_{t+1}, \\ (\psi_{t+1},\theta_{t+1}) &\sim& F_{t+1}, \\ \mathbb{E}[\psi]=\mathbb{E}[\theta] &=& 1, \\ u(c) &=& \frac{c^{1-\rho}}{1-\rho}. \end{eqnarray*}

## Solution method for IndShockConsumerType¶

With the introduction of (non-trivial) risk, the idiosyncratic income shocks model has no closed form solution and must be solved numerically. The function solveConsIndShock solves the one period problem for the IndShockConsumerType class. To do so, HARK uses the original version of the endogenous grid method (EGM) first described here :cite:6202365/HQ6H9JEI; see also the SolvingMicroDSOPs lecture notes.

Briefly, the transition equation for $$m_{t+1}$$ can be substituted into the problem definition; the second term of the reformulated maximand represents “end of period value of assets” $$\mathfrak{v}_t(a_t)$$ (“Gothic v”):

\begin{eqnarray*} v_t(m_t) &=& \max_{c_t} {~} u(c_t) + \underbrace{\DiscFac (1-\DiePrb_{t+1}) \mathbb{E}_{t} \left[ (\PermGroFac_{t+1}\psi_{t+1})^{1-\CRRA} v_{t+1}(\Rfree/(\PermGroFac_{t+1} \psi_{t+1}) a_t + \theta_{t+1}) \right]}_{\equiv \mathfrak{v}_t(a_t)}. \end{eqnarray*}

The first order condition with respect to $$c_t$$ is thus simply:

\begin{eqnarray*} u^{\prime}(c_t) - \mathfrak{v}'_t(a_t) = 0 \Longrightarrow c_t^{-\CRRA} = \mathfrak{v}'_t(a_t) \Longrightarrow c_t = \mathfrak{v}'_t(a_t)^{-1/\CRRA}, \end{eqnarray*}

and the marginal value of end-of-period assets can be computed as:

\begin{eqnarray*} \mathfrak{v}'_t(a_t) = \DiscFac (1-\DiePrb_{t+1}) \mathbb{E}_{t} \left[ \Rfree (\PermGroFac_{t+1}\psi_{t+1})^{-\CRRA} v'_{t+1}(\Rfree/(\PermGroFac_{t+1} \psi_{t+1}) a_t + \theta_{t+1}) \right]. \end{eqnarray*}

To solve the model, we choose an exogenous grid of $$a_t$$ values that spans the range of values that could plausibly be achieved, compute $$\mathfrak{v}'_t(a_t)$$ at each of these points, calculate the value of consumption $$c_t$$ whose marginal utility is consistent with the marginal value of assets, then find the endogenous $$m_t$$ gridpoint as $$m_t = a_t + c_t$$. The set of $$(m_t,c_t)$$ gridpoints is then interpolated to construct the consumption function.

## Example parameter values to construct an instance of IndShockConsumerType¶

In order to create an instance of IndShockConsumerType, the user must specify parameters that characterize the (age-varying) distribution of income shocks $$F_{t+1}$$, the artificial borrowing constraint $$\underline{a}$$, and the exogenous grid of end-of-period assets-above-minimum for use by EGM, along with all of the parameters for the perfect foresight model. The table below presents the complete list of parameter values required to instantiate an IndShockConsumerType, along with example values.

Parameter Description Code Example value Time-varying?
$$\DiscFac$$ Intertemporal discount factor $$\texttt{DiscFac}$$ $$0.96$$
$$\CRRA$$ Coefficient of relative risk aversion $$\texttt{CRRA}$$ $$2.0$$
$$\Rfree$$ Risk free interest factor $$\texttt{Rfree}$$ $$1.03$$
$$1 - \DiePrb_{t+1}$$ Survival probability $$\texttt{LivPrb}$$ $$[0.98]$$ $$\surd$$
$$\PermGroFac_{t+1}$$ Permanent income growth factor $$\texttt{PermGroFac}$$ $$[1.01]$$ $$\surd$$
$$\sigma_\psi$$ Standard deviation of log permanent income shocks $$\texttt{PermShkStd}$$ $$[0.1]$$ $$\surd$$
$$N_\psi$$ Number of discrete permanent income shocks $$\texttt{PermShkCount }$$ $$7$$
$$\sigma_\theta$$ Standard deviation of log transitory income shocks $$\texttt{TranShkStd}$$ $$[0.2]$$ $$\surd$$
$$N_\theta$$ Number of discrete transitory income shocks $$\texttt{TranShkCount }$$ $$7$$
$$\mho$$ Probability of being unemployed and getting $$\theta=\underline{\t heta}$$ $$\texttt{UnempPrb}$$ $$0.05$$
$$\underline{\theta}$$ Transitory shock when unemployed $$\texttt{IncUnemp}$$ $$0.3$$
$$\mho^{Ret}$$ Probability of being “unemployed” when retired $$\texttt{UnempPrb}$$ $$0.0005$$
$$\underline{\theta}^{Ret}$$ Transitory shock when “unemployed” and retired $$\texttt{IncUnemp}$$ $$0.0$$
$$(none)$$ Period of the lifecycle model when retirement begins $$\texttt{T_retire}$$ $$0$$
$$(none)$$ Minimum value in assets-above-minimum grid $$\texttt{aXtraMin}$$ $$0.001$$
$$(none)$$ Maximum value in assets-above-minimum grid $$\texttt{aXtraMax}$$ $$20.0$$
$$(none)$$ Number of points in base assets-above-minimum grid $$\texttt{aXtraCount}$$ $$48$$
$$(none)$$ Exponential nesting factor for base assets-above-minimum grid $$\texttt{aXtraNestFac }$$ $$3$$
$$(none)$$ Additional values to add to assets-above-minimum grid $$\texttt{aXtraExtra}$$ $$None$$
$$\underline{a}$$ Artificial borrowing constraint (normalized) :math:texttt{BoroCnstArt}  $$0.0$$
$$(none)$$ Indicator for whether $$\texttt{vFunc}$$ should be computed $$\texttt{vFuncBool}$$ $$True$$
$$(none)$$ Indicator for whether $$\texttt{cFunc}$$ should use cubic splines $$\texttt{CubicBool}$$ $$False$$
$$T$$ Number of periods in this type’s “cycle” $$\texttt{T_cycle}$$ $$1$$
(none) Number of times the “cycle” occurs $$\texttt{cycles}$$ $$0$$
[2]:

IdiosyncDict={
# Parameters shared with the perfect foresight model
"CRRA": 2.0,                           # Coefficient of relative risk aversion
"Rfree": 1.03,                         # Interest factor on assets
"DiscFac": 0.96,                       # Intertemporal discount factor
"LivPrb" : [0.98],                     # Survival probability
"PermGroFac" :[1.01],                  # Permanent income growth factor

# Parameters that specify the income distribution over the lifecycle
"PermShkStd" : [0.1],                  # Standard deviation of log permanent shocks to income
"PermShkCount" : 7,                    # Number of points in discrete approximation to permanent income shocks
"TranShkStd" : [0.2],                  # Standard deviation of log transitory shocks to income
"TranShkCount" : 7,                    # Number of points in discrete approximation to transitory income shocks
"UnempPrb" : 0.05,                     # Probability of unemployment while working
"IncUnemp" : 0.3,                      # Unemployment benefits replacement rate
"UnempPrbRet" : 0.0005,                # Probability of "unemployment" while retired
"IncUnempRet" : 0.0,                   # "Unemployment" benefits when retired
"T_retire" : 0,                        # Period of retirement (0 --> no retirement)
"tax_rate" : 0.0,                      # Flat income tax rate (legacy parameter, will be removed in future)

# Parameters for constructing the "assets above minimum" grid
"aXtraMin" : 0.001,                    # Minimum end-of-period "assets above minimum" value
"aXtraMax" : 20,                       # Maximum end-of-period "assets above minimum" value
"aXtraCount" : 48,                     # Number of points in the base grid of "assets above minimum"
"aXtraNestFac" : 3,                    # Exponential nesting factor when constructing "assets above minimum" grid

# A few other paramaters
"BoroCnstArt" : 0.0,                   # Artificial borrowing constraint; imposed minimum level of end-of period assets
"vFuncBool" : True,                    # Whether to calculate the value function during solution
"CubicBool" : False,                   # Preference shocks currently only compatible with linear cFunc
"T_cycle" : 1,                         # Number of periods in the cycle for this agent type

# Parameters only used in simulation
"AgentCount" : 10000,                  # Number of agents of this type
"T_sim" : 120,                         # Number of periods to simulate
"PermGroFacAgg" : 1.0,                 # Aggregate permanent income growth factor
"T_age" : None,                        # Age after which simulated agents are automatically killed
}


The distribution of permanent income shocks is specified as mean one lognormal, with an age-varying (underlying) standard deviation. The distribution of transitory income shocks is also mean one lognormal, but with an additional point mass representing unemployment; the transitory shocks are adjusted so that the distribution is still mean one. The continuous distributions are discretized with an equiprobable distribution.

Optionally, the user can specify the period when the individual retires and escapes essentially all income risk as T_retire; this can be turned off by setting the parameter to $$0$$. In retirement, all permanent income shocks are turned off, and the only transitory shock is an “unemployment” shock, likely with small probability; this prevents the retired problem from degenerating into a perfect foresight model.

The grid of assets above minimum $$\texttt{aXtraGrid}$$ is specified by its minimum and maximum level, the number of gridpoints, and the extent of exponential nesting. The greater the (integer) value of $$\texttt{aXtraNestFac}$$, the more dense the gridpoints will be at the bottom of the grid (and more sparse near the top); setting $$\texttt{aXtraNestFac}$$ to $$0$$ will generate an evenly spaced grid of $$a_t$$.

The artificial borrowing constraint $$\texttt{BoroCnstArt}$$ can be set to None to turn it off.

It is not necessary to compute the value function in this model, and it is not computationally free to do so. You can choose whether the value function should be calculated and returned as part of the solution of the model with $$\texttt{vFuncBool}$$. The consumption function will be constructed as a piecewise linear interpolation when $$\texttt{CubicBool}$$ is False, and will be a piecewise cubic spline interpolator if True.

## Solving and examining the solution of the idiosyncratic income shocks model¶

The cell below creates an infinite horizon instance of IndShockConsumerType and solves its model by calling its solve method.

[3]:

IndShockExample = IndShockConsumerType(**IdiosyncDict)
IndShockExample.cycles = 0 # Make this type have an infinite horizon
IndShockExample.solve()

GPFPF            = 0.984539
GPFInd           = 0.993777
GPFAgg           = 0.964848
Thorn = APF      = 0.994384
uInvEpShkuInv    = 0.990704
FVAF             = 0.932054
WRPF             = 0.213705
DiscFacGPFIndMax = 0.972061
DiscFacGPFAggMax = 1.010600


After solving the model, we can examine an element of this type’s $$\texttt{solution}$$:

[4]:

print(vars(IndShockExample.solution[0]))

{'cFunc': <HARK.interpolation.LowerEnvelope object at 0x7f248f60bd90>, 'vFunc': <HARK.interpolation.ValueFuncCRRA object at 0x7f248f60b8b0>, 'vPfunc': <HARK.interpolation.MargValueFuncCRRA object at 0x7f248f60b9a0>, 'vPPfunc': <HARK.utilities.NullFunc object at 0x7f248f60b160>, 'mNrmMin': 0.0, 'hNrm': 44.991920196607595, 'MPCmin': 0.044536273404377116, 'MPCmax': 1.0, 'mNrmSS': 1.5488165705077026}


The single-period solution to an idiosyncratic shocks consumer’s problem has all of the same attributes as in the perfect foresight model, with a couple additions. The solution can include the marginal marginal value of market resources function $$\texttt{vPPfunc}$$, but this is only constructed if $$\texttt{CubicBool}$$ is True, so that the MPC can be accurately computed; when it is False, then $$\texttt{vPPfunc}$$ merely returns NaN everywhere.

The solveConsIndShock function calculates steady state market resources and stores it in the attribute $$\texttt{mNrmSS}$$. This represents the steady state level of $$m_t$$ if this period were to occur indefinitely, but with income shocks turned off. This is relevant in a “one period infinite horizon” model like we’ve specified here, but is less useful in a lifecycle model.

Let’s take a look at the consumption function by plotting it, along with its derivative (the MPC):

[5]:

print('Consumption function for an idiosyncratic shocks consumer type:')
plot_funcs(IndShockExample.solution[0].cFunc,IndShockExample.solution[0].mNrmMin,5)
print('Marginal propensity to consume for an idiosyncratic shocks consumer type:')
plot_funcs_der(IndShockExample.solution[0].cFunc,IndShockExample.solution[0].mNrmMin,5)

Consumption function for an idiosyncratic shocks consumer type:

Marginal propensity to consume for an idiosyncratic shocks consumer type:


The lower part of the consumption function is linear with a slope of 1, representing the constrained part of the consumption function where the consumer would like to consume more by borrowing– his marginal utility of consumption exceeds the marginal value of assets– but he is prevented from doing so by the artificial borrowing constraint.

The MPC is a step function, as the $$\texttt{cFunc}$$ itself is a piecewise linear function; note the large jump in the MPC where the borrowing constraint begins to bind.

If you want to look at the interpolation nodes for the consumption function, these can be found by “digging into” attributes of $$\texttt{cFunc}$$:

[6]:

print('mNrmGrid for unconstrained cFunc is ',IndShockExample.solution[0].cFunc.functions[0].x_list)
print('cNrmGrid for unconstrained cFunc is ',IndShockExample.solution[0].cFunc.functions[0].y_list)
print('mNrmGrid for borrowing constrained cFunc is ',IndShockExample.solution[0].cFunc.functions[1].x_list)
print('cNrmGrid for borrowing constrained cFunc is ',IndShockExample.solution[0].cFunc.functions[1].y_list)

mNrmGrid for unconstrained cFunc is  [-0.25017509 -0.23682357 -0.04309334  0.08570877  0.19249704  0.28773035
0.37527975  0.4572262   0.53458817  0.60902763  0.68157147  0.75266421
0.82159155  0.89091324  0.96108615  1.03297006  1.10702535  1.18386894
1.26405846  1.34797683  1.43498517  1.52575439  1.62247992  1.7264799
1.83886328  1.96091089  2.09399047  2.23965509  2.39978161  2.57666105
2.77296758  2.99185309  3.23706867  3.51312387  3.82546834  4.18073875
4.58704087  5.05438059  5.59517832  6.2249668   6.96332613  7.83514604
8.87231638 10.11613869 11.62057399 13.45688075 15.72024305 18.53939481
22.09098021]
cNrmGrid for unconstrained cFunc is  [0.         0.01235151 0.18691037 0.29541926 0.38070319 0.45312275
0.51644051 0.57261755 0.62253956 0.66772112 0.70902525 0.74671381
0.77986847 0.81082056 0.8397706  0.86728992 0.89351353 0.91869035
0.94296058 0.9662323  0.98732483 1.00628889 1.02460772 1.04277873
1.06096172 1.07933575 1.0979846  1.11695897 1.13637025 1.15642563
1.17732806 1.19928447 1.22251841 1.24729118 1.27390725 1.30273462
1.33419368 1.3688058  1.40720505 1.45016983 1.49866721 1.55391366
1.61742883 1.69119491 1.77777206 1.88053049 2.00400672 2.15448643
2.3411553 ]
mNrmGrid for borrowing constrained cFunc is  [0. 1.]
cNrmGrid for borrowing constrained cFunc is  [0. 1.]


The consumption function in this model is an instance of LowerEnvelope1D, a class that takes an arbitrary number of 1D interpolants as arguments to its initialization method. When called, a LowerEnvelope1D evaluates each of its component functions and returns the lowest value. Here, the two component functions are the unconstrained consumption function– how the agent would consume if the artificial borrowing constraint did not exist for just this period– and the borrowing constrained consumption function– how much he would consume if the artificial borrowing constraint is binding.

The actual consumption function is the lower of these two functions, pointwise. We can see this by plotting the component functions on the same figure:

[7]:

plot_funcs(IndShockExample.solution[0].cFunc.functions,-0.25,5.)


## Simulating the idiosyncratic income shocks model¶

In order to generate simulated data, an instance of IndShockConsumerType needs to know how many agents there are that share these particular parameters (and are thus ex ante homogeneous), the distribution of states for newly “born” agents, and how many periods to simulated. These simulation parameters are described in the table below, along with example values.

Description Code Example value
Number of consumers of this type $$\texttt{AgentCount}$$ $$10000$$
Number of periods to simulate $$\texttt{T_sim}$$ $$120$$
Mean of initial log (normalized) assets $$\texttt{aNrmInitMean}$$ $$-6.0$$
Stdev of initial log (normalized) assets $$\texttt{aNrmInitStd}$$ $$1.0$$
Mean of initial log permanent income $$\texttt{pLvlInitMean}$$ $$0.0$$
Stdev of initial log permanent income $$\texttt{pLvlInitStd}$$ $$0.0$$
Aggregrate productivity growth factor $$\texttt{PermGroFacAgg}$$ $$1.0$$
Age after which consumers are automatically killed $$\texttt{T_age}$$ $$None$$

Here, we will simulate 10,000 consumers for 120 periods. All newly born agents will start with permanent income of exactly $$P_t = 1.0 = \exp(\texttt{pLvlInitMean})$$, as $$\texttt{pLvlInitStd}$$ has been set to zero; they will have essentially zero assets at birth, as $$\texttt{aNrmInitMean}$$ is $$-6.0$$; assets will be less than $$1\%$$ of permanent income at birth.

These example parameter values were already passed as part of the parameter dictionary that we used to create IndShockExample, so it is ready to simulate. We need to set the track_vars attribute to indicate the variables for which we want to record a history.

[8]:

IndShockExample.track_vars = ['aNrm','mNrm','cNrm','pLvl']
IndShockExample.initialize_sim()
IndShockExample.simulate()

[8]:

{'aNrm': array([[0.15583477, 0.14673362, 0.1473055 , ..., 0.14868233, 0.14629481,
0.14586154],
[0.084073  , 0.5389655 , 0.23926021, ..., 0.31781026, 0.14906593,
0.20150695],
[0.21541963, 0.49649916, 0.21661362, ..., 0.3254421 , 0.07077974,
0.13631937],
...,
[1.29191016, 0.28844216, 0.11757566, ..., 0.80364401, 0.71704952,
0.95267769],
[1.14794272, 0.32446533, 0.22745331, ..., 0.80524313, 0.72239159,
0.2309337 ],
[1.23687247, 0.31514134, 0.60617177, ..., 0.72715137, 0.88126747,
0.14584513]]),
'mNrm': array([[1.01701761, 1.00227103, 1.00319764, ..., 1.00542852, 1.00156002,
1.00085799],
[0.89768887, 1.54981034, 1.14532072, ..., 1.25934394, 1.00605006,
1.08843884],
[1.10986283, 1.49672253, 1.11163864, ..., 1.27006968, 0.87408772,
0.98539683],
...,
[2.43192497, 1.21722942, 0.9547198 , ..., 1.86916805, 1.7662653 ,
2.04360107],
[2.26838438, 1.26871809, 1.12776042, ..., 1.87105059, 1.77263853,
1.13293678],
[2.36958175, 1.25551665, 1.63253661, ..., 1.77831707, 1.9605487 ,
1.00083141]]),
'cNrm': array([[0.86118284, 0.85553741, 0.85589214, ..., 0.85674619, 0.85526521,
0.85499645],
[0.81361587, 1.01084484, 0.90606052, ..., 0.94153368, 0.85698413,
0.88693189],
[0.89444319, 1.00022338, 0.89502501, ..., 0.94462757, 0.80330798,
0.84907745],
...,
[1.14001481, 0.92878726, 0.83714414, ..., 1.06552405, 1.04921579,
1.09092338],
[1.12044167, 0.94425276, 0.90030711, ..., 1.06580746, 1.05024694,
0.90200308],
[1.13270928, 0.94037531, 1.02636484, ..., 1.05116569, 1.07928123,
0.85498627]]),
'pLvl': array([[1.08875607, 0.96867555, 1.08875607, ..., 0.92780942, 1.17807023,
0.96867555],
[1.13528692, 0.97353506, 1.28263111, ..., 0.86083031, 1.04273763,
1.01007445],
[1.0533299 , 0.97841894, 1.28906561, ..., 0.8651488 , 1.22841816,
0.86758775],
...,
[2.96289199, 1.19335046, 1.31158638, ..., 1.4212364 , 1.13518463,
0.54678539],
[2.97775577, 1.40585064, 1.42799763, ..., 1.37671695, 1.23593915,
0.64415158],
[2.99269412, 1.20753356, 1.43516139, ..., 1.49890893, 1.06159073,
1.17807023]])}


We can now look at the simulated data in aggregate or at the individual consumer level. Like in the perfect foresight model, we can plot average (normalized) market resources over time, as well as average consumption:

[9]:

plt.plot(np.mean(IndShockExample.history['mNrm'],axis=1))
plt.xlabel('Time')
plt.ylabel('Mean market resources')
plt.show()

plt.plot(np.mean(IndShockExample.history['cNrm'],axis=1))
plt.xlabel('Time')
plt.ylabel('Mean consumption')
plt.show()


We could also plot individual consumption paths for some of the consumers– say, the first five:

[10]:

plt.plot(IndShockExample.history['cNrm'][:,0:5])
plt.xlabel('Time')
plt.ylabel('Individual consumption paths')
plt.show()


## Other example specifications of idiosyncratic income shocks consumers¶

$$\texttt{IndShockConsumerType}$$– and $$\texttt{HARK}$$ in general– can also represent models that are not infinite horizon.

### Lifecycle example¶

Suppose we wanted to represent consumers with a lifecycle– parameter values that differ by age, with a finite end point beyond which the individual cannot surive. This can be done very easily by simply specifying the time-varying attributes $$\texttt{PermGroFac}$$, $$\texttt{LivPrb}$$, $$\texttt{PermShkStd}$$, and $$\texttt{TranShkStd}$$ as Python lists specifying the sequence of periods these agents will experience, from beginning to end.

In the cell below, we define a parameter dictionary for a rather short ten period lifecycle, with arbitrarily chosen parameters. For a more realistically calibrated (and much longer) lifecycle model, see the SolvingMicroDSOPs REMARK.

[11]:

LifecycleDict={ # Click arrow to expand this fairly large parameter dictionary
# Parameters shared with the perfect foresight model
"CRRA": 2.0,                           # Coefficient of relative risk aversion
"Rfree": 1.03,                         # Interest factor on assets
"DiscFac": 0.96,                       # Intertemporal discount factor
"LivPrb" : [0.99,0.9,0.8,0.7,0.6,0.5,0.4,0.3,0.2,0.1],
"PermGroFac" : [1.01,1.01,1.01,1.02,1.02,1.02,0.7,1.0,1.0,1.0],

# Parameters that specify the income distribution over the lifecycle
"PermShkStd" : [0.1,0.2,0.1,0.2,0.1,0.2,0.1,0,0,0],
"PermShkCount" : 7,                    # Number of points in discrete approximation to permanent income shocks
"TranShkStd" : [0.3,0.2,0.1,0.3,0.2,0.1,0.3,0,0,0],
"TranShkCount" : 7,                    # Number of points in discrete approximation to transitory income shocks
"UnempPrb" : 0.05,                     # Probability of unemployment while working
"IncUnemp" : 0.3,                      # Unemployment benefits replacement rate
"UnempPrbRet" : 0.0005,                # Probability of "unemployment" while retired
"IncUnempRet" : 0.0,                   # "Unemployment" benefits when retired
"T_retire" : 7,                        # Period of retirement (0 --> no retirement)
"tax_rate" : 0.0,                      # Flat income tax rate (legacy parameter, will be removed in future)

# Parameters for constructing the "assets above minimum" grid
"aXtraMin" : 0.001,                    # Minimum end-of-period "assets above minimum" value
"aXtraMax" : 20,                       # Maximum end-of-period "assets above minimum" value
"aXtraCount" : 48,                     # Number of points in the base grid of "assets above minimum"
"aXtraNestFac" : 3,                    # Exponential nesting factor when constructing "assets above minimum" grid

# A few other paramaters
"BoroCnstArt" : 0.0,                   # Artificial borrowing constraint; imposed minimum level of end-of period assets
"vFuncBool" : True,                    # Whether to calculate the value function during solution
"CubicBool" : False,                   # Preference shocks currently only compatible with linear cFunc
"T_cycle" : 10,                        # Number of periods in the cycle for this agent type

# Parameters only used in simulation
"AgentCount" : 10000,                  # Number of agents of this type
"T_sim" : 120,                         # Number of periods to simulate
"PermGroFacAgg" : 1.0,                 # Aggregate permanent income growth factor
"T_age" : 11,                          # Age after which simulated agents are automatically killed
}


In this case, we have specified a ten period model in which retirement happens in period $$t=7$$. Agents in this model are more likely to die as they age, and their permanent income drops by 30% at retirement. Let’s make and solve this lifecycle example, then look at the $$\texttt{solution}$$ attribute.

[12]:

LifecycleExample = IndShockConsumerType(**LifecycleDict)
LifecycleExample.cycles = 1 # Make this consumer live a sequence of periods -- a lifetime -- exactly once
LifecycleExample.solve()
print('First element of solution is',LifecycleExample.solution[0])
print('Solution has', len(LifecycleExample.solution),'elements.')

First element of solution is <HARK.ConsumptionSaving.ConsIndShockModel.ConsumerSolution object at 0x7f248cea3400>
Solution has 11 elements.


This was supposed to be a ten period lifecycle model– why does our consumer type have eleven elements in its $$\texttt{solution}$$? It would be more precise to say that this specification has ten non-terminal periods. The solution to the 11th and final period in the model would be the same for every set of parameters: consume $$c_t = m_t$$, because there is no future. In a lifecycle model, the terminal period is assumed to exist; the $$\texttt{LivPrb}$$ parameter does not need to end with a $$0.0$$ in order to guarantee that survivors die.

We can quickly plot the consumption functions in each period of the model:

[13]:

print('Consumption functions across the lifecycle:')
mMin = np.min([LifecycleExample.solution[t].mNrmMin for t in range(LifecycleExample.T_cycle)])
LifecycleExample.unpack('cFunc') # This makes all of the cFuncs accessible in the attribute cFunc
plot_funcs(LifecycleExample.cFunc,mMin,5)

Consumption functions across the lifecycle:


### “Cyclical” example¶

We can also model consumers who face an infinite horizon, but who do not face the same problem in every period. Consider someone who works as a ski instructor: they make most of their income for the year in the winter, and make very little money in the other three seasons.

We can represent this type of individual as a four period, infinite horizon model in which expected “permanent” income growth varies greatly across seasons.

[14]:

CyclicalDict = { # Click the arrow to expand this parameter dictionary
# Parameters shared with the perfect foresight model
"CRRA": 2.0,                           # Coefficient of relative risk aversion
"Rfree": 1.03,                         # Interest factor on assets
"DiscFac": 0.96,                       # Intertemporal discount factor
"LivPrb" : 4*[0.98],                   # Survival probability
"PermGroFac" : [1.082251, 2.8, 0.3, 1.1],

# Parameters that specify the income distribution over the lifecycle
"PermShkStd" : [0.1,0.1,0.1,0.1],
"PermShkCount" : 7,                    # Number of points in discrete approximation to permanent income shocks
"TranShkStd" : [0.2,0.2,0.2,0.2],
"TranShkCount" : 7,                    # Number of points in discrete approximation to transitory income shocks
"UnempPrb" : 0.05,                     # Probability of unemployment while working
"IncUnemp" : 0.3,                      # Unemployment benefits replacement rate
"UnempPrbRet" : 0.0005,                # Probability of "unemployment" while retired
"IncUnempRet" : 0.0,                   # "Unemployment" benefits when retired
"T_retire" : 0,                        # Period of retirement (0 --> no retirement)
"tax_rate" : 0.0,                      # Flat income tax rate (legacy parameter, will be removed in future)

# Parameters for constructing the "assets above minimum" grid
"aXtraMin" : 0.001,                    # Minimum end-of-period "assets above minimum" value
"aXtraMax" : 20,                       # Maximum end-of-period "assets above minimum" value
"aXtraCount" : 48,                     # Number of points in the base grid of "assets above minimum"
"aXtraNestFac" : 3,                    # Exponential nesting factor when constructing "assets above minimum" grid

# A few other paramaters
"BoroCnstArt" : 0.0,                   # Artificial borrowing constraint; imposed minimum level of end-of period assets
"vFuncBool" : True,                    # Whether to calculate the value function during solution
"CubicBool" : False,                   # Preference shocks currently only compatible with linear cFunc
"T_cycle" : 4,                         # Number of periods in the cycle for this agent type

# Parameters only used in simulation
"AgentCount" : 10000,                  # Number of agents of this type
"T_sim" : 120,                         # Number of periods to simulate
"PermGroFacAgg" : 1.0,                 # Aggregate permanent income growth factor
"T_age" : None,                        # Age after which simulated agents are automatically killed
}


This consumer type’s parameter dictionary is nearly identical to the original infinite horizon type we made, except that each of the time-varying parameters now have four values, rather than just one. Most of these have the same value in each period except for $$\texttt{PermGroFac}$$, which varies greatly over the four seasons. Note that the product of the four “permanent” income growth factors is almost exactly 1.0– this type’s income does not grow on average in the long run!

Let’s make and solve this consumer type, then plot his quarterly consumption functions:

[15]:

CyclicalExample = IndShockConsumerType(**CyclicalDict)
CyclicalExample.cycles = 0 # Make this consumer type have an infinite horizon
CyclicalExample.solve()

CyclicalExample.unpack('cFunc')
print('Quarterly consumption functions:')
mMin = min([X.mNrmMin for X in CyclicalExample.solution])
plot_funcs(CyclicalExample.cFunc,mMin,5)

Quarterly consumption functions:


The very low green consumption function corresponds to the quarter in which the ski instructors make most of their income. They know that they are about to experience a 70% drop in “permanent” income, so they do not consume much relative to their income this quarter. In the other three quarters, normalized consumption is much higher, as current “permanent” income is low relative to future expectations. In level, the consumption chosen in each quarter is much more similar

[ ]: