{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Permanent versus Persistent Income Shocks\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "code_folding": [ 0 ] }, "outputs": [], "source": [ "# Initial imports and notebook setup\n", "%matplotlib inline\n", "import matplotlib.pyplot as plt\n", "\n", "import sys\n", "import os\n", "from copy import copy\n", "\n", "\n", "from HARK.ConsumptionSaving.ConsGenIncProcessModel import *\n", "import HARK.ConsumptionSaving.ConsumerParameters as Params\n", "\n", "from HARK.utilities import plotFuncs" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Classes to solve consumption-saving models with idiosyncratic shocks to income in which shocks are not necessarily fully transitory or fully permanent. $\\texttt{ConsGenIncProcessModel}$ extends $\\texttt{ConsIndShockModel}$ by explicitly tracking persistent income $p_t$ as a state variable.\n", "\n", "This model currently solves two types of model:\n", "1. A model with explicit permanent income shock.\n", "2. A model allowing (log) persistent income to follow an AR1 process.\n", "\n", "\n", "## GenIncProcess model\n", "Unlike in $\\texttt{ConsIndShockModel}$, consumers do not necessarily have the same predicted level of persistent income next period as this period (after controlling for growth). Instead, this model allows them to have a generic function $G$ that translates current persistent income into expected next period persistent income (subject to shocks). \n", "\n", "\n", "The agent's problem can be written in Bellman form as:\n", "\n", "\\begin{eqnarray*}\n", "v_t(M_t,p_t) &=& \\max_{c_t} U(c_t) + \\beta (1-\\mathsf{D}_{t+1}) \\mathbb{E} [v_{t+1}(M_{t+1}, p_{t+1}) ], \\\\\n", "a_t &=& M_t - c_t, \\\\\n", "a_t &\\geq& \\underline{a}, \\\\\n", "M_{t+1} &=& R a_t + \\theta_{t+1}, \\\\\n", "p_{t+1} &=& G_{t+1}(p_t)\\psi_{t+1}, \\\\\n", "\\psi_t \\sim F_{\\psi t} &\\qquad& \\theta_t \\sim F_{\\theta t}, \\mathbb{E} [F_{\\psi t}] = 1, \\\\\n", "U(c) &=& \\frac{c^{1-\\rho}}{1-\\rho}.\n", "\\end{eqnarray*}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The one period problem for this model is solved by the function $\\texttt{solveConsGenIncProcess}$, which creates an instance of the class $\\texttt{ConsGenIncProcessSolver}$. The class $\\texttt{GenIncProcessConsumerType}$ extends $\\texttt{IndShockConsumerType}$ to represents agents in this model. To construct an instance of this class, several parameters must be passed to the constructor as shown in the table below (parameters can be either \"primitive\" or \"constructed\" if they have already built-in capabilities from previous models).\n", "\n", "### Example parameter values to solve GenIncProcess model\n", "\n", "| Param | Description | Code | Value | Constructed |\n", "| :---: | --- | --- | --- | :---: |\n", "| $\\beta$ |Intertemporal discount factor | $\\texttt{DiscFac}$ | 0.96 | |\n", "| $\\rho $ |Coefficient of relative risk aversion | $\\texttt{CRRA}$ | 2.0 | |\n", "| $R $ | Risk free interest factor | $\\texttt{Rfree}$ | 1.03 | |\n", "| $1 - \\mathsf{D}$ |Survival probability | $\\texttt{LivPrb}$ | [0.98] | |\n", "| $\\underline{a} $ |Artificial borrowing constraint | $\\texttt{BoroCnstArt}$ | 0.0 | | \n", "| $(none) $ |Indicator of whether $\\texttt{vFunc}$ should be computed | $\\texttt{vFuncBool}$ | 'True' | |\n", "| $(none)$ |Indicator of whether $\\texttt{cFunc}$ should use cubic lines | $\\texttt{CubicBool}$ | 'False' | |\n", "|$F $ |A list containing three arrays of floats, representing a discrete
approximation to the income process:
event probabilities, persistent shocks, transitory shocks | $\\texttt{IncomeDstn}$ | - |$\\surd$ |\n", "| $G$ |Expected persistent income next period | $\\texttt{pLvlNextFunc}$ | - | $\\surd$ |\n", "| $ (none) $ |Array of time-varying persistent income levels | $\\texttt{pLvlGrid}$ | - |$\\surd$ |\n", "| $ (none) $ | Array of \"extra\" end-of-period asset values | $\\texttt{aXtraGrid}$ | - |$\\surd$ |\n", "\n", "### Constructed inputs to solve GenIncProcess\n", "The \"constructed\" inputs above are using expected attributes and are drawn on various methods as explained below.\n", "\n", "\n", "* The input $\\texttt{IncomeDstn}$ is created by the method $\\texttt{updateIncomeProcess}$ which inherits from $\\texttt{IndShockConsumerType}$. (*hyperlink to that noteboook*)\n", "\n", "* The input $\\texttt{pLvlNextFunc}$ is created by the method $\\texttt{updatepLvlNextFunc}$ which uses the initial sequence of $\\texttt{pLvlNextFunc}$, the mean and standard deviation of the (log) initial permanent income, $\\texttt{pLvlInitMean}$ and $\\texttt{pLvlInitStd}$. \n", "In this model, the method creates a trivial $\\texttt{pLvlNextFunc}$ attribute with no persistent income dynamics. But we can overwrite it by subclasses in order to make an AR1 income process for example. \n", "\n", "\n", "* The input $\\texttt{pLvlGrid}$ is created by the method $\\texttt{updatepLvlGrid}$ which updates the grid of persistent income levels for infinite horizon models (cycles=0) and lifecycle models (cycles=1). This method draws on the initial distribution of persistent income, the $\\texttt{pLvlNextFuncs}$, $\\texttt{pLvlInitMean}$, $\\texttt{pLvlInitStd}$ and the attribute $\\texttt{pLvlPctiles}$ (percentiles of the distribution of persistent income). It then uses a simulation approach to generate the $\\texttt{pLvlGrid}$ at each period of the cycle.\n", "\n", "\n", "* The input $\\texttt{aXtraGrid}$ is created by $\\texttt{updateAssetsGrid}$ which updates the agent's end-of-period assets grid by constructing a multi-exponentially spaced grid of aXtra values, based on $\\texttt{aNrmInitMean}$ and $\\texttt{aNrmInitStd}$. \n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1. Consumer with explicit Permanent income\n", "\n", "Let's make an example of our generic model above with an \"explicit permanent income\" consumer who experiences idiosyncratic shocks to permanent and transitory, and faces permanent income growth.\n", "\n", "The agent's problem can be written in Bellman form as:\n", "\n", "\\begin{eqnarray*}\n", "v_t(M_t,p_t) &=& \\max_{c_t} U(c_t) + \\beta (1-\\mathsf{D}_{t+1}) \\mathbb{E} [v_{t+1}(M_{t+1}, p_{t+1}) ], \\\\\n", "a_t &=& M_t - c_t, \\\\\n", "a_t &\\geq& \\underline{a}, \\\\\n", "M_{t+1} &=& R/(\\Gamma_{t+1} \\psi_{t+1}) a_t + \\theta_{t+1}, \\\\\n", "p_{t+1} &=& G_{t+1}(p_t)\\psi_{t+1}, \\\\\n", "\\psi_t \\sim F_{\\psi t} &\\qquad& \\theta_t \\sim F_{\\theta t}, \\mathbb{E} [F_{\\psi t}] = 1, \\\\\n", "U(c) &=& \\frac{c^{1-\\rho}}{1-\\rho}.\n", "\\end{eqnarray*}\n", "\n", "\n", "This agent type is identical to an $\\texttt{IndShockConsumerType}$ but for explicitly tracking $\\texttt{pLvl}$ as a state variable during solution as shown in the mathematical representation of GenIncProcess model. \n", "\n", "To construct $\\texttt{IndShockExplicitPermIncConsumerType}$ as an instance of $\\texttt{GenIncProcessConsumerType}$, we need to pass additional parameters to the constructor as shown in the table below.\n", "\n", "### Additional parameters to solve ExplicitPermInc model\n", "\n", "| Param | Description | Code | Value | Constructed |\n", "| :---: | --- | --- | --- | :---: |\n", "|(none)|percentiles of the distribution of persistent income|$\\texttt{pLvlPctiles}$|||\n", "| $G$ |Expected persistent income next period | $\\texttt{pLvlNextFunc}$ | - | $\\surd$ |\n", "|$\\Gamma $|Permanent income growth factor|$\\texttt{PermGroFac}$|[1.0]| |\n", "\n", "\n", "### Constructed inputs to solve ExplicitPermInc\n", "\n", "* In this \"explicit permanent income\" model, we overwrite the method $\\texttt{updatepLvlNextFunc}$ to create $\\texttt{pLvlNextFunc}$ as a sequence of linear functions, indicating constant expected permanent income growth across permanent income levels. This method uses the attribute $\\texttt{PermGroFac}$, and installs a special retirement function when it exists.\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "code_folding": [ 0 ] }, "outputs": [], "source": [ "# This cell defines a dictionary to make an instance of \"explicit permanent income\" consumer.\n", "GenIncDictionary = { \n", " \"CRRA\": 2.0, # Coefficient of relative risk aversion\n", " \"Rfree\": 1.03, # Interest factor on assets\n", " \"DiscFac\": 0.96, # Intertemporal discount factor\n", " \"LivPrb\" : [0.98], # Survival probability\n", " \"AgentCount\" : 10000, # Number of agents of this type (only matters for simulation)\n", " \"aNrmInitMean\" : 0.0, # Mean of log initial assets (only matters for simulation)\n", " \"aNrmInitStd\" : 1.0, # Standard deviation of log initial assets (only for simulation)\n", " \"pLvlInitMean\" : 0.0, # Mean of log initial permanent income (only matters for simulation)\n", " \"pLvlInitStd\" : 0.0, # Standard deviation of log initial permanent income (only matters for simulation)\n", " \"PermGroFacAgg\" : 1.0, # Aggregate permanent income growth factor (only matters for simulation)\n", " \"T_age\" : None, # Age after which simulated agents are automatically killed\n", " \"T_cycle\" : 1, # Number of periods in the cycle for this agent type\n", "# Parameters for constructing the \"assets above minimum\" grid\n", " \"aXtraMin\" : 0.001, # Minimum end-of-period \"assets above minimum\" value\n", " \"aXtraMax\" : 30, # Maximum end-of-period \"assets above minimum\" value \n", " \"aXtraExtra\" : [0.005,0.01], # Some other value of \"assets above minimum\" to add to the grid\n", " \"aXtraNestFac\" : 3, # Exponential nesting factor when constructing \"assets above minimum\" grid\n", " \"aXtraCount\" : 48, # Number of points in the grid of \"assets above minimum\"\n", "# Parameters describing the income process\n", " \"PermShkCount\" : 7, # Number of points in discrete approximation to permanent income shocks\n", " \"TranShkCount\" : 7, # Number of points in discrete approximation to transitory income shocks\n", " \"PermShkStd\" : [0.1], # Standard deviation of log permanent income shocks\n", " \"TranShkStd\" : [0.1], # Standard deviation of log transitory income shocks\n", " \"UnempPrb\" : 0.05, # Probability of unemployment while working\n", " \"UnempPrbRet\" : 0.005, # Probability of \"unemployment\" while retired\n", " \"IncUnemp\" : 0.3, # Unemployment benefits replacement rate\n", " \"IncUnempRet\" : 0.0, # \"Unemployment\" benefits when retired\n", " \"tax_rate\" : 0.0, # Flat income tax rate\n", " \"T_retire\" : 0, # Period of retirement (0 --> no retirement)\n", " \"BoroCnstArt\" : 0.0, # Artificial borrowing constraint; imposed minimum level of end-of period assets\n", " \"CubicBool\" : False, # Use cubic spline interpolation when True, linear interpolation when False\n", " \"vFuncBool\" : True, # Whether to calculate the value function during solution \n", "# More parameters specific to \"Explicit Permanent income\" shock model\n", " \"cycles\": 0,\n", " \"pLvlPctiles\" : np.concatenate(([0.001, 0.005, 0.01, 0.03], np.linspace(0.05, 0.95, num=19),[0.97, 0.99, 0.995, 0.999])),\n", " \"PermGroFac\" : [1.0], # Permanent income growth factor - long run permanent income growth doesn't work yet \n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's now create an instance of the type of consumer we are interested in and solve this agent's problem with an infinite horizon (cycles=0)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Make and solve an example \"explicit permanent income\" consumer with idiosyncratic shocks\n", "ExplicitExample = IndShockExplicitPermIncConsumerType(**GenIncDictionary)\n", " \n", "print('Here, the lowest percentile is ' + str(GenIncDictionary['pLvlPctiles'][0]*100))\n", "print('and the highest percentile is ' + str(GenIncDictionary['pLvlPctiles'][-1]*100) + '.\\n')\n", " \n", "ExplicitExample.solve()\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the cell below, we generate a plot of the consumption function for explicit permanent income consumer at different income levels." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "code_folding": [] }, "outputs": [], "source": [ "# Plot the consumption function at various permanent income levels.\n", "print('Consumption function by pLvl for explicit permanent income consumer:')\n", "pLvlGrid = ExplicitExample.pLvlGrid[0]\n", "mLvlGrid = np.linspace(0,20,300)\n", "for p in pLvlGrid:\n", " M_temp = mLvlGrid + ExplicitExample.solution[0].mLvlMin(p)\n", " C = ExplicitExample.solution[0].cFunc(M_temp,p*np.ones_like(M_temp))\n", " plt.plot(M_temp,C)\n", "plt.xlim(0.,20.)\n", "plt.xlabel('Market resource level mLvl')\n", "plt.ylabel('Consumption level cLvl')\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "## Permanent income normalized\n", "\n", "An alternative model is to normalized it by dividing all variables by permanent income $p_t$ and solve the model again." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Make and solve an example of normalized model\n", "NormalizedExample = IndShockConsumerType(**GenIncDictionary)\n", "NormalizedExample.solve()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Compare the normalized problem with and without explicit permanent income and plot the consumption functions\n", "print('Normalized consumption function by pLvl for explicit permanent income consumer:')\n", "pLvlGrid = ExplicitExample.pLvlGrid[0]\n", "mNrmGrid = np.linspace(0,20,300)\n", "for p in pLvlGrid:\n", " M_temp = mNrmGrid*p + ExplicitExample.solution[0].mLvlMin(p)\n", " C = ExplicitExample.solution[0].cFunc(M_temp,p*np.ones_like(M_temp))\n", " plt.plot(M_temp/p,C/p)\n", "\n", "plt.xlim(0.,20.)\n", "plt.xlabel('Normalized market resources mNrm')\n", "plt.ylabel('Normalized consumption cNrm')\n", "plt.show()\n", "\n", "print('Consumption function for normalized problem (without explicit permanent income):')\n", "mNrmMin = NormalizedExample.solution[0].mNrmMin\n", "plotFuncs(NormalizedExample.solution[0].cFunc,mNrmMin,mNrmMin+20.)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "The figures above show that the normalized consumption function for the \"explicit permanent income\" consumer is almost identical for every permanent income level (and the same as the normalized problem's $\\texttt{cFunc}$), but is less accurate due to extrapolation outside the bounds of $\\texttt{pLvlGrid}$. \n", "\n", "The \"explicit permanent income\" solution deviates from the solution to the normalized problem because of errors from extrapolating beyond the bounds of the $\\texttt{pLvlGrid}$. The error is largest for $\\texttt{pLvl}$ values near the upper and lower bounds, and propagates toward the center of the distribution.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Plot the value function at various permanent income levels\n", "if ExplicitExample.vFuncBool:\n", " pGrid = np.linspace(0.1,3.0,24)\n", " M = np.linspace(0.001,5,300)\n", " for p in pGrid:\n", " M_temp = M+ExplicitExample.solution[0].mLvlMin(p)\n", " C = ExplicitExample.solution[0].vFunc(M_temp,p*np.ones_like(M_temp))\n", " plt.plot(M_temp,C)\n", " plt.ylim([-200,0])\n", " plt.xlabel('Market resource level mLvl')\n", " plt.ylabel('Value v')\n", " plt.show()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Simulate many periods to get to the stationary distribution\n", "ExplicitExample.T_sim = 500\n", "ExplicitExample.track_vars = ['mLvlNow','cLvlNow','pLvlNow']\n", "ExplicitExample.initializeSim()\n", "ExplicitExample.simulate()\n", "plt.plot(np.mean(ExplicitExample.mLvlNow_hist,axis=1))\n", "plt.xlabel('Simulated time period')\n", "plt.ylabel('Average market resources mLvl')\n", "plt.show()\n" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "## 2. Persistent income shock consumer\n", "\n", "\n", "Class to solve consumption-saving models with idiosyncratic shocks to income in which shocks are persistent and transitory. This model extends $\\texttt{ConsGenIndShockModel}$ by allowing (log) persistent income to follow an AR(1) process.\n", "\n", "The agent's problem can be written in Bellman form as:\n", "\n", "\\begin{eqnarray*}\n", "v_t(M_t,p_t) &=& \\max_{c_t} U(c_t) + \\beta (1-\\mathsf{D}_{t+1}) \\mathbb{E} [v_{t+1}(M_{t+1}, p_{t+1}) ], \\\\\n", "a_t &=& M_t - c_t, \\\\\n", "a_t &\\geq& \\underline{a}, \\\\\n", "M_{t+1} &=& R a_t + \\theta_{t+1}, \\\\\n", "log(p_{t+1}) &=& \\varphi log(p_t)+(1-\\varphi log(\\overline{p}_{t+1} ) +log(\\Gamma_{t+1})+log(\\psi_{t+1}), \\\\\n", "\\\\\n", "\\psi_t \\sim F_{\\psi t} &\\qquad& \\theta_t \\sim F_{\\theta t}, \\mathbb{E} [F_{\\psi t}] = 1 \\\\\n", "\\end{eqnarray*}\n", "\n", "### Additional parameters to solve PersistentShock model\n", "\n", "| Param | Description | Code | Value | Constructed |\n", "| :---: | --- | --- | --- | :---: |\n", "|$\\varphi$|Serial correlation coefficient for permanent income|$\\texttt{PrstIncCorr}$|0.98||\n", "||||||\n", "\n", "### Constructed inputs to solve PersistentShock\n", "\n", "* For this model, we overwrite the method $\\texttt{updatepLvlNextFunc}$ to create the input $\\texttt{pLvlNextFunc}$ as a sequence of AR1-style functions. The method uses now the attributes $\\texttt{PermGroFac}$ and $\\texttt{PrstIncCorr}$. If cycles=0, the product of $\\texttt{PermGroFac}$ across all periods must be 1.0, otherwise this method is invalid.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "code_folding": [ 0 ] }, "outputs": [], "source": [ "# Make a dictionary for the \"persistent idiosyncratic shocks\" model\n", "PrstIncCorr = 0.98 # Serial correlation coefficient for persistent income\n", "\n", "persistent_shocks = copy(GenIncDictionary)\n", "persistent_shocks['PrstIncCorr'] = PrstIncCorr\n" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "The $\\texttt{PersistentShockConsumerType}$ class solves the problem of a consumer facing idiosyncratic shocks to his persistent and transitory income, and for which the (log) persistent income follows an AR1 process rather than random walk." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Make and solve an example of \"persistent idisyncratic shocks\" consumer\n", "PersistentExample = PersistentShockConsumerType(**persistent_shocks)\n", "PersistentExample.solve()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Plot the consumption function at various levels of persistent income pLvl\n", "print('Consumption function by persistent income level pLvl for a consumer with AR1 coefficient of ' + str(PersistentExample.PrstIncCorr) + ':')\n", "pLvlGrid = PersistentExample.pLvlGrid[0]\n", "mLvlGrid = np.linspace(0,20,300)\n", "for p in pLvlGrid:\n", " M_temp = mLvlGrid + PersistentExample.solution[0].mLvlMin(p)\n", " C = PersistentExample.solution[0].cFunc(M_temp,p*np.ones_like(M_temp))\n", " plt.plot(M_temp,C)\n", "plt.xlim(0.,20.)\n", "plt.xlabel('Market resource level mLvl')\n", "plt.ylabel('Consumption level cLvl')\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Plot the value function at various persistent income levels\n", "if PersistentExample.vFuncBool:\n", " pGrid = PersistentExample.pLvlGrid[0]\n", " M = np.linspace(0.001,5,300)\n", " for p in pGrid:\n", " M_temp = M+PersistentExample.solution[0].mLvlMin(p)\n", " C = PersistentExample.solution[0].vFunc(M_temp,p*np.ones_like(M_temp))\n", " plt.plot(M_temp,C)\n", " plt.ylim([-200,0])\n", " plt.xlabel('Market resource level mLvl')\n", " plt.ylabel('Value v')\n", " plt.show()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Simulate some data\n", "PersistentExample.T_sim = 500\n", "PersistentExample.track_vars = ['mLvlNow','cLvlNow','pLvlNow']\n", "PersistentExample.initializeSim()\n", "PersistentExample.simulate()\n", "plt.plot(np.mean(PersistentExample.mLvlNow_hist,axis=1))\n", "plt.xlabel('Simulated time period')\n", "plt.ylabel('Average market resources mLvl')\n", "plt.show()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 2", "language": "python", "name": "python2" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.14" } }, "nbformat": 4, "nbformat_minor": 2 }