def test_infinite_horizon(self): baseEx_inf = IndShockConsumerType(cycles=0, **self.base_params) baseEx_inf.solve() baseEx_inf.unpack("cFunc") m1 = np.linspace( 1, baseEx_inf.solution[0].mNrmSS, 50 ) # m1 defines the plot range on the left of target m value (e.g. m <= target m) c_m1 = baseEx_inf.cFunc[0](m1) self.assertAlmostEqual(c_m1[0], 0.8527887545025995) self.assertAlmostEqual(c_m1[-1], 1.0036279936408656) x1 = np.linspace(0, 25, 1000) cfunc_m = baseEx_inf.cFunc[0](x1) self.assertAlmostEqual(cfunc_m[500], 1.8902146173138235) self.assertAlmostEqual(cfunc_m[700], 2.1591451850267176) m = np.linspace(0.001, 8, 1000) # Use the HARK method derivative to get the derivative of cFunc, and the values are just the MPC MPC = baseEx_inf.cFunc[0].derivative(m) self.assertAlmostEqual(MPC[500], 0.08415000641504392) self.assertAlmostEqual(MPC[700], 0.07173144137912524)
def setUp(self): """ Prepare to compare the models by initializing and solving them """ # Set up and solve infinite type # Define a test dictionary that should have the same solution in the # perfect foresight and idiosyncratic shocks models. test_dictionary = deepcopy(init_idiosyncratic_shocks) test_dictionary["LivPrb"] = [1.0] test_dictionary["DiscFac"] = 0.955 test_dictionary["PermGroFac"] = [1.0] test_dictionary["PermShkStd"] = [0.0] test_dictionary["TranShkStd"] = [0.0] test_dictionary["UnempPrb"] = 0.0 test_dictionary["T_cycle"] = 1 test_dictionary["T_retire"] = 0 test_dictionary["BoroCnstArt"] = None InfiniteType = IndShockConsumerType(**test_dictionary) InfiniteType.cycles = 0 InfiniteType.update_income_process() InfiniteType.solve() InfiniteType.unpack("cFunc") # Make and solve a perfect foresight consumer type with the same parameters PerfectForesightType = PerfForesightConsumerType(**test_dictionary) PerfectForesightType.cycles = 0 PerfectForesightType.solve() PerfectForesightType.unpack("cFunc") self.InfiniteType = InfiniteType self.PerfectForesightType = PerfectForesightType
def makeConvergencePlot(DiscFac, CRRA, Rfree, PermShkStd): # Construct finite horizon agent with baseline parameters baseAgent_Fin = IndShockConsumerType(verbose=0, **base_params) baseAgent_Fin.DiscFac = DiscFac baseAgent_Fin.CRRA = CRRA baseAgent_Fin.Rfree = Rfree baseAgent_Fin.PermShkStd = [PermShkStd] baseAgent_Fin.cycles = 100 baseAgent_Fin.updateIncomeProcess() baseAgent_Fin.solve() baseAgent_Fin.unpack('cFunc') # figure limits mMax = 6 # 11 mMin = 0 cMin = 0 cMax = 4 # 7 mPlotMin = 0 mLocCLabels = 5.6 # 9.6 # Defines horizontal limit of figure mPlotTop = 3.5 # 6.5 # Defines maximum m value where functions are plotted mPts = 1000 # Number of points at which functions are evaluated plt.figure(figsize=(12, 8)) plt.ylim([cMin, cMax]) plt.xlim([mMin, mMax]) mBelwLabels = np.linspace(mPlotMin, mLocCLabels - 0.1, mPts) # Range of m below loc of labels m_FullRange = np.linspace(mPlotMin, mPlotTop, mPts) # Full plot range c_Tm0 = m_FullRange # c_Tm0 defines the last period consumption rule (c=m) c_Tm1 = baseAgent_Fin.cFunc[-2]( mBelwLabels ) # c_Tm1 defines the second-to-last period consumption rule c_Tm5 = baseAgent_Fin.cFunc[-6]( mBelwLabels) # c_Tm5 defines the T-5 period consumption rule c_Tm10 = baseAgent_Fin.cFunc[-11]( mBelwLabels) # c_Tm10 defines the T-10 period consumption rule c_Limt = baseAgent_Fin.cFunc[0]( mBelwLabels ) # c_Limt defines limiting infinite-horizon consumption rule plt.plot(mBelwLabels, c_Limt, label="$c(m)$") plt.plot(mBelwLabels, c_Tm1, label="$c_{T-1}(m)$") plt.plot(mBelwLabels, c_Tm5, label="$c_{T-5}(m)$") plt.plot(mBelwLabels, c_Tm10, label="$c_{T-10}(m)$") plt.plot(m_FullRange, c_Tm0, label="$c_{T}(m) = 45$ degree line") plt.legend(fontsize='x-large') plt.tick_params( labelbottom=False, labelleft=False, left="off", right="off", bottom="off", top="off", ) plt.show() return None
def makeTargetMfig(Rfree, DiscFac, CRRA, PermShkStd, TranShkStd): baseAgent_Inf = IndShockConsumerType(verbose=0, cycles=0, **base_params) baseAgent_Inf.Rfree = Rfree baseAgent_Inf.DiscFac = DiscFac baseAgent_Inf.CRRA = CRRA baseAgent_Inf.PermShkStd = [PermShkStd] baseAgent_Inf.TranShkStd = [TranShkStd] baseAgent_Inf.updateIncomeProcess() baseAgent_Inf.checkConditions() mPlotMin = 0 mPlotMax = 250 baseAgent_Inf.aXtraMax = mPlotMax baseAgent_Inf.solve() baseAgent_Inf.unpack('cFunc') cPlotMin = 0 cPlotMax = baseAgent_Inf.cFunc[0](mPlotMax) if (baseAgent_Inf.GPFInd >= 1): baseAgent_Inf.checkGICInd(verbose=3) mBelwTrg = np.linspace(mPlotMin, mPlotMax, 1000) EPermGroFac = baseAgent_Inf.PermGroFac[0] EmDelEq0 = lambda m: (EPermGroFac / Rfree) + (1.0 - EPermGroFac / Rfree ) * m cBelwTrg_Best = baseAgent_Inf.cFunc[0](mBelwTrg) # "best" = optimal c cBelwTrg_Sstn = EmDelEq0(mBelwTrg) # "sustainable" c mNrmTrg = baseAgent_Inf.solution[0].mNrmSS plt.figure(figsize=(12, 8)) plt.plot(mBelwTrg, cBelwTrg_Best, label="$c(m_{t})$") plt.plot(mBelwTrg, cBelwTrg_Sstn, label="$\mathsf{E}_{t}[\Delta m_{t+1}] = 0$") plt.xlim(mPlotMin, mPlotMax) plt.ylim(cPlotMin, cPlotMax) plt.plot( [mNrmTrg, mNrmTrg], [0, 2.5], color="black", linestyle="--", ) plt.tick_params( # labelbottom=False, # labelleft=False, # left="off", right="off", # bottom="off", top="off", ) plt.text(0, 1.47, r"$c$", fontsize=26) plt.text(3.02, 0, r"$m$", fontsize=26) plt.text(mNrmTrg - 0.05, -0.1, "m̌", fontsize=26) plt.legend(fontsize='x-large') plt.show() return None
def test_GICFails(self): GIC_fail_dictionary = dict(self.base_params) GIC_fail_dictionary["Rfree"] = 1.08 GIC_fail_dictionary["PermGroFac"] = [1.00] GICFailExample = IndShockConsumerType( cycles=0, # cycles=0 makes this an infinite horizon consumer **GIC_fail_dictionary) GICFailExample.solve() GICFailExample.unpack("cFunc") m = np.linspace(0, 5, 1000) c_m = GICFailExample.cFunc[0](m) self.assertAlmostEqual(c_m[500], 0.7772637042393458) self.assertAlmostEqual(c_m[700], 0.8392649061916746) self.assertFalse(GICFailExample.conditions["GIC"])
def test_baseEx(self): baseEx = IndShockConsumerType(**self.base_params) baseEx.cycles = 100 # Make this type have a finite horizon (Set T = 100) baseEx.solve() baseEx.unpack("cFunc") m = np.linspace(0, 9.5, 1000) c_m = baseEx.cFunc[0](m) c_t1 = baseEx.cFunc[-2](m) c_t5 = baseEx.cFunc[-6](m) c_t10 = baseEx.cFunc[-11](m) self.assertAlmostEqual(c_m[500], 1.4008090582203356) self.assertAlmostEqual(c_t1[500], 2.9227437159255216) self.assertAlmostEqual(c_t5[500], 1.7350607327187664) self.assertAlmostEqual(c_t10[500], 1.4991390649979213) self.assertAlmostEqual(c_t10[600], 1.6101476268581576) self.assertAlmostEqual(c_t10[700], 1.7196531041366991)
# c(m) = \lim_{n \uparrow \infty} c_{T-n}(m) \notag # $$ # # %% # Create a buffer stock consumer instance by invoking the IndShockConsumerType class # %% {"jupyter": {"source_hidden": true}, "tags": []} # with the built-in parameter dictionary "base_params" # Construct finite horizon agent with baseline parameters baseAgent_Fin = IndShockConsumerType(**base_params) baseAgent_Fin.cycles = 100 # Set finite horizon (T = 100) baseAgent_Fin.solve(verbose=0) # Solve the model baseAgent_Fin.unpack('cFunc') # Make the consumption function easily accessible # %% # Plot the different consumption rules for the different periods # %% {"jupyter": {"source_hidden": true, "outputs_hidden": true}, "tags": []} mPlotMin = 0 mLocCLabels = 9.6 # Defines horizontal limit of figure mPlotTop = 6.5 # Defines maximum m value where functions are plotted mPts = 1000 # Number of points at which functions are evaluated mBelwLabels = np.linspace(mPlotMin, mLocCLabels-0.1, mPts) # Range of m below loc of labels m_FullRange = np.linspace(mPlotMin, mPlotTop, mPts) # Full plot range # c_Tm0 defines the last period consumption rule (c=m)
def makeGrowthplot(PermGroFac, DiscFac): # cycles=0 tells the solver to find the infinite horizon solution baseAgent_Inf = IndShockConsumerType(verbose=0, cycles=0, **base_params) baseAgent_Inf.PermGroFac = [PermGroFac] baseAgent_Inf.DiscFac = DiscFac baseAgent_Inf.updateIncomeProcess() baseAgent_Inf.checkConditions() baseAgent_Inf.solve() baseAgent_Inf.unpack('cFunc') if (baseAgent_Inf.GPFInd >= 1): baseAgent_Inf.checkGICInd(verbose=3) elif baseAgent_Inf.solution[0].mNrmSS > 3.5: print('Solution exists but is outside the plot range.') else: def EcLev_tp1_Over_p_t(a): ''' Taking end-of-period assets a as input, return ratio of expectation of next period's consumption to this period's permanent income Inputs: a: end-of-period assets Returns: EcLev_tp1_Over_p_{t}: next period's expected c level / current p ''' # Extract parameter values to make code more readable permShkVals = baseAgent_Inf.PermShkDstn[0].X tranShkVals = baseAgent_Inf.TranShkDstn[0].X permShkPrbs = baseAgent_Inf.PermShkDstn[0].pmf tranShkPrbs = baseAgent_Inf.TranShkDstn[0].pmf Rfree = baseAgent_Inf.Rfree EPermGroFac = baseAgent_Inf.PermGroFac[0] PermGrowFac_tp1 = EPermGroFac * permShkVals # Nonstochastic growth times idiosyncratic permShk RNrmFac_tp1 = Rfree / PermGrowFac_tp1 # Growth-normalized interest factor # 'bank balances' b = end-of-last-period assets times normalized return factor b_tp1 = RNrmFac_tp1 * a # expand dims of b_tp1 and use broadcasted sum of a column and a row vector # to obtain a matrix of possible market resources next period # because matrix mult is much much faster than looping to calc E m_tp1_GivenTranAndPermShks = np.expand_dims(b_tp1, axis=1) + tranShkVals # List of possible values of $\mathbf{c}_{t+1}$ (Transposed by .T) cRat_tp1_GivenTranAndPermShks = baseAgent_Inf.cFunc[0]( m_tp1_GivenTranAndPermShks).T cLev_tp1_GivenTranAndPermShks = cRat_tp1_GivenTranAndPermShks * PermGrowFac_tp1 # compute expectation over perm shocks by right multiplying with probs EOverPShks_cLev_tp1_GivenTranShkShks = np.dot( cLev_tp1_GivenTranAndPermShks, permShkPrbs) # finish expectation over trans shocks by right multiplying with probs EcLev_tp1_Over_p_t = np.dot(EOverPShks_cLev_tp1_GivenTranShkShks, tranShkPrbs) # return expected consumption return EcLev_tp1_Over_p_t # Calculate the expected consumption growth factor # mBelwTrg defines the plot range on the left of target m value (e.g. m <= target m) mNrmTrg = baseAgent_Inf.solution[0].mNrmSS mBelwTrg = np.linspace(1, mNrmTrg, 50) c_For_mBelwTrg = baseAgent_Inf.cFunc[0](mBelwTrg) a_For_mBelwTrg = mBelwTrg - c_For_mBelwTrg EcLev_tp1_Over_p_t_For_mBelwTrg = [ EcLev_tp1_Over_p_t(i) for i in a_For_mBelwTrg ] # mAbveTrg defines the plot range on the right of target m value (e.g. m >= target m) mAbveTrg = np.linspace(mNrmTrg, 3.5, 50) # EcGro_For_mAbveTrg: E [consumption growth factor] when m_{t} is below target m EcGro_For_mBelwTrg = np.array( EcLev_tp1_Over_p_t_For_mBelwTrg) / c_For_mBelwTrg c_For_mAbveTrg = baseAgent_Inf.cFunc[0](mAbveTrg) a_For_mAbveTrg = mAbveTrg - c_For_mAbveTrg EcLev_tp1_Over_p_t_For_mAbveTrg = [ EcLev_tp1_Over_p_t(i) for i in a_For_mAbveTrg ] # EcGro_For_mAbveTrg: E [consumption growth factor] when m_{t} is bigger than target m_{t} EcGro_For_mAbveTrg = np.array( EcLev_tp1_Over_p_t_For_mAbveTrg) / c_For_mAbveTrg Rfree = 1.0 EPermGroFac = 1.0 mNrmTrg = baseAgent_Inf.solution[0].mNrmSS # Calculate Absolute Patience Factor Phi = lower bound of consumption growth factor APF = (Rfree * DiscFac)**(1.0 / CRRA) plt.figure(figsize=(12, 8)) # Plot the Absolute Patience Factor line plt.plot([0, 3.5], [APF, APF], label="\u03A6 = [(\u03B2 R)^(1/ \u03C1)]/R") # Plot the Permanent Income Growth Factor line plt.plot([0, 3.5], [EPermGroFac, EPermGroFac], label="\u0393") # Plot the expected consumption growth factor on the left side of target m plt.plot(mBelwTrg, EcGro_For_mBelwTrg, color="black") # Plot the expected consumption growth factor on the right side of target m plt.plot(mAbveTrg, EcGro_For_mAbveTrg, color="black", label="$\mathsf{E}_{t}[c_{t+1}/c_{t}]$") # Plot the target m plt.plot( [mNrmTrg, mNrmTrg], [0, 3.5], color="black", linestyle="--", label="", ) plt.xlim(1, 3.5) plt.ylim(0.94, 1.10) plt.text(2.105, 0.930, "$m_{t}$", fontsize=26, fontweight="bold") plt.text( mNrmTrg - 0.02, 0.930, "m̌", fontsize=26, fontweight="bold", ) plt.tick_params( labelbottom=False, labelleft=False, left="off", right="off", bottom="off", top="off", ) plt.legend(fontsize='x-large') plt.show() return None
def makeBoundsFigure(UnempPrb, PermShkStd, TranShkStd, DiscFac, CRRA): baseAgent_Inf = IndShockConsumerType(verbose=0, cycles=0, **base_params) baseAgent_Inf.UnempPrb = UnempPrb baseAgent_Inf.PermShkStd = [PermShkStd] baseAgent_Inf.TranShkStd = [TranShkStd] baseAgent_Inf.DiscFac = DiscFac baseAgent_Inf.CRRA = CRRA baseAgent_Inf.updateIncomeProcess() baseAgent_Inf.checkConditions() baseAgent_Inf.solve() baseAgent_Inf.unpack('cFunc') # Retrieve parameters (makes code readable) Rfree = baseAgent_Inf.Rfree CRRA = baseAgent_Inf.CRRA EPermGroFac = baseAgent_Inf.PermGroFac[0] mNrmTrg = baseAgent_Inf.solution[0].mNrmSS UnempPrb = baseAgent_Inf.UnempPrb κ_Min = 1.0 - (Rfree**(-1.0)) * (Rfree * DiscFac)**(1.0 / CRRA) h_inf = (1.0 / (1.0 - EPermGroFac / Rfree)) cFunc_Uncnst = lambda m: (h_inf - 1) * κ_Min + κ_Min * m cFunc_TopBnd = lambda m: (1 - UnempPrb**(1.0 / CRRA) * (Rfree * DiscFac)**(1.0 / CRRA) / Rfree) * m cFunc_BotBnd = lambda m: (1 - (Rfree * DiscFac)**(1.0 / CRRA) / Rfree) * m # Plot the consumption function and its bounds cMaxLabel = r"c̅$(m) = (m-1+h)κ̲$" # Use unicode kludge cMinLabel = r"c̲$(m)= (1-\Phi_{R})m = κ̲ m$" mPlotMax = 25 mPlotMin = 0 # mKnk is point where the two upper bounds meet mKnk = ((h_inf - 1) * κ_Min) / ( (1 - UnempPrb**(1.0 / CRRA) * (Rfree * DiscFac)**(1.0 / CRRA) / Rfree) - κ_Min) mBelwKnkPts = 300 mAbveKnkPts = 700 mBelwKnk = np.linspace(mPlotMin, mKnk, mBelwKnkPts) mAbveKnk = np.linspace(mKnk, mPlotMax, mAbveKnkPts) mFullPts = np.linspace(mPlotMin, mPlotMax, mBelwKnkPts + mAbveKnkPts) plt.figure(figsize=(12, 8)) plt.plot(mFullPts, baseAgent_Inf.cFunc[0](mFullPts), label=r'$c(m)$') plt.plot(mBelwKnk, cFunc_Uncnst(mBelwKnk), label=cMaxLabel, linestyle="--") plt.plot( mAbveKnk, cFunc_Uncnst(mAbveKnk), label= r'Upper Bound $ = $ Min $[\overline{\overline{c}}(m),\overline{c}(m)]$', linewidth=2.5, color='black') plt.plot(mBelwKnk, cFunc_TopBnd(mBelwKnk), linewidth=2.5, color='black') plt.plot(mAbveKnk, cFunc_TopBnd(mAbveKnk), linestyle="--", label=r"$\overline{\overline{c}}(m) = κ̅m = (1 - ℘^{1/ρ}Φᵣ)m$") plt.plot(mBelwKnk, cFunc_BotBnd(mBelwKnk), color='red', linewidth=2.5) plt.plot(mAbveKnk, cFunc_BotBnd(mAbveKnk), color='red', label=cMinLabel, linewidth=2.5) plt.tick_params(labelbottom=False, labelleft=False, left='off', right='off', bottom='off', top='off') plt.xlim(mPlotMin, mPlotMax) plt.ylim(mPlotMin, 1.12 * cFunc_Uncnst(mPlotMax)) plt.text(mPlotMin, 1.12 * cFunc_Uncnst(mPlotMax) + 0.05, "$c$", fontsize=22) plt.text(mPlotMax + 0.1, mPlotMin, "$m$", fontsize=22) plt.legend(fontsize='x-large') plt.show() return None
if do_simulation: PFexample.T_sim = 120 # Set number of simulation periods PFexample.track_vars = ["mNrmNow"] PFexample.initializeSim() PFexample.simulate() # Make and solve an example consumer with idiosyncratic income shocks IndShockExample = IndShockConsumerType() IndShockExample.cycles = 0 # Make this type have an infinite horizon start_time = time() IndShockExample.solve() end_time = time() print("Solving a consumer with idiosyncratic shocks took " + mystr(end_time - start_time) + " seconds.") IndShockExample.unpack('cFunc') # Plot the consumption function and MPC for the infinite horizon consumer print("Concave consumption function:") plotFuncs(IndShockExample.cFunc[0], IndShockExample.solution[0].mNrmMin, 5) print("Marginal consumption function:") plotFuncsDer(IndShockExample.cFunc[0], IndShockExample.solution[0].mNrmMin, 5) # Compare the consumption functions for the perfect foresight and idiosyncratic # shock types. Risky income cFunc asymptotically approaches perfect foresight cFunc. print("Consumption functions for perfect foresight vs idiosyncratic shocks:") plotFuncs( [PFexample.cFunc[0], IndShockExample.cFunc[0]], IndShockExample.solution[0].mNrmMin, 100, )
def makeGICFailExample(DiscFac, PermShkStd, UnempPrb): # Construct the "GIC fails" example. GIC_fails_dictionary = dict(base_params) GIC_fails_dictionary['Rfree'] = 1.04 GIC_fails_dictionary['PermGroFac'] = [1.00] GICFailsExample = IndShockConsumerType( verbose=0, cycles=0, # cycles=0 makes this an infinite horizon consumer **GIC_fails_dictionary) GICFailsExample.DiscFac = DiscFac GICFailsExample.PermShkStd = [PermShkStd] GICFailsExample.UnempPrb = UnempPrb GICFailsExample.updateIncomeProcess() GICFailsExample.checkConditions() # Get calibrated parameters to make code more readable LivPrb = GICFailsExample.LivPrb[0] Rfree = GICFailsExample.Rfree DiscFac = GICFailsExample.DiscFac CRRA = GICFailsExample.CRRA permShkPrbs = GICFailsExample.PermShkDstn[0].pmf permShkVals = GICFailsExample.PermShkDstn[0].X EPermGroFac = GICFailsExample.PermGroFac[0] # np.dot multiplies vectors; probability times value for each outcome is expectation EpermShkInv = np.dot(permShkPrbs, permShkVals**(-1)) # $ \Ex[\permShk^{-1}] $ InvEpermShkInv = (EpermShkInv)**(-1) # $ (\Ex[\permShk^{-1}])^{-1}$ PermGroFac = EPermGroFac * InvEpermShkInv # Uncertainty-adjusted permanent growth factor ERNrmFac = Rfree / PermGroFac # Interest factor normalized by uncertainty-adjusted growth ErNrmRte = ERNrmFac - 1 # Interest rate is interest factor - 1 # "sustainable" C = P + (discounted) interest income # "sustainable" c = 1 + (discounted, normalized) interest income EmDelEq0 = lambda m: 1 + (m - 1) * (ErNrmRte / ERNrmFac ) # "sustainable" c where E[Δ m] = 0 GICFailsExample.solve( ) # Above, we set up the problem but did not solve it GICFailsExample.unpack( 'cFunc' ) # Make the consumption function easily accessible for plotting mPlotMin = 0 mPts = 1000 m = np.linspace(mPlotMin, 5, mPts) c_Limt = GICFailsExample.cFunc[0](m) c_Sstn = EmDelEq0(m) # "sustainable" consumption plt.figure(figsize=(12, 8)) plt.plot(m, c_Limt, label="$c(m_{t})$") plt.plot(m, c_Sstn, label="$\mathsf{E}_{t}[\Delta m_{t+1}] = 0$") plt.xlim(0, 5.5) plt.ylim(0, 1.6) plt.tick_params( labelbottom=False, labelleft=False, left="off", right="off", bottom="off", top="off", ) plt.legend(fontsize='x-large') plt.show() print(f'Current Growth Impatience Factor is {GICFailsExample.GPFInd}') return None
# - # ## Counterclockwise Concavification # # + {"code_folding": [0]} # This figure illustrates how both risks and constraints are examples of counterclockwise concavifications. # It plots three lines: the linear consumption function of a perfect foresight consumer, the kinked consumption # function of a consumer who faces a constraint, and the curved consumption function of a consumer that faces risk. # load the three agents: unconstrained perfect foresight, constrained perfect foresight, unconstrained with risk CCC_unconstr = IndShockConsumerType(**init_lifecycle) CCC_unconstr.delFromTimeInv('BoroCnstArt') CCC_unconstr.addToTimeVary('BoroCnstArt') CCC_unconstr.solve() CCC_unconstr.unpack("cFunc") CCC_constraint = IndShockConsumerType(**init_lifecycle) CCC_constraint.delFromTimeInv('BoroCnstArt') CCC_constraint.addToTimeVary('BoroCnstArt') CCC_constraint.BoroCnstArt = [ None, -1, None, None, None, None, None, None, None, None ] CCC_constraint.solve() CCC_constraint.unpack("cFunc") CCC_risk = IndShockConsumerType(**init_lifecycle_risk1) CCC_risk.delFromTimeInv('BoroCnstArt') CCC_risk.addToTimeVary('BoroCnstArt') CCC_risk.solve() CCC_risk.unpack("cFunc")
# # $$ # c(m) = \lim_{n \uparrow \infty} c_{T-n}(m) \notag # $$ # # %% # Create a buffer stock consumer instance by invoking the IndShockConsumerType class # with the built-in parameter dictionary "base_params" # Construct finite horizon agent with baseline parameters baseAgent_Fin = IndShockConsumerType(**base_params) baseAgent_Fin.cycles = 100 # Set finite horizon (T = 100) baseAgent_Fin.solve() # Solve the model baseAgent_Fin.unpack('cFunc') # Make the consumption function easily accessible # %% # Plot the different consumption rules for the different periods mPlotMin = 0 mLocCLabels = 9.6 # Defines horizontal limit of figure mPlotTop = 6.5 # Defines maximum m value where functions are plotted mPts = 1000 # Number of points at which functions are evaluated mBelwLabels = np.linspace(mPlotMin,mLocCLabels-0.1,mPts) # Range of m below loc of labels m_FullRange = np.linspace(mPlotMin,mPlotTop,mPts) # Full plot range c_Tm0 = m_FullRange # c_Tm0 defines the last period consumption rule (c=m) c_Tm1 = baseAgent_Fin.cFunc[ -2](mBelwLabels) # c_Tm1 defines the second-to-last period consumption rule c_Tm5 = baseAgent_Fin.cFunc[ -6](mBelwLabels) # c_Tm5 defines the T-5 period consumption rule
def make_future_kink(in_BoroCnstArt): """ This figure illustrates how a the introduction of a current constraint can hide/move a kink that was induced by a future constraint. To construct this figure, we plot two consumption functions: 1) perfect foresight consumer that faces one constraint in period 2 2) perfect foresight consumer that faces the same constraint as above plus one more constraint in period 3 Both consumption functions first loads the parameter set of the perfect foresight lifecycle households with ten periods. We then change the parameter "BoroCnstArt" which corresponds to big Tau in the paper, i.e. the set of future constraints ordered by time. """ # Make and solve the consumer with only one borrowing constraint Bcons1 = IndShockConsumerType(**init_lifecycle) Bcons1.delFromTimeInv("BoroCnstArt") Bcons1.addToTimeVary("BoroCnstArt") Bcons1.BoroCnstArt = [None, 0, None, None, None, None, None, None, None, None] Bcons1.solve() Bcons1.unpack("cFunc") # Make and solve the consumer with more than one binding borrowing constraint BCons2 = IndShockConsumerType(**init_lifecycle) BCons2.delFromTimeInv("BoroCnstArt") BCons2.addToTimeVary("BoroCnstArt") BCons2.BoroCnstArt = [ None, 0, in_BoroCnstArt, None, None, None, None, None, None, None, ] BCons2.solve() BCons2.unpack("cFunc") x = np.linspace(1, 1.2, 500, endpoint=True) y_mod1 = Bcons1.cFunc[0](x) y_mod2 = BCons2.cFunc[0](x) where_close = np.isclose(y_mod1, y_mod2) x0 = x[where_close][0] y0 = y_mod1[where_close][0] y1dd = np.diff(y_mod1, n=2) ind1 = np.argmin(y1dd[:250]) + 1 x1 = x[ind1] y1 = y_mod1[ind1] y2dd = np.diff(y_mod2, n=2) ind2 = np.argmin(y2dd[:250]) + 1 x2 = x[ind2] y2 = y_mod2[ind2] # Display the figure # print('Figure 2: How a Current Constraint Can Hide a Future Kink') f = plt.figure() plt.plot(x, y_mod1, color="green", label="$c_{t,1}$") plt.plot(x, y_mod2, color="red", label="$\hat{c}_{t,2}$") # plt.text(1.15,1.01,"$\hat{c}_{t,2}$",fontsize=14) # plt.text(1.07,1.01,"$c_{t,1}$",fontsize=14) # plt.arrow(1.149,1.011,-0.01,0,head_width=0.001,width=0.0001,facecolor='black',length_includes_head='True') # plt.arrow(1.085,1.011,0.01,0,head_width=0.001,width=0.0001,facecolor='black',length_includes_head='True') plt.xlim(left=1.0, right=1.2) plt.ylim(0.98, 1.025) plt.tick_params( labelbottom=False, labelleft=False, left="off", right="off", bottom="off", top="off", ) plt.text(0.99, 1.025, "$c$", fontsize=14) plt.text(1.20, 0.978, "$w$", fontsize=14) plt.text(0.988, y0, "$\hat{c}_{t,1}^{\#}$", fontsize=14) plt.text(0.988, y1 + 0.0015, "${c}_{t,1}^{\#}$", fontsize=14) plt.text(0.97, y2 - 0.0015, "$\hat{c}_{t,2}(w_{t,1})$", fontsize=14) plt.annotate( "kink that \n gets hidden", xy=(x1, y1), xytext=((x1 + 3) / 4, y1 + 0.005), arrowprops=dict(facecolor="black", headwidth=4, width=1, shrink=0.15), ) plt.text(x0 - 0.005, 0.977, "$\hat{w}_{t,1}$", fontsize=14) plt.text(x1 - 0.005, 0.977, "$w_{t,1}$", fontsize=14) plt.text(x2 - 0.01, 0.975, "$\hat{w}_{t,2}$", fontsize=14) plt.plot([1, x0], [y0, y0], color="black", linestyle="--") plt.plot([1, x1], [y1, y1], color="black", linestyle="--") plt.plot([1, x2], [y2, y2], color="black", linestyle="--") plt.plot([x0, x0], [0.98, y0], color="black", linestyle="--") plt.plot([x1, x1], [0.98, y1], color="black", linestyle="--") plt.plot([x2, x2], [0.98, y2], color="black", linestyle="--") plt.legend() plt.show() return None
# %% [markdown] # `# Create a buffer stock consumer instance:` # %% {"jupyter": {"source_hidden": true}, "tags": []} # Create a buffer stock consumer instance by invoking the IndShockConsumerType class # with the parameter dictionary "base_params" base_params['cycles'] = 100 # periods to solve from end # Construct finite horizon agent with baseline parameters baseAgent_Fin = \ IndShockConsumerType(**base_params, quietly=True) # Don't say anything during setup baseAgent_Fin.solve(quietly=True) # Solve the model quietly baseAgent_Fin.unpack('cFunc') # Retrieve consumption functions cFunc = baseAgent_Fin.cFunc # Shorthand # %% [markdown] # `# Plot the consumption rules:` # %% {"jupyter": {"source_hidden": true}, "tags": []} # Plot the different consumption rules for the different periods mPlotMin = 0 mLocCLabels = 9.6 # Defines horizontal limit of figure mPlotTop = 6.5 # Defines maximum m value where functions are plotted mPts = 1000 # Number of points at which functions are evaluated mBelwLabels = np.linspace(mPlotMin, mLocCLabels-0.1, mPts) # Range of m below loc of labels
# - # ## Counterclockwise Concavification # # + {"code_folding": [0]} # This figure illustrates how both risks and constraints are examples of counterclockwise concavifications. # It plots three lines: the linear consumption function of a perfect foresight consumer, the kinked consumption # function of a consumer who faces a constraint, and the curved consumption function of a consumer that faces risk. # load the three agents: unconstrained perfect foresight, constrained perfect foresight, unconstrained with risk CCC_unconstr = IndShockConsumerType(**init_lifecycle) CCC_unconstr.delFromTimeInv('BoroCnstArt') CCC_unconstr.addToTimeVary('BoroCnstArt') CCC_unconstr.solve() CCC_unconstr.unpack('cFunc') CCC_constraint = IndShockConsumerType(**init_lifecycle) CCC_constraint.delFromTimeInv('BoroCnstArt') CCC_constraint.addToTimeVary('BoroCnstArt') CCC_constraint.BoroCnstArt = [ None, -1, None, None, None, None, None, None, None, None ] CCC_constraint.solve() CCC_constraint.unpack('cFunc') CCC_risk = IndShockConsumerType(**init_lifecycle_risk1) CCC_risk.delFromTimeInv('BoroCnstArt') CCC_risk.addToTimeVary('BoroCnstArt') CCC_risk.solve() CCC_risk.unpack('cFunc')
def make_cons_func(in_BoroCnstArt, in_TranShkStd): """ This figure illustrates how the effect of risk is greater if there already exists a constraint. Initialize four types: unconstrained perfect foresight, unconstrained with risk, constrained perfect foresight, and constrained with risk. """ WwCR_unconstr = IndShockConsumerType(**init_lifecycle) WwCR_unconstr.delFromTimeInv("BoroCnstArt") WwCR_unconstr.addToTimeVary("BoroCnstArt") WwCR_unconstr.solve() WwCR_unconstr.unpack("cFunc") init_lifecycle_risk2["TranShkStd"] = [0, in_TranShkStd, 0, 0, 0, 0, 0, 0, 0, 0, 0] WwCR_risk = IndShockConsumerType(**init_lifecycle_risk2) WwCR_risk.delFromTimeInv("BoroCnstArt") WwCR_risk.addToTimeVary("BoroCnstArt") WwCR_risk.solve() WwCR_risk.unpack("cFunc") WwCR_constr = IndShockConsumerType(**init_lifecycle) WwCR_constr.cycles = 1 # Make this consumer live a sequence of periods exactly once WwCR_constr.delFromTimeInv("BoroCnstArt") WwCR_constr.addToTimeVary("BoroCnstArt") WwCR_constr.BoroCnstArt = [ None, None, in_BoroCnstArt, None, None, None, None, None, None, None, ] WwCR_constr.solve() WwCR_constr.unpack("cFunc") WwCR_constr_risk = IndShockConsumerType(**init_lifecycle_risk2) WwCR_constr_risk.delFromTimeInv("BoroCnstArt") WwCR_constr_risk.addToTimeVary("BoroCnstArt") WwCR_constr_risk.BoroCnstArt = [ None, None, in_BoroCnstArt, None, None, None, None, None, None, None, ] WwCR_constr_risk.solve() WwCR_constr_risk.unpack("cFunc") x = np.linspace(-8, -4, 1000, endpoint=True) y = WwCR_unconstr.cFunc[1](x) y2 = WwCR_risk.cFunc[1](x) y3 = WwCR_constr.cFunc[1](x) y4 = WwCR_constr_risk.cFunc[1](x) where_close = np.isclose(y, y3, atol=1e-05) where_close_risk = np.isclose(y2, y4, atol=1e-05) x0 = x[where_close][0] x1 = x[where_close_risk][0] y0 = y[where_close][0] y1 = y2[where_close_risk][0] # Display the figure # print('Figure 3: Consumption Functions With and Without a Constraint and a Risk') f = plt.figure() plt.plot(x, y, color="black", linewidth=3, label="${c}_{t,0}$") plt.plot( x, y2, color="black", linestyle="--", linewidth=3, label=r"$\tilde{c}_{t,0}$" ) plt.plot(x, y3, color="red", label="${c}_{t,1}$") plt.plot(x, y4, color="red", linestyle="--", label=r"$\tilde{c}_{t,1}$") plt.xlim(left=-8, right=-4.5) plt.ylim(0, 0.30) plt.text(-8.15, 0.305, "$c$", fontsize=14) plt.text(-4.5, -0.02, "$w$", fontsize=14) # plt.plot([-6.15,-6.15],[0,0.05],color="black",linestyle=":") plt.plot([x0, x0], [0, y0], color="black", linestyle=":") plt.plot([x1, x1], [0, y1], color="black", linestyle=":") # plt.text(-6.2,-0.02,r"$\underline{w}_{t,1}$",fontsize=14) plt.text(x0, -0.02, r"${w}_{t,1}$", fontsize=14) plt.text(x1, -0.02, r"$\bar{w}_{t,1}$", fontsize=14) plt.tick_params( labelbottom=False, labelleft=False, left="off", right="off", bottom="off", top="off", ) plt.legend() plt.show() return None
def make_concavification_figure(in_BoroCnstArt, in_UnempProb): """ This figure illustrates how both risks and constraints are examples of counterclockwise concavifications. It plots three lines: the linear consumption function of a perfect foresight consumer, the kinked consumption function of a consumer who faces a constraint, and the curved consumption function of a consumer that faces risk. """ # load the three agents: unconstrained perfect foresight, constrained perfect foresight, unconstrained with risk CCC_unconstr = IndShockConsumerType(**init_lifecycle) CCC_unconstr.delFromTimeInv("BoroCnstArt") CCC_unconstr.addToTimeVary("BoroCnstArt") CCC_unconstr.solve() CCC_unconstr.unpack("cFunc") CCC_constraint = IndShockConsumerType(**init_lifecycle) CCC_constraint.delFromTimeInv("BoroCnstArt") CCC_constraint.addToTimeVary("BoroCnstArt") CCC_constraint.BoroCnstArt = [ None, in_BoroCnstArt, None, None, None, None, None, None, None, None, ] CCC_constraint.solve() CCC_constraint.unpack("cFunc") init_lifecycle_risk1["UnempPrb"] = in_UnempProb CCC_risk = IndShockConsumerType(**init_lifecycle_risk1) CCC_risk.delFromTimeInv("BoroCnstArt") CCC_risk.addToTimeVary("BoroCnstArt") CCC_risk.solve() CCC_risk.unpack("cFunc") x = np.linspace(-1, 1, 500, endpoint=True) y = CCC_unconstr.cFunc[0](x) y2 = CCC_constraint.cFunc[0](x) y3 = CCC_risk.cFunc[0](x) where_close = np.isclose(y, y2, atol=1e-05) # Display the figure # print('Figure 1: Counterclockwise Concavifications') f = plt.figure() plt.plot(x, y, color="black") plt.plot(x, y2, color="green", label="Constraint", linestyle="--") plt.plot(x, y3, color="red", label="Risk", linestyle="--") plt.tick_params( labelbottom=False, labelleft=False, left="off", right="off", bottom="off", top="off", ) if np.any(where_close): x0 = x[where_close][0] y0 = y[where_close][0] plt.text(x0 - 0.02, 0.42, "$w^{\#}$", fontsize=14) plt.plot([x0, x0], [0.45, y0], color="black", linestyle=":", linewidth=1) plt.text(-1.2, 1.0, "$c$", fontsize=14) plt.text(1.12, 0.42, "$w$", fontsize=14) plt.ylim(0.465, 1.0) plt.legend() plt.show() return None
LifecycleExample.solve() print('First element of solution is', LifecycleExample.solution[0]) print('Solution has', len(LifecycleExample.solution), 'elements.') # %% [markdown] # 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: # %% 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) # %% [markdown] # ### "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. # %% {"code_folding": [0]} 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
print("First element of solution is", LifecycleExample.solution[0]) print("Solution has", len(LifecycleExample.solution), "elements.") # %% [markdown] # 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: # %% print("Consumption functions across the lifecycle:") mMin = np.min([ LifecycleExample.solution[t].mNrmMin for t in range(LifecycleExample.T_cycle) ]) # This makes all of the cFuncs accessible in the attribute cFunc LifecycleExample.unpack("cFunc") plotFuncs(LifecycleExample.cFunc, mMin, 5) # %% [markdown] # ### "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. # %% code_folding=[0] 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