├── Appendix └── OLGModelB.m ├── Assignments └── Assignment1_OLGModel.m ├── Documentation └── IntroToOLG.pdf ├── LICENSE ├── OLGModel1.m ├── OLGModel10.m ├── OLGModel10_ConsumptionFn.m ├── OLGModel10_ProgressiveIncomeTaxFn.m ├── OLGModel10_ReturnFn.m ├── OLGModel11.m ├── OLGModel12.m ├── OLGModel12_ConsumptionFn.m ├── OLGModel12_ProgressiveIncomeTaxFn.m ├── OLGModel12_ReturnFn.m ├── OLGModel13.m ├── OLGModel14.m ├── OLGModel14_FirmCorporateTaxRevenue.m ├── OLGModel14_FirmReturnFn.m ├── OLGModel14_FirmShareIssuance.m ├── OLGModel14_HouseholdConsumptionFn.m ├── OLGModel14_HouseholdIncomeFn.m ├── OLGModel14_HouseholdReturnFn.m ├── OLGModel1_ReturnFn.m ├── OLGModel2.m ├── OLGModel3.m ├── OLGModel3_ReturnFn.m ├── OLGModel4.m ├── OLGModel4_ConsumptionFn.m ├── OLGModel4_ReturnFn.m ├── OLGModel5.m ├── OLGModel5_ConsumptionFn.m ├── OLGModel5_ProgressiveIncomeTaxFn.m ├── OLGModel5_ReturnFn.m ├── OLGModel6.m ├── OLGModel6_ConsumptionFn.m ├── OLGModel6_ProgressiveIncomeTaxFn.m ├── OLGModel6_ReturnFn.m ├── OLGModel7.m ├── OLGModel7_DisposableIncomeFn.m ├── OLGModel8.m ├── OLGModel8_ReturnFn.m ├── OLGModel9A.m ├── OLGModel9B.m ├── OLGModel9B_ReturnFn.m ├── README.md └── TestTheOLGModels.m /Assignments/Assignment1_OLGModel.m: -------------------------------------------------------------------------------- 1 | %% Assignment 1: Add Government Debt to OLG Model 5 2 | % We make five changes to the code for OLG Model 5 3 | % First, create government debt parameter B (B for bonds). Line 82. 4 | % Second, is that instead of FnsToEvaluate.K we have FnsToEvaluate.Assets (the total asset holdings of the households); essentially just renaming. Line 147. 5 | % Third, is to substitute K=Assets-B into the general equilbrium condition for the capital market clearance. Line 153 (and similarly for line 156) 6 | % Fourth, modify government budget constraint to include government expenses for the interest on the debt: r*B. Line 157. 7 | % Fifth, some minor changes to model output in terms of what is plotted (to reflect the difference between K and Assets). 8 | % (Note: 'A' is already being used to denote the aggregate production technology parameter.) 9 | % 10 | % Lets model agents from age 20 to age 100, so 81 periods 11 | 12 | Params.agejshifter=19; % Age 20 minus one. Makes keeping track of actual age easy in terms of model age 13 | Params.J=100-Params.agejshifter; % =81, Number of period in life-cycle 14 | 15 | % Grid sizes to use 16 | n_d=101; % Endogenous labour choice (fraction of time worked) 17 | n_a=301; 18 | n_z=0; % This is how the VFI Toolkit thinks about deterministic models 19 | N_j=Params.J; % Number of periods in finite horizon 20 | 21 | figure_c=0; % I like to use a counter for the figures. Makes it easier to keep track of them when editing. 22 | 23 | 24 | %% Parameters 25 | 26 | % Discount rate 27 | Params.beta = 0.99; 28 | % Preferences 29 | Params.sigma = 2; % Coeff of relative risk aversion (curvature of consumption) 30 | Params.eta = 1.5; % Curvature of leisure (This will end up being 1/Frisch elasty) 31 | Params.psi = 10; % Weight on leisure 32 | 33 | Params.A=1; % Aggregate TFP. Not actually used anywhere. 34 | % Production function 35 | Params.alpha = 0.3; % Share of capital 36 | Params.delta = 0.1; % Depreciation rate of capital 37 | 38 | % Warm-glow of bequest 39 | Params.warmglowparam1=1; 40 | Params.warmglowparam2=2; 41 | 42 | % Demographics 43 | Params.Jr=67-Params.agejshifter; % Retirement age is 67 (remember j=1 is age 20) (You work when younger, not working from Jr on) 44 | Params.agej=(1:1:Params.J)'; % Current 'j' age, so can check when you retire. 45 | % Population growth rate 46 | Params.n=0.02; % percentage rate (expressed as fraction) at which population growths 47 | 48 | % Conditional survival probabilities: sj is the probability of surviving to be age j+1, given alive at age j 49 | % Most countries have calculations of these (as they are used by the government departments that oversee pensions) 50 | % In fact I will here get data on the conditional death probabilities, and then survival is just 1-death. 51 | % Here I just use them for the US, taken from "National Vital Statistics Report, volume 58, number 10, March 2010." 52 | % I took them from first column (qx) of Table 1 (Total Population) 53 | % Conditional death probabilities 54 | Params.dj=[0.006879, 0.000463, 0.000307, 0.000220, 0.000184, 0.000172, 0.000160, 0.000149, 0.000133, 0.000114, 0.000100, 0.000105, 0.000143, 0.000221, 0.000329, 0.000449, 0.000563, 0.000667, 0.000753, 0.000823,... 55 | 0.000894, 0.000962, 0.001005, 0.001016, 0.001003, 0.000983, 0.000967, 0.000960, 0.000970, 0.000994, 0.001027, 0.001065, 0.001115, 0.001154, 0.001209, 0.001271, 0.001351, 0.001460, 0.001603, 0.001769, 0.001943, 0.002120, 0.002311, 0.002520, 0.002747, 0.002989, 0.003242, 0.003512, 0.003803, 0.004118, 0.004464, 0.004837, 0.005217, 0.005591, 0.005963, 0.006346, 0.006768, 0.007261, 0.007866, 0.008596, 0.009473, 0.010450, 0.011456, 0.012407, 0.013320, 0.014299, 0.015323,... 56 | 0.016558, 0.018029, 0.019723, 0.021607, 0.023723, 0.026143, 0.028892, 0.031988, 0.035476, 0.039238, 0.043382, 0.047941, 0.052953, 0.058457, 0.064494,... 57 | 0.071107, 0.078342, 0.086244, 0.094861, 0.104242, 0.114432, 0.125479, 0.137427, 0.150317, 0.164187, 0.179066, 0.194979, 0.211941, 0.229957, 0.249020, 0.269112, 0.290198, 0.312231, 1.000000]; 58 | % dj covers Ages 0 to 100 59 | Params.sj=1-Params.dj(21:101); % Conditional survival probabilities 60 | Params.sj(end)=0; 61 | 62 | % Labor efficiency units depend on age 63 | Params.kappa_j=[linspace(1,3,50-Params.agejshifter), linspace(3,2,(Params.Jr-1)-(50-Params.agejshifter)),zeros(1,Params.J-Params.Jr+1)]; 64 | % These are not done seriously, really they should be set to something like 'average hourly wage conditional on age' in the data. 65 | % I have made them increase until age 50 (j=31), then decrease, and then be zero from retirement at age 67. 66 | % For parameters that depend on age, we just make them a vector with a 67 | % length the same as the number of periods, VFI Toolkit then handles 68 | % them automatically. 69 | 70 | % Taxes 71 | Params.tau = 0.15; % Tax rate on labour income 72 | % In addition to payroll tax rate tau, which funds the pension system we will add a progressive 73 | % income tax which funds government spending. 74 | % The progressive income tax takes the functional form: 75 | % IncomeTax=eta1+eta2*log(Income)*Income; % This functional form is empirically a decent fit for the US tax system 76 | % And is determined by the two parameters 77 | Params.eta1=0.09; % eta1 will be determined in equilibrium to balance gov budget constraint 78 | Params.eta2=0.053; 79 | 80 | % Government spending 81 | Params.GdivYtarget = 0.15; % Government spending as a fraction of GDP (this is essentially just used as a target to define a general equilibrium condition) 82 | Params.B=0.2; % Government debt 83 | 84 | %% Some initial values/guesses for variables that will be determined in general eqm 85 | Params.pension=0.4; % Initial guess (this will be determined in general eqm) 86 | Params.r=0.06; 87 | Params.AccidentBeq=0.03; % Accidental bequests (this is the lump sum transfer) 88 | Params.G=0.2; % Government expenditure 89 | % Params.eta1=0.09; 90 | 91 | %% Grids 92 | Params.amax=5; 93 | a_grid=Params.amax*(linspace(0,1,n_a).^3)'; % The ^3 means most points are near zero, which is where the derivative of the value fn changes most. 94 | % Note: Implicitly, we are imposing borrowing constraint a'>=0 95 | z_grid=1; % Note: n_z=0 means that z_grid and pi_z will be ignored, but we still need them as inputs to various commands 96 | pi_z=1; 97 | 98 | % Grid for labour choice 99 | h_grid=linspace(0,1,n_d)'; 100 | % Switch into toolkit notation 101 | d_grid=h_grid; 102 | 103 | %% Now, create the return function 104 | DiscountFactorParamNames={'beta','sj'}; 105 | 106 | ReturnFn=@(h,aprime,a,agej,r,A,delta,alpha,sigma,psi,eta,Jr,pension,tau,kappa_j,J,warmglowparam1,warmglowparam2,AccidentBeq, eta1,eta2)... 107 | OLGModel5_ReturnFn(h,aprime,a,agej,r,A,delta,alpha,sigma,psi,eta,Jr,pension,tau,kappa_j,J,warmglowparam1,warmglowparam2,AccidentBeq, eta1,eta2); 108 | 109 | %% Now solve the value function iteration problem, just to check that things are working before we go to General Equilbrium 110 | disp('Test ValueFnIter') 111 | vfoptions=struct(); % Just using the defaults. 112 | tic; 113 | [V, Policy]=ValueFnIter_Case1_FHorz(n_d,n_a,n_z,N_j, d_grid, a_grid, z_grid, pi_z, ReturnFn, Params, DiscountFactorParamNames, [], vfoptions); 114 | toc 115 | 116 | %% Initial distribution of agents at birth (j=1) 117 | jequaloneDist=zeros(n_a,1); % n_a by n_z. 118 | jequaloneDist(1)=1; % Everyone is born with zero assets 119 | 120 | %% Agents age distribution 121 | % Many OLG models include some kind of population growth, and perhaps 122 | % some other things that create a weighting of different ages that needs to 123 | % be used to calculate the stationary distribution and aggregate variable. 124 | Params.mewj=ones(1,Params.J); % Marginal distribution of households over age 125 | for jj=2:length(Params.mewj) 126 | Params.mewj(jj)=Params.sj(jj-1)*Params.mewj(jj-1)/(1+Params.n); 127 | end 128 | Params.mewj=Params.mewj./sum(Params.mewj); % Normalize to one 129 | 130 | AgeWeightsParamNames={'mewj'}; % Many finite horizon models apply different weights to different 'ages'; eg., due to survival rates or population growth rates. 131 | 132 | %% Test 133 | disp('Test StationaryDist') 134 | simoptions=struct(); % Just use the defaults 135 | tic; 136 | StationaryDist=StationaryDist_FHorz_Case1(jequaloneDist,AgeWeightsParamNames,Policy,n_d,n_a,n_z,N_j,pi_z,Params,simoptions); 137 | toc 138 | 139 | %% General eqm variables 140 | GEPriceParamNames={'r','pension','AccidentBeq','G','eta1'}; 141 | 142 | %% Set up the General Equilibrium conditions (on assets/interest rate, assuming a representative firm with Cobb-Douglas production function) 143 | 144 | % Stationary Distribution Aggregates (important that ordering of Names and Functions is the same) 145 | FnsToEvaluate.H = @(h,aprime,a) h; % Aggregate hours worked 146 | FnsToEvaluate.L = @(h,aprime,a,kappa_j) kappa_j*h; % Aggregate labour supply (in efficiency units) 147 | FnsToEvaluate.Assets = @(h,aprime,a) a; % Aggregate physical capital 148 | FnsToEvaluate.PensionSpending = @(h,aprime,a,pension,agej,Jr) (agej>=Jr)*pension; % Total spending on pensions 149 | FnsToEvaluate.AccidentalBeqLeft = @(h,aprime,a,sj) aprime*(1-sj); % Accidental bequests left by people who die 150 | FnsToEvaluate.IncomeTaxRevenue = @(h,aprime,a,eta1,eta2,kappa_j,r,delta,alpha,A) OLGModel5_ProgressiveIncomeTaxFn(h,aprime,a,eta1,eta2,kappa_j,r,delta,alpha,A); % Revenue raised by the progressive income tax (needed own function to avoid log(0) causing problems) 151 | 152 | % General Equilibrium conditions (these should evaluate to zero in general equilbrium) 153 | GeneralEqmEqns.capitalmarket = @(r,Assets,B,L,alpha,delta,A) r-alpha*A*((Assets-B)^(alpha-1))*(L^(1-alpha)); % interest rate equals marginal product of capital net of depreciation 154 | GeneralEqmEqns.pensions = @(PensionSpending,tau,L,r,A,alpha,delta) PensionSpending-tau*(A*(1-alpha)*((r+delta)/(alpha*A))^(alpha/(alpha-1)))*L; % Retirement benefits equal Payroll tax revenue: pension*fractionretired-tau*w*H 155 | GeneralEqmEqns.bequests = @(AccidentalBeqLeft,AccidentBeq,n) AccidentalBeqLeft/(1+n)-AccidentBeq; % Accidental bequests received equal accidental bequests left 156 | GeneralEqmEqns.Gtarget = @(G,GdivYtarget,A,Assets,B,L,alpha) G-GdivYtarget*(A*(Assets-B)^(alpha)*(L^(1-alpha))); % G is equal to the target, GdivYtarget*Y 157 | GeneralEqmEqns.govbudget = @(G,IncomeTaxRevenue,r,B) G+r*B-IncomeTaxRevenue; % Government budget balances (note that pensions are a seperate budget) 158 | % Note: the pensions general eqm condition looks more complicated just because we replaced w with the formula for w in terms of r. It is actually just the same formula as before. 159 | 160 | %% Test 161 | disp('Test AggVars') 162 | AggVars=EvalFnOnAgentDist_AggVars_FHorz_Case1(StationaryDist, Policy, FnsToEvaluate, Params, [], n_d, n_a, n_z,N_j, d_grid, a_grid, z_grid); 163 | 164 | %% Solve for the General Equilibrium 165 | heteroagentoptions.verbose=1; 166 | p_eqm=HeteroAgentStationaryEqm_Case1_FHorz(jequaloneDist,AgeWeightsParamNames,n_d, n_a, n_z, N_j, 0, pi_z, d_grid, a_grid, z_grid, ReturnFn, FnsToEvaluate, GeneralEqmEqns, Params, DiscountFactorParamNames, [], [], [], GEPriceParamNames, heteroagentoptions, simoptions, vfoptions); 167 | % p_eqm contains the general equilibrium parameter values 168 | % Put this into Params so we can calculate things about the initial equilibrium 169 | Params.r=p_eqm.r; 170 | Params.pension=p_eqm.pension; 171 | Params.AccidentBeq=p_eqm.AccidentBeq; 172 | Params.G=p_eqm.G; 173 | Params.eta1=p_eqm.eta1; 174 | 175 | % Calculate a few things related to the general equilibrium. 176 | [V, Policy]=ValueFnIter_Case1_FHorz(n_d,n_a,n_z,N_j, d_grid, a_grid, z_grid, pi_z, ReturnFn, Params, DiscountFactorParamNames, [], vfoptions); 177 | StationaryDist=StationaryDist_FHorz_Case1(jequaloneDist,AgeWeightsParamNames,Policy,n_d,n_a,n_z,N_j,pi_z,Params,simoptions); 178 | % Can just use the same FnsToEvaluate as before. 179 | AgeConditionalStats=LifeCycleProfiles_FHorz_Case1(StationaryDist,Policy,FnsToEvaluate,[],Params,n_d,n_a,n_z,N_j,d_grid,a_grid,z_grid); 180 | 181 | %% Plot the life cycle profiles of capital and labour for the inital and final eqm. 182 | 183 | % figure_c=figure_c+1; 184 | % figure(figure_c) 185 | % subplot(3,1,1); plot(1:1:Params.J,AgeConditionalStats.H.Mean) 186 | % title('Life Cycle Profile: Hours Worked') 187 | % subplot(3,1,2); plot(1:1:Params.J,AgeConditionalStats.L.Mean) 188 | % title('Life Cycle Profile: Labour Supply') 189 | % subplot(3,1,3); plot(1:1:Params.J,AgeConditionalStats.Assets.Mean) 190 | % title('Life Cycle Profile: Assets') 191 | % saveas(figure_c,'./SavedOutput/Graphs/OLGModel5_LifeCycleProfiles','pdf') 192 | 193 | %% Calculate some aggregates and print findings about them 194 | 195 | % Add consumption to the FnsToEvaluate 196 | FnsToEvaluate.Consumption=@(h,aprime,a,agej,Jr,r,pension,tau,kappa_j,alpha,delta,A,eta1,eta2) OLGModel5_ConsumptionFn(h,aprime,a,agej,Jr,r,pension,tau,kappa_j,alpha,delta,A,eta1,eta2); 197 | 198 | AggVars=EvalFnOnAgentDist_AggVars_FHorz_Case1(StationaryDist, Policy, FnsToEvaluate, Params, [], n_d, n_a, n_z,N_j, d_grid, a_grid, z_grid); 199 | 200 | K=AggVars.Assets.Mean-Params.B; 201 | 202 | % GDP 203 | Y=Params.A*(K^Params.alpha)*(AggVars.L.Mean^(1-Params.alpha)); 204 | 205 | % wage (note that this is calculation is only valid because we have Cobb-Douglas production function and are looking at a stationary general equilibrium) 206 | KdivL=((Params.r+Params.delta)/(Params.alpha*Params.A))^(1/(Params.alpha-1)); 207 | w=Params.A*(1-Params.alpha)*(KdivL^Params.alpha); % wage rate (per effective labour unit) 208 | 209 | fprintf('Following are some aggregates of the model economy: \n') 210 | fprintf('Output: Y=%8.2f \n',Y) 211 | fprintf('Capital-Output ratio: K/Y=%8.2f \n',K/Y) 212 | fprintf('Assets-Output ratio: Assets/Y=%8.2f \n',AggVars.Assets.Mean/Y) 213 | fprintf('Consumption-Output ratio: C/Y=%8.2f \n',AggVars.Consumption.Mean/Y) 214 | fprintf('Average labor productivity: Y/H=%8.2f \n', Y/AggVars.H.Mean) 215 | fprintf('Government-to-Output ratio: G/Y=%8.2f \n', Params.G/Y) 216 | fprintf('Government-Debt-to-Output ratio: B/Y=%8.2f \n', Params.B/Y) 217 | fprintf('Accidental Bequests as fraction of GDP: %8.2f \n',Params.AccidentBeq/Y) 218 | fprintf('Wage: w=%8.2f \n',w) 219 | 220 | 221 | 222 | -------------------------------------------------------------------------------- /Documentation/IntroToOLG.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vfitoolkit/IntroToOLGModels/b84aee3c58b41fb8399148147e44cd98afb23832/Documentation/IntroToOLG.pdf -------------------------------------------------------------------------------- /OLGModel1.m: -------------------------------------------------------------------------------- 1 | %% OLG Model 1: consumption-leisure in general equilibrium OLG 2 | % We start with about the simplest OLG model we can in which there is just the life-cycle with a 3 | % consumption-leisure choice. No assets (savings) and no government. 4 | % The solution will look a bit silly, don't worry, they will improve over the next few models :) 5 | % 6 | % We will solve for the general equilibrium. We then plot some life-cycle 7 | % profiles for the household (based on general equilibrium). 8 | % 9 | % If you have not seen: "Introduction to Life-Cycle Models" I recommend you start there 10 | % before looking at OLG models 11 | % See: https://www.vfitoolkit.com/updates-blog/2021/an-introduction-to-life-cycle-models/ 12 | % 13 | % In this first model households receive pensions which simply 'fall from 14 | % the sky' in the sense that there is no government/tax to fund the 15 | % pensions. This is a bit odd but allows us to focus on the most basic general equilibrium. 16 | % In the second model we will add a tax to fund pensions. 17 | 18 | %% Begin setting up to use VFI Toolkit to solve 19 | % Lets model agents from age 20 to age 100, so 81 periods 20 | 21 | Params.agejshifter=19; % Age 20 minus one. Makes keeping track of actual age easy in terms of model age 22 | Params.J=100-Params.agejshifter; % =81, Number of period in life-cycle 23 | 24 | % Grid sizes to use 25 | n_d=101; % Endogenous labour choice (fraction of time worked) 26 | n_a=1; 27 | n_z=0; % This is how the VFI Toolkit thinks about deterministic models 28 | N_j=Params.J; % Number of periods in finite horizon 29 | 30 | figure_c=0; % I like to use a counter for the figures. Makes it easier to keep track of them when editing. 31 | 32 | %% Parameters 33 | 34 | % Discount rate 35 | Params.beta = 0.99; 36 | % Preferences 37 | Params.sigma = 2; % Coeff of relative risk aversion (curvature of consumption) 38 | Params.eta = 1.5; % Curvature of leisure (This will end up being 1/Frisch elasty) 39 | Params.psi = 10; % Weight on leisure 40 | 41 | Params.A=1; % Aggregate TFP. Not actually used anywhere. 42 | % Production function 43 | Params.alpha = 0.3; % Share of capital 44 | Params.delta = 0.1; % Depreciation rate of capital 45 | 46 | % Demographics 47 | Params.Jr=67-Params.agejshifter; % Retirement age is 67 (remember j=1 is age 20) (You work when younger, not working from Jr on) 48 | Params.agej=(1:1:Params.J)'; % Current 'j' age, so can check when you retire. 49 | 50 | % This is the tax which is unused here but will be used to fund the pensions in OLG Model 2 51 | Params.tau=0; 52 | % The amount of pension that retirees receive 53 | Params.pension=0.3; 54 | 55 | %% Some initial values/guesses for variables that will be determined in general eqm 56 | Params.w=1; 57 | 58 | %% Grids 59 | % While there are no 'a' in this model, VFI Toolkit requires it 60 | % to figure out what is going on. By making it just a single grid point, 61 | % and then not using them anywhere, we are essentially solving a model without them. 62 | a_grid=1; 63 | z_grid=[]; % Note: n_z=0 means that z_grid and pi_z will be ignored, but we still need them as inputs to various commands 64 | pi_z=[]; 65 | 66 | % Grid for labour choice 67 | h_grid=linspace(0,1,n_d)'; 68 | % Switch into toolkit notation 69 | d_grid=h_grid; 70 | 71 | %% Now, create the return function 72 | DiscountFactorParamNames={'beta'}; 73 | 74 | % Note: the following return function actually includes 'assets', but since 75 | % this very basic model has only one possible value for assets this ends up 76 | % irrelevant (VFI Toolkit is not really designed for models this simple with no endogenous state so it looks like it is just overkill when used to solve them). 77 | ReturnFn=@(h,aprime,a,agej,w,sigma,psi,eta,Jr,pension,tau)... 78 | OLGModel1_ReturnFn(h,aprime,a,agej,w,sigma,psi,eta,Jr,pension,tau); 79 | 80 | %% Now solve the value function iteration problem, just to check that things are working before we go to General Equilbrium 81 | disp('Test ValueFnIter') 82 | vfoptions=struct(); % Just using the defaults. 83 | tic; 84 | [V, Policy]=ValueFnIter_Case1_FHorz(n_d,n_a,n_z,N_j, d_grid, a_grid, z_grid, pi_z, ReturnFn, Params, DiscountFactorParamNames, [], vfoptions); 85 | toc 86 | 87 | %% Initial distribution of agents at birth (j=1) 88 | jequaloneDist=1; % n_a by n_z, but in current setup this is just 1-by-1 in anycase so 'everyone' is going to have to be born here. 89 | 90 | %% Agents age distribution 91 | % Many OLG models include some kind of population growth, and perhaps 92 | % some other things that create a weighting of different ages that needs to 93 | % be used to calculate the stationary distribution and aggregate variable. 94 | % This toy model does not have population growth, but there will be 95 | % different fractions of households of each age due to the probability of dying. 96 | % This toy model does not. 97 | Params.mewj=ones(1,Params.J)/Params.J; % This is the Marginal distribution of households over age 98 | % Agents are evenly spread across all ages. 99 | 100 | AgeWeightsParamNames={'mewj'}; % Many finite horizon models apply different weights to different 'ages'; eg., due to survival rates or population growth rates. 101 | 102 | %% Test 103 | disp('Test StationaryDist') 104 | simoptions=struct(); % Just use the defaults 105 | tic; 106 | StationaryDist=StationaryDist_FHorz_Case1(jequaloneDist,AgeWeightsParamNames,Policy,n_d,n_a,n_z,N_j,pi_z,Params,simoptions); 107 | toc 108 | 109 | %% Everything until this point is just the same as for Life-Cycle Models 110 | % For OLG models we need to add a few things 111 | % 1) GEPriceParamNames: the names of the parameters/prices to be determined in general equilibrium 112 | % 2) FnsToEvaluate: these are same as in Life-Cycle models 113 | % 3) GeneralEqmEqns: the general equilibrium equations, these will be equal to zero in general equilibrium 114 | % they take any price/parameter as inputs, and also any FnsToEvaluate as inputs 115 | % 4) That is it for set up, now just use HeteroAgentStationaryEqm_Case1_FHorz() command to solve for the general equilibrium 116 | % 5) p_eqm contains the general equilibrium values of parameters/prices determined in general 117 | % equilibrium, we can put these in Params and then just calculate anything like value 118 | % function, agent stationary distribution, life-cycle profiles, etc., as normal. 119 | 120 | %% General eqm variables 121 | GEPriceParamNames={'w'}; 122 | 123 | %% Set up the General Equilibrium conditions (on assets/interest rate, assuming a representative firm with Cobb-Douglas production function) 124 | 125 | % Stationary Distribution Aggregates (important that ordering of Names and Functions is the same) 126 | FnsToEvaluate.L = @(h,aprime,a) h; % Aggregate labour supply 127 | % This version of the model is simple enough that tax revenues and pension expenditures can all just be calculated 'directly'. 128 | 129 | % General Equilibrium conditions (these should evaluate to zero in general equilbrium) 130 | GeneralEqmEqns.labormarket = @(w,alpha,L,A) w-(1-alpha)*A*L^(-alpha); % wage equals marginal product of labour 131 | % Note: Inputs to general equilibrium conditions must be either aggregate variables or parameters 132 | 133 | %% Test 134 | disp('Test AggVars') 135 | AggVars=EvalFnOnAgentDist_AggVars_FHorz_Case1(StationaryDist, Policy, FnsToEvaluate, Params, [], n_d, n_a, n_z,N_j, d_grid, a_grid, z_grid); 136 | 137 | % Advanced: If you did want to test the GeneralEqmEqns to makes sure they are doing what you expect the following commented out lines show how 138 | % % % To be able to test the general equilibrium conditions you need to add the aggregate variables into Params 139 | % % AggVarNames=fieldnames(AggVars); 140 | % % for ii=1:length(AggVarNames) 141 | % % Params.(AggVarNames{ii})=AggVars.(AggVarNames{ii}).Mean; 142 | % % end 143 | % % GeneralEqmConditionsVec=real(GeneralEqmConditions_Case1_v2(GeneralEqmEqns,Params, 2)); 144 | 145 | %% Solve for the General Equilibrium 146 | % Use the toolkit to find the equilibrium price index. 147 | % In what follows I use the (default) 'search' approach to calculate the General equilibrium. 148 | 149 | heteroagentoptions.verbose=1; 150 | p_eqm=HeteroAgentStationaryEqm_Case1_FHorz(jequaloneDist,AgeWeightsParamNames,n_d, n_a, n_z, N_j, 0, pi_z, d_grid, a_grid, z_grid, ReturnFn, FnsToEvaluate, GeneralEqmEqns, Params, DiscountFactorParamNames, [], [], [], GEPriceParamNames, heteroagentoptions, simoptions, vfoptions); 151 | 152 | %% p_eqm contains the general equilibrium 'prices', to calculate things about the model 153 | % economy in general equilibrium we must put these in Params, and then use them as standard. 154 | 155 | % p_eqm contains the general equilibrium parameter values 156 | % Put this into Params so we can calculate things about the general equilibrium 157 | Params.w=p_eqm.w; 158 | 159 | % Calculate a few things related to the general equilibrium. 160 | [V, Policy]=ValueFnIter_Case1_FHorz(n_d,n_a,n_z,N_j, d_grid, a_grid, z_grid, pi_z, ReturnFn, Params, DiscountFactorParamNames, [], vfoptions); 161 | StationaryDist=StationaryDist_FHorz_Case1(jequaloneDist,AgeWeightsParamNames,Policy,n_d,n_a,n_z,N_j,pi_z,Params,simoptions); 162 | 163 | % We could of course also look at things like life-cycle profiles or 164 | % simulate panel data, but we will wait until later OLG Models to do so. 165 | % E.g., OLG Model 3 plots some life-cycle profiles, OLG Model 4 plots some 166 | % 'aggregates', like GDP and the capital-output ratio. -------------------------------------------------------------------------------- /OLGModel10.m: -------------------------------------------------------------------------------- 1 | %% OLG Model 10: Permanent Types 1, Fixed effect 2 | % Add a fixed effect to idiosyncratic productivity, which we call gamma_i 3 | % Modelled as a more general "permanent type" (how VFI Toolkit solves fixed 4 | % effects and much more, as seen in later examples). 5 | % 6 | % Main change to codes is now we need to call _PType version of all the 7 | % codes, which also changes exactly what form the output comes in. 8 | % 9 | % We use N_i to set the number of permanent types 10 | % If we enter a parameter as size N_i-by-1 it will automatically be treated 11 | % as depending on i and handled appropriately (would be the same for 12 | % N_j-by-N-i, for a parameter depending on age, and differing by permanent type) 13 | % 14 | % We also need to define the distribution across the permanent types (a 15 | % parameter, and we put the name of it in PTypeDistParamNames). We call 16 | % this gamma_dist. 17 | % 18 | % Run times will be roughly linear in the number of permanent types. By 19 | % default so is memory use, but can reduce it using vfoptions and simoptions. 20 | % 21 | % Model statistics, like AggVars and Life-cycle profiles are automatically 22 | % calculated both for the aggregate/average economy, and also for each individual 23 | % permanent type (technically, the statistics are conditional on the permanent type). 24 | % This is demonstrated in the life-cycle profile plots that show both the 25 | % mean for the whole population, and the (conditional) mean for each of the agent types. 26 | % 27 | % All the objects like value function, agent distribution, and model 28 | % statistics are organised according to the 'name' of the permanent type. 29 | % When we just use N_i types, these are automatically given the names 30 | % ptype001, ptype002, etc. (Later examples show how to specify names if you want to set them yourself) 31 | 32 | 33 | %% Begin setting up to use VFI Toolkit to solve 34 | % Lets model agents from age 20 to age 100, so 81 periods 35 | 36 | Params.agejshifter=19; % Age 20 minus one. Makes keeping track of actual age easy in terms of model age 37 | Params.J=100-Params.agejshifter; % =81, Number of period in life-cycle 38 | 39 | % Grid sizes to use 40 | n_d=51; % Endogenous labour choice (fraction of time worked) 41 | n_a=301; % Endogenous asset holdings 42 | % Exogenous labor productivity units shocks (next two lines) 43 | n_z=15; % AR(1) with age-dependent params 44 | vfoptions.n_e=3; % iid 45 | N_j=Params.J; % Number of periods in finite horizon 46 | N_i=3; % Number of permanent types (number of values of fixed effect) 47 | 48 | %% Parameters 49 | 50 | % Discount rate 51 | Params.beta = 0.96; 52 | % Preferences 53 | Params.sigma = 2; % Coeff of relative risk aversion (curvature of consumption) 54 | Params.eta = 1.5; % Curvature of leisure (This will end up being 1/Frisch elasty) 55 | Params.psi = 10; % Weight on leisure 56 | 57 | Params.A=1; % Aggregate TFP. Not actually used anywhere. 58 | % Production function 59 | Params.alpha = 0.3; % Share of capital 60 | Params.delta = 0.1; % Depreciation rate of capital 61 | 62 | % Demographics 63 | Params.agej=1:1:Params.J; % Is a vector of all the agej: 1,2,3,...,J 64 | Params.Jr=46; 65 | % Population growth rate 66 | Params.n=0.02; % percentage rate (expressed as fraction) at which population growths 67 | 68 | % Fixed effect 69 | Params.gamma_i=[-0.5,0,0.5]; 70 | 71 | % Age-dependent labor productivity units 72 | Params.kappa_j=[linspace(0.5,2,Params.Jr-15),linspace(2,1,14),zeros(1,Params.J-Params.Jr+1)]; 73 | % Life-cycle AR(1) process z, on (log) labor productivity units 74 | % Chosen following Karahan & Ozkan (2013) [as used by Fella, Gallipoli & Pan (2019)] 75 | % Originals just cover ages 24 to 60, so I create these, and then repeat first and last periods to fill it out 76 | Params.rho_z=0.7596+0.2039*((1:1:37)/10)-0.0535*((1:1:37)/10).^2+0.0028*((1:1:37)/10).^3; % Chosen following Karahan & Ozkan (2013) [as used by Fella, Gallipoli & Pan (2019)] 77 | Params.sigma_epsilon_z=0.0518-0.0405*((1:1:37)/10)+0.0105*((1:1:37)/10).^2-0.0002*((1:1:37)/10).^3; % Chosen following Karahan & Ozkan (2013) [as used by Fella, Gallipoli & Pan (2019)] 78 | % Note that 37 covers 24 to 60 inclusive 79 | % Now repeat the first and last values to fill in working age, and put zeros for retirement (where it is anyway irrelevant) 80 | Params.rho_z=[Params.rho_z(1)*ones(1,4),Params.rho_z,Params.rho_z(end)*ones(1,4),zeros(1,100-65+1)]; 81 | Params.sigma_epsilon_z=[Params.sigma_epsilon_z(1)*ones(1,4),Params.sigma_epsilon_z,Params.sigma_epsilon_z(end)*ones(1,4),Params.sigma_epsilon_z(end)*ones(1,100-65+1)]; 82 | % Transitory iid shock 83 | Params.sigma_e=0.0410+0.0221*((24:1:60)/10)-0.0069*((24:1:60)/10).^2+0.0008*((24:1:60)/10).^3; 84 | % Now repeat the first and last values to fill in working age, and put zeros for retirement (where it is anyway irrelevant) 85 | Params.sigma_e=[Params.sigma_e(1)*ones(1,4),Params.sigma_e,Params.sigma_e(end)*ones(1,4),Params.sigma_e(end)*ones(1,100-65+1)]; 86 | % Note: These will interact with the endogenous labor so the final labor 87 | % earnings process will not equal that of Karahan & Ozkan (2013) 88 | % Note: Karahan & Ozkan (2013) also have a fixed effect (which they call alpha) and which I ignore here. 89 | 90 | % Conditional survival probabilities: sj is the probability of surviving to be age j+1, given alive at age j 91 | % Most countries have calculations of these (as they are used by the government departments that oversee pensions) 92 | % In fact I will here get data on the conditional death probabilities, and then survival is just 1-death. 93 | % Here I just use them for the US, taken from "National Vital Statistics Report, volume 58, number 10, March 2010." 94 | % I took them from first column (qx) of Table 1 (Total Population) 95 | % Conditional death probabilities 96 | Params.dj=[0.006879, 0.000463, 0.000307, 0.000220, 0.000184, 0.000172, 0.000160, 0.000149, 0.000133, 0.000114, 0.000100, 0.000105, 0.000143, 0.000221, 0.000329, 0.000449, 0.000563, 0.000667, 0.000753, 0.000823,... 97 | 0.000894, 0.000962, 0.001005, 0.001016, 0.001003, 0.000983, 0.000967, 0.000960, 0.000970, 0.000994, 0.001027, 0.001065, 0.001115, 0.001154, 0.001209, 0.001271, 0.001351, 0.001460, 0.001603, 0.001769, 0.001943, 0.002120, 0.002311, 0.002520, 0.002747, 0.002989, 0.003242, 0.003512, 0.003803, 0.004118, 0.004464, 0.004837, 0.005217, 0.005591, 0.005963, 0.006346, 0.006768, 0.007261, 0.007866, 0.008596, 0.009473, 0.010450, 0.011456, 0.012407, 0.013320, 0.014299, 0.015323,... 98 | 0.016558, 0.018029, 0.019723, 0.021607, 0.023723, 0.026143, 0.028892, 0.031988, 0.035476, 0.039238, 0.043382, 0.047941, 0.052953, 0.058457, 0.064494,... 99 | 0.071107, 0.078342, 0.086244, 0.094861, 0.104242, 0.114432, 0.125479, 0.137427, 0.150317, 0.164187, 0.179066, 0.194979, 0.211941, 0.229957, 0.249020, 0.269112, 0.290198, 0.312231, 1.000000]; 100 | % dj covers Ages 0 to 100 101 | Params.sj=1-Params.dj(21:101); % Conditional survival probabilities 102 | Params.sj(end)=0; % In the present model the last period (j=J) value of sj is actually irrelevant 103 | 104 | % Warm glow of bequest 105 | Params.warmglow1=0.3; % (relative) importance of bequests 106 | Params.warmglow2=3; % bliss point of bequests (essentially, the target amount) 107 | Params.warmglow3=Params.sigma; % By using the same curvature as the utility of consumption it makes it much easier to guess appropraite parameter values for the warm glow 108 | 109 | % Taxes 110 | Params.tau = 0.15; % Tax rate on labour income 111 | % In addition to payroll tax rate tau, which funds the pension system we will add a progressive 112 | % income tax which funds government spending. 113 | % The progressive income tax takes the functional form: 114 | % IncomeTax=eta1+eta2*log(Income)*Income; % This functional form is empirically a decent fit for the US tax system 115 | % And is determined by the two parameters 116 | % Params.eta1=0.09; % eta1 will be determined in equilibrium to balance gov budget constraint 117 | Params.eta2=0.053; 118 | 119 | % Government spending 120 | Params.GdivYtarget = 0.15; % Government spending as a fraction of GDP (this is essentially just used as a target to define a general equilibrium condition) 121 | 122 | %% Some initial values/guesses for variables that will be determined in general eqm 123 | Params.pension=0.4; % Initial guess (this will be determined in general eqm) 124 | Params.r=0.1; 125 | Params.AccidentBeq=0.03; % Accidental bequests (this is the lump sum transfer) 126 | Params.G=0.12; % Government expenditure 127 | Params.eta1=0.09; % tax rate (part of progressive tax) 128 | 129 | %% Grids 130 | a_grid=10*(linspace(0,1,n_a).^3)'; % The ^3 means most points are near zero, which is where the derivative of the value fn changes most. 131 | 132 | % First, z, the AR(1) with age-dependent parameters 133 | [z_grid_J, pi_z_J] = discretizeLifeCycleAR1_FellaGallipoliPan(Params.rho_z,Params.sigma_epsilon_z,n_z,Params.J); 134 | % z_grid_J is n_z-by-J, so z_grid_J(:,j) is the grid for age j 135 | % pi_z_J is n_z-by-n_z-by-J, so pi_z_J(:,:,j) is the transition matrix for age j 136 | 137 | % Second, e, the iid normal with age-dependent parameters 138 | [e_grid_J, pi_e_J] = discretizeLifeCycleAR1_FellaGallipoliPan(zeros(1,Params.J),Params.sigma_e,vfoptions.n_e,Params.J); % Note: AR(1) with rho=0 is iid normal 139 | % Because e is iid we actually just use 140 | pi_e_J=shiftdim(pi_e_J(1,:,:),1); 141 | 142 | % Similarly any (iid) e variable always has to go into vfoptions and simoptions 143 | vfoptions.e_grid=e_grid_J; 144 | vfoptions.pi_e=pi_e_J; 145 | simoptions.n_e=vfoptions.n_e; 146 | simoptions.e_grid=e_grid_J; 147 | simoptions.pi_e=pi_e_J; 148 | 149 | 150 | % Grid for labour choice 151 | h_grid=linspace(0,1,n_d)'; % Notice that it is imposing the 0<=h<=1 condition implicitly 152 | % Switch into toolkit notation 153 | d_grid=h_grid; 154 | 155 | % Distribution of the agents across the permanent types (must sum to 1) 156 | Params.gamma_dist=[0.2,0.5,0.3]; 157 | PTypeDistParamNames={'gamma_dist'}; 158 | 159 | %% Now, create the return function 160 | DiscountFactorParamNames={'beta','sj'}; 161 | 162 | % Notice we use 'OLGModel10_ReturnFn' 163 | ReturnFn=@(h,aprime,a,z,e,sigma,psi,eta,agej,Jr,J,gamma_i,pension,r,A,delta,alpha,kappa_j,warmglow1,warmglow2,AccidentBeq, eta1,eta2,tau) OLGModel10_ReturnFn(h,aprime,a,z,e,sigma,psi,eta,agej,Jr,J,gamma_i,pension,r,A,delta,alpha,kappa_j,warmglow1,warmglow2,AccidentBeq, eta1,eta2,tau) 164 | 165 | %% Now solve the value function iteration problem, just to check that things are working before we go to General Equilbrium 166 | disp('Test ValueFnIter') 167 | tic; 168 | [V, Policy]=ValueFnIter_Case1_FHorz_PType(n_d,n_a,n_z,N_j,N_i, d_grid, a_grid, z_grid_J, pi_z_J, ReturnFn, Params, DiscountFactorParamNames, vfoptions); 169 | toc 170 | 171 | %% Initial distribution of agents at birth (j=1) 172 | % Before we plot the life-cycle profiles we have to define how agents are 173 | % at age j=1. We will give them all zero assets. 174 | jequaloneDist=zeros([n_a,n_z,vfoptions.n_e],'gpuArray'); % Put no households anywhere on grid 175 | jequaloneDist(1,floor((n_z+1)/2),floor((simoptions.n_e+1)/2))=1; % All agents start with zero assets, and the median shock 176 | 177 | %% Agents age distribution 178 | % Many OLG models include some kind of population growth, and perhaps 179 | % some other things that create a weighting of different ages that needs to 180 | % be used to calculate the stationary distribution and aggregate variable. 181 | % Many OLG models include some kind of population growth, and perhaps 182 | % some other things that create a weighting of different ages that needs to 183 | % be used to calculate the stationary distribution and aggregate variable. 184 | Params.mewj=ones(1,Params.J); % Marginal distribution of households over age 185 | for jj=2:length(Params.mewj) 186 | Params.mewj(jj)=Params.sj(jj-1)*Params.mewj(jj-1)/(1+Params.n); 187 | end 188 | Params.mewj=Params.mewj./sum(Params.mewj); % Normalize to one 189 | 190 | AgeWeightsParamNames={'mewj'}; % So VFI Toolkit knows which parameter is the mass of agents of each age 191 | 192 | %% Test 193 | disp('Test StationaryDist') 194 | StationaryDist=StationaryDist_Case1_FHorz_PType(jequaloneDist,AgeWeightsParamNames,PTypeDistParamNames,Policy,n_d,n_a,n_z,N_j,N_i,pi_z_J,Params,simoptions); 195 | 196 | %% General eqm variables 197 | GEPriceParamNames={'r','pension','AccidentBeq','G','eta1'}; 198 | 199 | %% Set up the General Equilibrium conditions (on assets/interest rate, assuming a representative firm with Cobb-Douglas production function) 200 | % Note: we need to add z & e to FnsToEvaluate inputs. 201 | 202 | % Stationary Distribution Aggregates (important that ordering of Names and Functions is the same) 203 | FnsToEvaluate.H = @(h,aprime,a,z,e) h; % Aggregate labour supply 204 | FnsToEvaluate.L = @(h,aprime,a,z,e,kappa_j) kappa_j*exp(z+e)*h; % Aggregate labour supply in efficiency units 205 | FnsToEvaluate.K = @(h,aprime,a,z,e) a;% Aggregate physical capital 206 | FnsToEvaluate.PensionSpending = @(h,aprime,a,z,e,pension,agej,Jr) (agej>=Jr)*pension; % Total spending on pensions 207 | FnsToEvaluate.AccidentalBeqLeft = @(h,aprime,a,z,e,sj) aprime*(1-sj); % Accidental bequests left by people who die 208 | FnsToEvaluate.IncomeTaxRevenue = @(h,aprime,a,z,e,eta1,eta2,kappa_j,r,delta,alpha,A,gamma_i,agej,Jr) OLGModel10_ProgressiveIncomeTaxFn(h,aprime,a,z,e,eta1,eta2,kappa_j,r,delta,alpha,A,gamma_i,agej,Jr); % Revenue raised by the progressive income tax (needed own function to avoid log(0) causing problems) 209 | 210 | % General Equilibrium conditions (these should evaluate to zero in general equilbrium) 211 | GeneralEqmEqns.capitalmarket = @(r,K,L,alpha,delta,A) r-alpha*A*(K^(alpha-1))*(L^(1-alpha)); % interest rate equals marginal product of capital net of depreciation 212 | GeneralEqmEqns.pensions = @(PensionSpending,tau,L,r,A,alpha,delta) PensionSpending-tau*(A*(1-alpha)*((r+delta)/(alpha*A))^(alpha/(alpha-1)))*L; % Retirement benefits equal Payroll tax revenue: pension*fractionretired-tau*w*H 213 | GeneralEqmEqns.bequests = @(AccidentalBeqLeft,AccidentBeq,n) AccidentalBeqLeft/(1+n)-AccidentBeq; % Accidental bequests received equal accidental bequests left 214 | GeneralEqmEqns.Gtarget = @(G,GdivYtarget,A,K,L,alpha) G-GdivYtarget*(A*K^(alpha)*(L^(1-alpha))); % G is equal to the target, GdivYtarget*Y 215 | GeneralEqmEqns.govbudget = @(G,IncomeTaxRevenue) G-IncomeTaxRevenue; % Government budget balances (note that pensions are a seperate budget) 216 | % Note: the pensions general eqm condition looks more complicated just because we replaced w with the formula for w in terms of r. It is actually just the same formula as before. 217 | 218 | %% Test 219 | % Note: Because we used simoptions we must include this as an input 220 | disp('Test AggVars') 221 | AggVars=EvalFnOnAgentDist_AggVars_FHorz_Case1_PType(StationaryDist, Policy, FnsToEvaluate, Params, n_d, n_a, n_z,N_j,N_i, d_grid, a_grid, z_grid_J,simoptions); 222 | 223 | %% Solve for the General Equilibrium 224 | heteroagentoptions.verbose=1; 225 | p_eqm=HeteroAgentStationaryEqm_Case1_FHorz_PType(n_d, n_a, n_z, N_j, N_i, [], pi_z_J, d_grid, a_grid, z_grid_J,jequaloneDist, ReturnFn, FnsToEvaluate, GeneralEqmEqns, Params, DiscountFactorParamNames, AgeWeightsParamNames, PTypeDistParamNames, GEPriceParamNames,heteroagentoptions, simoptions, vfoptions); 226 | % p_eqm contains the general equilibrium parameter values 227 | % Put this into Params so we can calculate things about the initial equilibrium 228 | Params.r=p_eqm.r; 229 | Params.pension=p_eqm.pension; 230 | Params.AccidentBeq=p_eqm.AccidentBeq; 231 | Params.G=p_eqm.G; 232 | Params.eta1=p_eqm.eta1; 233 | 234 | % Calculate a few things related to the general equilibrium. 235 | [V, Policy]=ValueFnIter_Case1_FHorz_PType(n_d,n_a,n_z,N_j, N_i, d_grid, a_grid, z_grid_J, pi_z_J, ReturnFn, Params, DiscountFactorParamNames, vfoptions); 236 | StationaryDist=StationaryDist_Case1_FHorz_PType(jequaloneDist,AgeWeightsParamNames,PTypeDistParamNames,Policy,n_d,n_a,n_z,N_j,N_i,pi_z_J,Params,simoptions); 237 | % Can just use the same FnsToEvaluate as before. 238 | AgeConditionalStats=LifeCycleProfiles_FHorz_Case1_PType(StationaryDist,Policy,FnsToEvaluate,Params,n_d,n_a,n_z,N_j,N_i,d_grid,a_grid,z_grid_J,simoptions); 239 | 240 | %% Plot the life cycle profiles of capital and labour for the inital and final eqm. 241 | % Note that there is the mean, and also those for each agent type 242 | % VFI Toolkit automatically gives them names ptype001, ptype002, etc. 243 | 244 | figure(1) 245 | subplot(3,1,1); plot(1:1:Params.J,AgeConditionalStats.H.Mean) 246 | hold on 247 | subplot(3,1,1); plot(1:1:Params.J,AgeConditionalStats.H.ptype001.Mean,1:1:Params.J,AgeConditionalStats.H.ptype002.Mean,1:1:Params.J,AgeConditionalStats.H.ptype003.Mean) 248 | hold off 249 | title('Life Cycle Profile: Hours Worked') 250 | legend('Average','ptype001','ptype002','ptype003') 251 | subplot(3,1,2); plot(1:1:Params.J,AgeConditionalStats.L.Mean) 252 | hold on 253 | subplot(3,1,2); plot(1:1:Params.J,AgeConditionalStats.L.ptype001.Mean,1:1:Params.J,AgeConditionalStats.L.ptype002.Mean,1:1:Params.J,AgeConditionalStats.L.ptype003.Mean) 254 | hold off 255 | title('Life Cycle Profile: Labour Supply') 256 | subplot(3,1,3); plot(1:1:Params.J,AgeConditionalStats.K.Mean) 257 | hold on 258 | subplot(3,1,3); plot(1:1:Params.J,AgeConditionalStats.K.ptype001.Mean,1:1:Params.J,AgeConditionalStats.K.ptype002.Mean,1:1:Params.J,AgeConditionalStats.K.ptype003.Mean) 259 | hold off 260 | title('Life Cycle Profile: Assets') 261 | saveas(figure_c,'./SavedOutput/Graphs/OLGModel6_LifeCycleProfiles','pdf') 262 | 263 | %% Calculate some aggregates and print findings about them 264 | 265 | % Add consumption to the FnsToEvaluate 266 | FnsToEvaluate.Consumption=@(h,aprime,a,z,e,agej,Jr,r,gamma_i,pension,tau,kappa_j,alpha,delta,A,eta1,eta2,AccidentBeq) OLGModel10_ConsumptionFn(h,aprime,a,z,e,agej,Jr,r,gamma_i,pension,tau,kappa_j,alpha,delta,A,eta1,eta2,AccidentBeq); 267 | 268 | AggVars=EvalFnOnAgentDist_AggVars_FHorz_Case1_PType(StationaryDist, Policy, FnsToEvaluate, Params, n_d, n_a, n_z,N_j, N_i, d_grid, a_grid, z_grid_J,simoptions); 269 | 270 | % GDP 271 | Y=Params.A*(AggVars.K.Mean^Params.alpha)*(AggVars.L.Mean^(1-Params.alpha)); 272 | 273 | % wage (note that this is calculation is only valid because we have Cobb-Douglas production function and are looking at a stationary general equilibrium) 274 | KdivL=((Params.r+Params.delta)/(Params.alpha*Params.A))^(1/(Params.alpha-1)); 275 | w=Params.A*(1-Params.alpha)*(KdivL^Params.alpha); % wage rate (per effective labour unit) 276 | 277 | fprintf('Following are some aggregates of the model economy: \n') 278 | fprintf('Output: Y=%8.2f \n',Y) 279 | fprintf('Capital-Output ratio: K/Y=%8.2f \n',AggVars.K.Mean/Y) 280 | fprintf('Consumption-Output ratio: C/Y=%8.2f \n',AggVars.Consumption.Mean/Y) 281 | fprintf('Average labor productivity: Y/H=%8.2f \n', Y/AggVars.H.Mean) 282 | fprintf('Government-to-Output ratio: G/Y=%8.2f \n', Params.G/Y) 283 | fprintf('Accidental Bequests as fraction of GDP: %8.2f \n',Params.AccidentBeq/Y) 284 | fprintf('Wage: w=%8.2f \n',w) 285 | 286 | 287 | 288 | -------------------------------------------------------------------------------- /OLGModel10_ConsumptionFn.m: -------------------------------------------------------------------------------- 1 | function c=OLGModel10_ConsumptionFn(h,aprime,a,z,e,agej,Jr,r,gamma_i,pension,tau,kappa_j,alpha,delta,A,eta1,eta2,AccidentBeq) 2 | % Note: these lines are essentially just a copy of the relevant part of the return fn 3 | 4 | KdivL=((r+delta)/(alpha*A))^(1/(alpha-1)); 5 | w=A*(1-alpha)*(KdivL^alpha); % wage rate (per effective labour unit) 6 | 7 | % Progressive income tax 8 | if agej0 15 | IncomeTax=eta1+eta2*log(Income)*Income; 16 | end 17 | % Note: Have made pensions exempt from income tax. 18 | 19 | if agej0 14 | IncomeTax=eta1+eta2*log(Income)*Income; 15 | end 16 | % Note: Have made pensions exempt from income tax. 17 | 18 | 19 | end -------------------------------------------------------------------------------- /OLGModel10_ReturnFn.m: -------------------------------------------------------------------------------- 1 | function F=OLGModel10_ReturnFn(h,aprime,a,z,e,sigma,psi,eta,agej,Jr,J,gamma_i,pension,r,A,delta,alpha,kappa_j,warmglow1,warmglow2,AccidentBeq, eta1,eta2,tau) 2 | % Add fixed effect gamma_i to idiosyncratic labor productivity (compared to OLGModel6_ReturnFn) 3 | 4 | KdivL=((r+delta)/(alpha*A))^(1/(alpha-1)); 5 | w=A*(1-alpha)*(KdivL^alpha); % wage rate (per effective labour unit) 6 | 7 | % Progressive income tax 8 | if agej0 15 | IncomeTax=eta1+eta2*log(Income)*Income; 16 | end 17 | % Note: Have made pensions exempt from income tax. 18 | 19 | 20 | F=-Inf; 21 | if agej0 28 | F=(c^(1-sigma))/(1-sigma) -psi*(h^(1+eta))/(1+eta); % The utility function 29 | end 30 | 31 | % Warm-glow bequest 32 | if agej==J % Final period 33 | warmglow=warmglow1*(aprime^(1-warmglow2))/(1-warmglow2); 34 | F=F+warmglow; 35 | end 36 | % Notice that we have modelled the warm-glow in such a way that you only 37 | % get it if you die in the last period (j=J). But we know there is a 1-sj 38 | % risk of dying every period. So we might prefer to model that we get the 39 | % warm glow bequest if we die at any age. The following commented out two lines 40 | % implement this alternative. [note: need to add sj to inputs of ReturnFn to use it] 41 | % warmglow=warmglowparam1*(aprime^(1-warmglowparam2))/(1-warmglowparam2); % Note: same formula as above 42 | % F=F+(1-sj)*warmglow 43 | % Note: if using this, have to make sure sj=0 for j=J. 44 | % Comment: I am not aware of any study saying which of these two 45 | % alternatives works better empirically. 46 | 47 | end 48 | -------------------------------------------------------------------------------- /OLGModel11.m: -------------------------------------------------------------------------------- 1 | %% OLG Model 11: Permanent Types 2, single male and single female 2 | % Use two permanent types: male and female 3 | % The only difference between the two will be the labor productivity. 4 | % So there will be different parameters: gamma_i, kappa_j, rho_z, sigma_epsilon_z, sigma_e 5 | % And different grids and probabilities for z and e. 6 | % 7 | % We will use names for the permanent types (rather than just a number of 8 | % permanent types as in previous model example). 9 | % 10 | % We do this by using Names_i that contains the names themselves. 11 | % We will use two names, 'male' and 'female' 12 | % Any parameter that is declared as normal will be treated as the same for 13 | % all permanent types. 14 | % Any parameter that depends on permanent type should be set up as follows 15 | % Params.rho_z.male=0.9; 16 | % Params.rho_z.female=0.8; 17 | % Similarly anything like grids, or options, that depends on the permanent 18 | % type can be done with the same '.-indexing' by name of the permanent 19 | % types. 20 | % 21 | % All the objects like value function, agent distribution, and model 22 | % statistics are organised according to the 'name' of the permanent type. 23 | % When we just use Names_i types, these are automatically given the names 24 | % we use, so here 'male' and 'female' 25 | % 26 | % This example is mainly illustrative, don't take the calibration seriously. 27 | % 28 | % The only changes relative to OLG Model 10 are changing Names_i to Names_i, 29 | % and then changing the labor productivity parameters in the 'Parameters' 30 | % section, and the section where the grids are set up. Of course the graphs 31 | % are changed slightly too. 32 | % 33 | % Idle comment: whether you call it N_i or Names_i is irrelevant, what 34 | % matters if whether it is a number or a cell of strings. I rename N_i and 35 | % Names_i just as a mental cue to help remember what is going on. 36 | 37 | 38 | %% Begin setting up to use VFI Toolkit to solve 39 | % Lets model agents from age 20 to age 100, so 81 periods 40 | 41 | Params.agejshifter=19; % Age 20 minus one. Makes keeping track of actual age easy in terms of model age 42 | Params.J=100-Params.agejshifter; % =81, Number of period in life-cycle 43 | 44 | % Grid sizes to use 45 | n_d=51; % Endogenous labour choice (fraction of time worked) 46 | n_a=301; % Endogenous asset holdings 47 | % Exogenous labor productivity units shocks (next two lines) 48 | n_z=15; % AR(1) with age-dependent params 49 | vfoptions.n_e=3; % iid 50 | N_j=Params.J; % Number of periods in finite horizon 51 | Names_i={'male','female'}; % Number of permanent types 52 | 53 | %% Parameters 54 | 55 | % Discount rate 56 | Params.beta = 0.96; 57 | % Preferences 58 | Params.sigma = 2; % Coeff of relative risk aversion (curvature of consumption) 59 | Params.eta = 1.5; % Curvature of leisure (This will end up being 1/Frisch elasty) 60 | Params.psi = 10; % Weight on leisure 61 | 62 | Params.A=1; % Aggregate TFP. Not actually used anywhere. 63 | % Production function 64 | Params.alpha = 0.3; % Share of capital 65 | Params.delta = 0.1; % Depreciation rate of capital 66 | 67 | % Demographics 68 | Params.agej=1:1:Params.J; % Is a vector of all the agej: 1,2,3,...,J 69 | Params.Jr=46; 70 | % Population growth rate 71 | Params.n=0.02; % percentage rate (expressed as fraction) at which population growths 72 | 73 | % Fixed effect 74 | Params.gamma_i.male=0.1; 75 | Params.gamma_i.female=0.1; 76 | 77 | % Age-dependent labor productivity units 78 | Params.kappa_j.male=[linspace(0.5,2,Params.Jr-15),linspace(2,1,14),zeros(1,Params.J-Params.Jr+1)]; 79 | Params.kappa_j.female=[linspace(0.5,1.8,Params.Jr-15),linspace(1.8,1,14),zeros(1,Params.J-Params.Jr+1)]; % start the same but peak lower 80 | % Life-cycle AR(1) process z, on (log) labor productivity units 81 | % Chosen following Karahan & Ozkan (2013) [as used by Fella, Gallipoli & Pan (2019)] 82 | % Originals just cover ages 24 to 60, so I create these, and then repeat first and last periods to fill it out 83 | rho_z=0.7596+0.2039*((1:1:37)/10)-0.0535*((1:1:37)/10).^2+0.0028*((1:1:37)/10).^3; % Chosen following Karahan & Ozkan (2013) [as used by Fella, Gallipoli & Pan (2019)] 84 | sigma_epsilon_z=0.0518-0.0405*((1:1:37)/10)+0.0105*((1:1:37)/10).^2-0.0002*((1:1:37)/10).^3; % Chosen following Karahan & Ozkan (2013) [as used by Fella, Gallipoli & Pan (2019)] 85 | % Note that 37 covers 24 to 60 inclusive 86 | % Now repeat the first and last values to fill in working age, and put zeros for retirement (where it is anyway irrelevant) 87 | rho_z=[rho_z(1)*ones(1,4),rho_z,rho_z(end)*ones(1,4),zeros(1,100-65+1)]; 88 | sigma_epsilon_z=[sigma_epsilon_z(1)*ones(1,4),sigma_epsilon_z,sigma_epsilon_z(end)*ones(1,4),sigma_epsilon_z(end)*ones(1,100-65+1)]; 89 | % Transitory iid shock 90 | sigma_e=0.0410+0.0221*((24:1:60)/10)-0.0069*((24:1:60)/10).^2+0.0008*((24:1:60)/10).^3; 91 | % Now repeat the first and last values to fill in working age, and put zeros for retirement (where it is anyway irrelevant) 92 | sigma_e=[sigma_e(1)*ones(1,4),sigma_e,sigma_e(end)*ones(1,4),sigma_e(end)*ones(1,100-65+1)]; 93 | % Note: These will interact with the endogenous labor so the final labor 94 | % earnings process will not equal that of Karahan & Ozkan (2013) 95 | % Note: Karahan & Ozkan (2013) also have a fixed effect (which they call alpha) and which I ignore here. 96 | Params.rho_z.male=rho_z; 97 | Params.rho_z.female=0.9*rho_z; % Lower autocorrelation (arbitrary, just want to make them different from male) 98 | Params.sigma_epsilon_z.male=sigma_epsilon_z; 99 | Params.sigma_epsilon_z.female=0.9*sigma_epsilon_z; % smaller innovations to the AR(1) (arbitrary, just want to make them different from male) 100 | Params.sigma_e.male=sigma_e; 101 | Params.sigma_e.female=1.3*sigma_e; % larger iid shocks (arbitrary, just want to make them different from male) 102 | 103 | 104 | % Conditional survival probabilities: sj is the probability of surviving to be age j+1, given alive at age j 105 | % Most countries have calculations of these (as they are used by the government departments that oversee pensions) 106 | % In fact I will here get data on the conditional death probabilities, and then survival is just 1-death. 107 | % Here I just use them for the US, taken from "National Vital Statistics Report, volume 58, number 10, March 2010." 108 | % I took them from first column (qx) of Table 1 (Total Population) 109 | % Conditional death probabilities 110 | Params.dj=[0.006879, 0.000463, 0.000307, 0.000220, 0.000184, 0.000172, 0.000160, 0.000149, 0.000133, 0.000114, 0.000100, 0.000105, 0.000143, 0.000221, 0.000329, 0.000449, 0.000563, 0.000667, 0.000753, 0.000823,... 111 | 0.000894, 0.000962, 0.001005, 0.001016, 0.001003, 0.000983, 0.000967, 0.000960, 0.000970, 0.000994, 0.001027, 0.001065, 0.001115, 0.001154, 0.001209, 0.001271, 0.001351, 0.001460, 0.001603, 0.001769, 0.001943, 0.002120, 0.002311, 0.002520, 0.002747, 0.002989, 0.003242, 0.003512, 0.003803, 0.004118, 0.004464, 0.004837, 0.005217, 0.005591, 0.005963, 0.006346, 0.006768, 0.007261, 0.007866, 0.008596, 0.009473, 0.010450, 0.011456, 0.012407, 0.013320, 0.014299, 0.015323,... 112 | 0.016558, 0.018029, 0.019723, 0.021607, 0.023723, 0.026143, 0.028892, 0.031988, 0.035476, 0.039238, 0.043382, 0.047941, 0.052953, 0.058457, 0.064494,... 113 | 0.071107, 0.078342, 0.086244, 0.094861, 0.104242, 0.114432, 0.125479, 0.137427, 0.150317, 0.164187, 0.179066, 0.194979, 0.211941, 0.229957, 0.249020, 0.269112, 0.290198, 0.312231, 1.000000]; 114 | % dj covers Ages 0 to 100 115 | Params.sj=1-Params.dj(21:101); % Conditional survival probabilities 116 | Params.sj(end)=0; % In the present model the last period (j=J) value of sj is actually irrelevant 117 | 118 | % Warm glow of bequestz_grid 119 | Params.warmglow1=0.3; % (relative) importance of bequests 120 | Params.warmglow2=3; % bliss point of bequests (essentially, the target amount) 121 | Params.warmglow3=Params.sigma; % By using the same curvature as the utility of consumption it makes it much easier to guess appropraite parameter values for the warm glow 122 | 123 | % Taxes 124 | Params.tau = 0.15; % Tax rate on labour income 125 | % In addition to payroll tax rate tau, which funds the pension system we will add a progressive 126 | % income tax which funds government spending. 127 | % The progressive income tax takes the functional form: 128 | % IncomeTax=eta1+eta2*log(Income)*Income; % This functional form is empirically a decent fit for the US tax system 129 | % And is determined by the two parameters 130 | % Params.eta1=0.09; % eta1 will be determined in equilibrium to balance gov budget constraint 131 | Params.eta2=0.053; 132 | 133 | % Government spending 134 | Params.GdivYtarget = 0.15; % Government spending as a fraction of GDP (this is essentially just used as a target to define a general equilibrium condition) 135 | 136 | %% Some initial values/guesses for variables that will be determined in general eqm 137 | Params.pension=0.4; % Initial guess (this will be determined in general eqm) 138 | Params.r=0.1; 139 | Params.AccidentBeq=0.03; % Accidental bequests (this is the lump sum transfer) 140 | Params.G=0.12; % Government expenditure 141 | Params.eta1=0.09; % tax rate (part of progressive tax) 142 | 143 | %% Grids 144 | a_grid=10*(linspace(0,1,n_a).^3)'; % The ^3 means most points are near zero, which is where the derivative of the value fn changes most. 145 | 146 | % First, z, the AR(1) with age-dependent parameters 147 | [z_grid_J.male, pi_z_J.male] = discretizeLifeCycleAR1_FellaGallipoliPan(Params.rho_z.male,Params.sigma_epsilon_z.male,n_z,Params.J); 148 | [z_grid_J.female, pi_z_J.female] = discretizeLifeCycleAR1_FellaGallipoliPan(Params.rho_z.female,Params.sigma_epsilon_z.female,n_z,Params.J); 149 | % z_grid_J is n_z-by-J, so z_grid_J(:,j) is the grid for age j 150 | % pi_z_J is n_z-by-n_z-by-J, so pi_z_J(:,:,j) is the transition matrix for age j 151 | 152 | % Second, e, the iid normal with age-dependent parameters 153 | [e_grid_J.male, pi_e_J.male] = discretizeLifeCycleAR1_FellaGallipoliPan(zeros(1,Params.J),Params.sigma_e.male,vfoptions.n_e,Params.J); % Note: AR(1) with rho=0 is iid normal 154 | [e_grid_J.female, pi_e_J.female] = discretizeLifeCycleAR1_FellaGallipoliPan(zeros(1,Params.J),Params.sigma_e.female,vfoptions.n_e,Params.J); % Note: AR(1) with rho=0 is iid normal 155 | % Because e is iid we actually just use 156 | pi_e_J.male=shiftdim(pi_e_J.male(1,:,:),1); 157 | pi_e_J.female=shiftdim(pi_e_J.female(1,:,:),1); 158 | 159 | % Similarly any (iid) e variable always has to go into vfoptions and simoptions 160 | simoptions.n_e=vfoptions.n_e; 161 | vfoptions.e_grid.male=e_grid_J.male; 162 | vfoptions.pi_e.male=pi_e_J.male; 163 | simoptions.e_grid.male=e_grid_J.male; 164 | simoptions.pi_e.male=pi_e_J.male; 165 | vfoptions.e_grid.female=e_grid_J.female; 166 | vfoptions.pi_e.female=pi_e_J.female; 167 | simoptions.e_grid.female=e_grid_J.female; 168 | simoptions.pi_e.female=pi_e_J.female; 169 | 170 | 171 | % Grid for labour choice 172 | h_grid=linspace(0,1,n_d)'; % Notice that it is imposing the 0<=h<=1 condition implicitly 173 | % Switch into toolkit notation 174 | d_grid=h_grid; 175 | 176 | % Distribution of the agents across the permanent types (must sum to 1) 177 | Params.gamma_dist=[0.5,0.5]; 178 | PTypeDistParamNames={'gamma_dist'}; 179 | 180 | %% Now, create the return function 181 | DiscountFactorParamNames={'beta','sj'}; 182 | 183 | % Notice we use 'OLGModel10_ReturnFn' 184 | ReturnFn=@(h,aprime,a,z,e,sigma,psi,eta,agej,Jr,J,gamma_i,pension,r,A,delta,alpha,kappa_j,warmglow1,warmglow2,AccidentBeq, eta1,eta2,tau)... 185 | OLGModel10_ReturnFn(h,aprime,a,z,e,sigma,psi,eta,agej,Jr,J,gamma_i,pension,r,A,delta,alpha,kappa_j,warmglow1,warmglow2,AccidentBeq, eta1,eta2,tau); 186 | 187 | %% Now solve the value function iteration problem, just to check that things are working before we go to General Equilbrium 188 | disp('Test ValueFnIter') 189 | tic; 190 | [V, Policy]=ValueFnIter_Case1_FHorz_PType(n_d,n_a,n_z,N_j,Names_i, d_grid, a_grid, z_grid_J, pi_z_J, ReturnFn, Params, DiscountFactorParamNames, vfoptions); 191 | toc 192 | 193 | %% Initial distribution of agents at birth (j=1) 194 | % Before we plot the life-cycle profiles we have to define how agents are 195 | % at age j=1. We will give them all zero assets. 196 | jequaloneDist=zeros([n_a,n_z,vfoptions.n_e],'gpuArray'); % Put no households anywhere on grid 197 | jequaloneDist(1,floor((n_z+1)/2),floor((simoptions.n_e+1)/2))=1; % All agents start with zero assets, and the median shock 198 | 199 | %% Agents age distribution 200 | % Many OLG models include some kind of population growth, and perhaps 201 | % some other things that create a weighting of different ages that needs to 202 | % be used to calculate the stationary distribution and aggregate variable. 203 | % Many OLG models include some kind of population growth, and perhaps 204 | % some other things that create a weighting of different ages that needs to 205 | % be used to calculate the stationary distribution and aggregate variable. 206 | Params.mewj=ones(1,Params.J); % Marginal distribution of households over age 207 | for jj=2:length(Params.mewj) 208 | Params.mewj(jj)=Params.sj(jj-1)*Params.mewj(jj-1)/(1+Params.n); 209 | end 210 | Params.mewj=Params.mewj./sum(Params.mewj); % Normalize to one 211 | 212 | AgeWeightsParamNames={'mewj'}; % So VFI Toolkit knows which parameter is the mass of agents of each age 213 | 214 | %% Test 215 | disp('Test StationaryDist') 216 | StationaryDist=StationaryDist_Case1_FHorz_PType(jequaloneDist,AgeWeightsParamNames,PTypeDistParamNames,Policy,n_d,n_a,n_z,N_j,Names_i,pi_z_J,Params,simoptions); 217 | 218 | %% General eqm variables 219 | GEPriceParamNames={'r','pension','AccidentBeq','G','eta1'}; 220 | 221 | %% Set up the General Equilibrium conditions (on assets/interest rate, assuming a representative firm with Cobb-Douglas production function) 222 | 223 | % Stationary Distribution Aggregates (important that ordering of Names and Functions is the same) 224 | FnsToEvaluate.H = @(h,aprime,a,z,e) h; % Aggregate labour supply 225 | FnsToEvaluate.L = @(h,aprime,a,z,e,kappa_j) kappa_j*exp(z+e)*h; % Aggregate labour supply in efficiency units 226 | FnsToEvaluate.K = @(h,aprime,a,z,e) a;% Aggregate physical capital 227 | FnsToEvaluate.PensionSpending = @(h,aprime,a,z,e,pension,agej,Jr) (agej>=Jr)*pension; % Total spending on pensions 228 | FnsToEvaluate.AccidentalBeqLeft = @(h,aprime,a,z,e,sj) aprime*(1-sj); % Accidental bequests left by people who die 229 | FnsToEvaluate.IncomeTaxRevenue = @(h,aprime,a,z,e,eta1,eta2,kappa_j,r,delta,alpha,A,gamma_i,agej,Jr) OLGModel10_ProgressiveIncomeTaxFn(h,aprime,a,z,e,eta1,eta2,kappa_j,r,delta,alpha,A,gamma_i,agej,Jr); % Revenue raised by the progressive income tax (needed own function to avoid log(0) causing problems) 230 | 231 | % General Equilibrium conditions (these should evaluate to zero in general equilbrium) 232 | GeneralEqmEqns.capitalmarket = @(r,K,L,alpha,delta,A) r-alpha*A*(K^(alpha-1))*(L^(1-alpha)); % interest rate equals marginal product of capital net of depreciation 233 | GeneralEqmEqns.pensions = @(PensionSpending,tau,L,r,A,alpha,delta) PensionSpending-tau*(A*(1-alpha)*((r+delta)/(alpha*A))^(alpha/(alpha-1)))*L; % Retirement benefits equal Payroll tax revenue: pension*fractionretired-tau*w*H 234 | GeneralEqmEqns.bequests = @(AccidentalBeqLeft,AccidentBeq,n) AccidentalBeqLeft/(1+n)-AccidentBeq; % Accidental bequests received equal accidental bequests left 235 | GeneralEqmEqns.Gtarget = @(G,GdivYtarget,A,K,L,alpha) G-GdivYtarget*(A*K^(alpha)*(L^(1-alpha))); % G is equal to the target, GdivYtarget*Y 236 | GeneralEqmEqns.govbudget = @(G,IncomeTaxRevenue) G-IncomeTaxRevenue; % Government budget balances (note that pensions are a seperate budget) 237 | % Note: the pensions general eqm condition looks more complicated just because we replaced w with the formula for w in terms of r. It is actually just the same formula as before. 238 | 239 | %% Test 240 | % Note: Because we used simoptions we must include this as an input 241 | disp('Test AggVars') 242 | AggVars=EvalFnOnAgentDist_AggVars_FHorz_Case1_PType(StationaryDist, Policy, FnsToEvaluate, Params, n_d, n_a, n_z,N_j,Names_i, d_grid, a_grid, z_grid_J,simoptions); 243 | 244 | %% Solve for the General Equilibrium 245 | heteroagentoptions.verbose=1; 246 | p_eqm=HeteroAgentStationaryEqm_Case1_FHorz_PType(n_d, n_a, n_z, N_j, Names_i, [], pi_z_J, d_grid, a_grid, z_grid_J,jequaloneDist, ReturnFn, FnsToEvaluate, GeneralEqmEqns, Params, DiscountFactorParamNames, AgeWeightsParamNames, PTypeDistParamNames, GEPriceParamNames,heteroagentoptions, simoptions, vfoptions); 247 | % p_eqm contains the general equilibrium parameter values 248 | % Put this into Params so we can calculate things about the initial equilibrium 249 | Params.r=p_eqm.r; 250 | Params.pension=p_eqm.pension; 251 | Params.AccidentBeq=p_eqm.AccidentBeq; 252 | Params.G=p_eqm.G; 253 | Params.eta1=p_eqm.eta1; 254 | 255 | % Calculate a few things related to the general equilibrium. 256 | [V, Policy]=ValueFnIter_Case1_FHorz_PType(n_d,n_a,n_z,N_j, Names_i, d_grid, a_grid, z_grid_J, pi_z_J, ReturnFn, Params, DiscountFactorParamNames, vfoptions); 257 | StationaryDist=StationaryDist_Case1_FHorz_PType(jequaloneDist,AgeWeightsParamNames,PTypeDistParamNames,Policy,n_d,n_a,n_z,N_j,Names_i,pi_z_J,Params,simoptions); 258 | % Can just use the same FnsToEvaluate as before. 259 | AgeConditionalStats=LifeCycleProfiles_FHorz_Case1_PType(StationaryDist,Policy,FnsToEvaluate,Params,n_d,n_a,n_z,N_j,Names_i,d_grid,a_grid,z_grid_J,simoptions); 260 | 261 | %% Plot the life cycle profiles of capital and labour for the inital and final eqm. 262 | % Note that there is the mean, and also those for each agent type 263 | % VFI Toolkit automatically gives them names ptype001, ptype002, etc. 264 | 265 | figure(1) 266 | subplot(3,1,1); plot(1:1:Params.J,AgeConditionalStats.H.Mean) 267 | hold on 268 | subplot(3,1,1); plot(1:1:Params.J,AgeConditionalStats.H.male.Mean,1:1:Params.J,AgeConditionalStats.H.female.Mean) 269 | hold off 270 | title('Life Cycle Profile: Hours Worked') 271 | legend('Average','male','female') 272 | subplot(3,1,2); plot(1:1:Params.J,AgeConditionalStats.L.Mean) 273 | hold on 274 | subplot(3,1,2); plot(1:1:Params.J,AgeConditionalStats.L.male.Mean,1:1:Params.J,AgeConditionalStats.L.female.Mean) 275 | hold off 276 | title('Life Cycle Profile: Labour Supply') 277 | subplot(3,1,3); plot(1:1:Params.J,AgeConditionalStats.K.Mean) 278 | hold on 279 | subplot(3,1,3); plot(1:1:Params.J,AgeConditionalStats.K.male.Mean,1:1:Params.J,AgeConditionalStats.K.female.Mean) 280 | hold off 281 | title('Life Cycle Profile: Assets') 282 | saveas(figure_c,'./SavedOutput/Graphs/OLGModel6_LifeCycleProfiles','pdf') 283 | 284 | %% Calculate some aggregates and print findings about them 285 | 286 | % Add consumption to the FnsToEvaluate 287 | FnsToEvaluate.Consumption=@(h,aprime,a,z,e,agej,Jr,r,gamma_i,pension,tau,kappa_j,alpha,delta,A,eta1,eta2,AccidentBeq) OLGModel10_ConsumptionFn(h,aprime,a,z,e,agej,Jr,r,gamma_i,pension,tau,kappa_j,alpha,delta,A,eta1,eta2,AccidentBeq); 288 | 289 | AggVars=EvalFnOnAgentDist_AggVars_FHorz_Case1_PType(StationaryDist, Policy, FnsToEvaluate, Params, n_d, n_a, n_z,N_j, Names_i, d_grid, a_grid, z_grid_J,simoptions); 290 | 291 | % GDP 292 | Y=Params.A*(AggVars.K.Mean^Params.alpha)*(AggVars.L.Mean^(1-Params.alpha)); 293 | 294 | % wage (note that this is calculation is only valid because we have Cobb-Douglas production function and are looking at a stationary general equilibrium) 295 | KdivL=((Params.r+Params.delta)/(Params.alpha*Params.A))^(1/(Params.alpha-1)); 296 | w=Params.A*(1-Params.alpha)*(KdivL^Params.alpha); % wage rate (per effective labour unit) 297 | 298 | fprintf('Following are some aggregates of the model economy: \n') 299 | fprintf('Output: Y=%8.2f \n',Y) 300 | fprintf('Capital-Output ratio: K/Y=%8.2f \n',AggVars.K.Mean/Y) 301 | fprintf('Consumption-Output ratio: C/Y=%8.2f \n',AggVars.Consumption.Mean/Y) 302 | fprintf('Average labor productivity: Y/H=%8.2f \n', Y/AggVars.H.Mean) 303 | fprintf('Government-to-Output ratio: G/Y=%8.2f \n', Params.G/Y) 304 | fprintf('Accidental Bequests as fraction of GDP: %8.2f \n',Params.AccidentBeq/Y) 305 | fprintf('Wage: w=%8.2f \n',w) 306 | 307 | 308 | 309 | -------------------------------------------------------------------------------- /OLGModel12.m: -------------------------------------------------------------------------------- 1 | %% OLG Model 12: Married Couples 2 | % We model a household as a married couple that has two labor supply 3 | % decisions (one for each spouse), and has two labor productivity processes 4 | % (so a deterministic age-profile, a persistent AR(1) shock, and a 5 | % transitory i.i.d. shock for each spouse). 6 | % 7 | % We essentially take OLG Model 6, and just change the household problem 8 | % (and so also the functions to evaluate). The state space now has two 9 | % decision variables, one endogenous state (asset holdings), and four 10 | % exogenous states (two markov, z, and two iid, e). 11 | 12 | %% Begin setting up to use VFI Toolkit to solve 13 | % Lets model agents from age 20 to age 100, so 81 periods 14 | 15 | Params.agejshifter=19; % Age 20 minus one. Makes keeping track of actual age easy in terms of model age 16 | Params.J=100-Params.agejshifter; % =81, Number of period in life-cycle 17 | 18 | % Grid sizes to use 19 | n_d=[11,11]; % Endogenous labour choice (fraction of time worked) 20 | n_a=301; % Endogenous asset holdings 21 | % Exogenous labor productivity units shocks (next two lines) 22 | n_z=[5,5]; % AR(1) with age-dependent params 23 | vfoptions.n_e=[3,3]; % iid 24 | N_j=Params.J; % Number of periods in finite horizon 25 | 26 | vfoptions.lowmemory=1; % The married household problem is larger, so loop over e 27 | simoptions.parallel=3; % Reduce gpu memory requirements (by using sparse cpu matrix instead of gpu matrix; by default it would be parallel=2) 28 | 29 | %% Parameters 30 | 31 | % Discount rate 32 | Params.beta = 0.96; 33 | % Preferences 34 | Params.sigma = 2; % Coeff of relative risk aversion (curvature of consumption) 35 | Params.eta = 1.5; % Curvature of leisure (This will end up being 1/Frisch elasty) 36 | Params.psi = 0; % Weight on leisure 37 | 38 | Params.A=1; % Aggregate TFP. Not actually used anywhere. 39 | % Production function 40 | Params.alpha = 0.3; % Share of capital 41 | Params.delta = 0.1; % Depreciation rate of capital 42 | 43 | % Demographics 44 | Params.agej=1:1:Params.J; % Is a vector of all the agej: 1,2,3,...,J 45 | Params.Jr=46; 46 | % Population growth rate 47 | Params.n=0.02; % percentage rate (expressed as fraction) at which population growths 48 | 49 | % Age-dependent labor productivity units (two, one for each spouse) 50 | Params.kappa_j1=[linspace(0.5,2,Params.Jr-15),linspace(2,1,14),zeros(1,Params.J-Params.Jr+1)]; 51 | Params.kappa_j2=0.9*[linspace(0.5,2,Params.Jr-15),linspace(2,1,14),zeros(1,Params.J-Params.Jr+1)]; 52 | % I am not aware of any age-dependent parameter estimates of correlated 53 | % shocks for married couples. The following are instead loosely based on Wu & Krueger (2021). 54 | Params.rho_z_married=[0.9,0;0,0.7]; 55 | Params.sigmasq_epsilon_z_married=[0.0303, 0.0027; 0.0027, 0.0382]; 56 | Params.sigma_epsilon_z_married=sqrt(Params.sigmasq_epsilon_z_married); 57 | % The Farmer-Toda method can discretize a VAR(1) with any (postivite semi-definite) variance-covariance matrix. 58 | % iid processes on idiosyncratic labor units which are correlated 59 | Params.sigmasq_epsilon_e_married=[0.1,0.05;0.05,0.1]; 60 | Params.sigma_epsilon_e_married=sqrt(Params.sigmasq_epsilon_e_married); 61 | 62 | % Conditional survival probabilities: sj is the probability of surviving to be age j+1, given alive at age j 63 | % Most countries have calculations of these (as they are used by the government departments that oversee pensions) 64 | % In fact I will here get data on the conditional death probabilities, and then survival is just 1-death. 65 | % Here I just use them for the US, taken from "National Vital Statistics Report, volume 58, number 10, March 2010." 66 | % I took them from first column (qx) of Table 1 (Total Population) 67 | % Conditional death probabilities 68 | Params.dj=[0.006879, 0.000463, 0.000307, 0.000220, 0.000184, 0.000172, 0.000160, 0.000149, 0.000133, 0.000114, 0.000100, 0.000105, 0.000143, 0.000221, 0.000329, 0.000449, 0.000563, 0.000667, 0.000753, 0.000823,... 69 | 0.000894, 0.000962, 0.001005, 0.001016, 0.001003, 0.000983, 0.000967, 0.000960, 0.000970, 0.000994, 0.001027, 0.001065, 0.001115, 0.001154, 0.001209, 0.001271, 0.001351, 0.001460, 0.001603, 0.001769, 0.001943, 0.002120, 0.002311, 0.002520, 0.002747, 0.002989, 0.003242, 0.003512, 0.003803, 0.004118, 0.004464, 0.004837, 0.005217, 0.005591, 0.005963, 0.006346, 0.006768, 0.007261, 0.007866, 0.008596, 0.009473, 0.010450, 0.011456, 0.012407, 0.013320, 0.014299, 0.015323,... 70 | 0.016558, 0.018029, 0.019723, 0.021607, 0.023723, 0.026143, 0.028892, 0.031988, 0.035476, 0.039238, 0.043382, 0.047941, 0.052953, 0.058457, 0.064494,... 71 | 0.071107, 0.078342, 0.086244, 0.094861, 0.104242, 0.114432, 0.125479, 0.137427, 0.150317, 0.164187, 0.179066, 0.194979, 0.211941, 0.229957, 0.249020, 0.269112, 0.290198, 0.312231, 1.000000]; 72 | % dj covers Ages 0 to 100 73 | Params.sj=1-Params.dj(21:101); % Conditional survival probabilities 74 | Params.sj(end)=0; % In the present model the last period (j=J) value of sj is actually irrelevant 75 | 76 | % Warm glow of bequest 77 | Params.warmglow1=0.3; % (relative) importance of bequests 78 | Params.warmglow2=3; % bliss point of bequests (essentially, the target amount) 79 | Params.warmglow3=Params.sigma; % By using the same curvature as the utility of consumption it makes it much easier to guess appropraite parameter values for the warm glow 80 | 81 | % Taxes 82 | Params.tau = 0.15; % Tax rate on labour income 83 | % In addition to payroll tax rate tau, which funds the pension system we will add a progressive 84 | % income tax which funds government spending. 85 | % The progressive income tax takes the functional form: 86 | % IncomeTax=eta1+eta2*log(Income)*Income; % This functional form is empirically a decent fit for the US tax system 87 | % And is determined by the two parameters 88 | Params.eta1=0.09; % eta1 will be determined in equilibrium to balance gov budget constraint 89 | Params.eta2=0.053; 90 | 91 | % Government spending 92 | Params.GdivYtarget = 0.15; % Government spending as a fraction of GDP (this is essentially just used as a target to define a general equilibrium condition) 93 | 94 | %% Some initial values/guesses for variables that will be determined in general eqm 95 | Params.r=0.16; 96 | Params.pension=2; % Initial guess (this will be determined in general eqm) 97 | Params.AccidentBeq=0.07; % Accidental bequests (this is the lump sum transfer) 98 | Params.G=0.5; % Government expenditure 99 | Params.eta1=0.51; 100 | % Params.eta1=0.09; % already set above 101 | 102 | %% Grids 103 | a_grid=10*(linspace(0,1,n_a).^3)'; % The ^3 means most points are near zero, which is where the derivative of the value fn changes most. 104 | 105 | % First, the AR(1) process on z1 and z2 with correlated innovations. 106 | % Notice that this is just a VAR(1) process on z1 and z2 (with zeros on the off-diagonals of the auto-correlation matrix) 107 | % We use the Farmer-Toda method to discretize the VAR(1) 108 | % Note that for VAR(1), the Farmer-Toda method produces a 'joint grid' 109 | [z_grid, pi_z]=discretizeVAR1_FarmerToda([0;0],Params.rho_z_married,Params.sigma_epsilon_z_married,n_z); 110 | 111 | % Second, the iid process on e1 and e2 which are correlated 112 | % Notice that this is just a VAR(1) with zero auto-correlation 113 | [e_grid, pi_e]=discretizeVAR1_FarmerToda(zeros(2,1),zeros(2,2),Params.sigma_epsilon_e_married,vfoptions.n_e); 114 | pi_e=pi_e(1,:)'; % Because it is iid, the distribution is just the first row (all rows are identical). We use pi_e as a column vector for VFI Toolkit to handle iid variables. 115 | 116 | % To use e variables we need to put them in vfoptions and simoptions 117 | vfoptions.e_grid=e_grid; 118 | vfoptions.pi_e=pi_e; 119 | simoptions.n_e=vfoptions.n_e; 120 | simoptions.e_grid=vfoptions.e_grid; 121 | simoptions.pi_e=vfoptions.pi_e; 122 | % (Because z_grid does not depend on age we do not need to put it into vfoptions and simoptions) 123 | 124 | % Grid for labour choice 125 | h1_grid=linspace(0,1,n_d(1))'; % Notice that it is imposing the 0<=h1<=1 condition implicitly 126 | h2_grid=linspace(0,1,n_d(2))'; % Notice that it is imposing the 0<=h2<=1 condition implicitly 127 | % Switch into toolkit notation 128 | d_grid=[h1_grid; h2_grid]; 129 | 130 | %% Now, create the return function 131 | DiscountFactorParamNames={'beta','sj'}; 132 | 133 | % Notice we use 'OLGModel12_ReturnFn' 134 | ReturnFn=@(h1,h2,aprime,a,z1,z2,e1,e2,sigma,psi,eta,agej,Jr,J,pension,r,kappa_j1,kappa_j2,A,alpha,delta,eta1,eta2,warmglow1,warmglow2,AccidentBeq,tau)... 135 | OLGModel12_ReturnFn(h1,h2,aprime,a,z1,z2,e1,e2,sigma,psi,eta,agej,Jr,J,pension,r,kappa_j1,kappa_j2,A,alpha,delta,eta1,eta2,warmglow1,warmglow2,AccidentBeq,tau); 136 | 137 | %% Now solve the value function iteration problem, just to check that things are working before we go to General Equilbrium 138 | disp('Test ValueFnIter') 139 | tic; 140 | % Note: z_grid and pi_z, this will be ignored due to presence of vfoptions.z_grid_J and vfoptions.pi_z_J 141 | [V, Policy]=ValueFnIter_Case1_FHorz(n_d,n_a,n_z,N_j, d_grid, a_grid, z_grid, pi_z, ReturnFn, Params, DiscountFactorParamNames, [], vfoptions); 142 | toc 143 | 144 | %% Initial distribution of agents at birth (j=1) 145 | % Before we plot the life-cycle profiles we have to define how agents are 146 | % at age j=1. We will give them all zero assets. 147 | jequaloneDist=zeros([n_a,n_z,vfoptions.n_e],'gpuArray'); % Put no households anywhere on grid 148 | jequaloneDist(1,floor((n_z(1)+1)/2),floor((n_z(2)+1)/2),floor((simoptions.n_e(1)+1)/2),floor((simoptions.n_e(2)+1)/2))=1; % All agents start with zero assets, and the median shock 149 | 150 | %% Agents age distribution 151 | % Many OLG models include some kind of population growth, and perhaps 152 | % some other things that create a weighting of different ages that needs to 153 | % be used to calculate the stationary distribution and aggregate variable. 154 | % Many OLG models include some kind of population growth, and perhaps 155 | % some other things that create a weighting of different ages that needs to 156 | % be used to calculate the stationary distribution and aggregate variable. 157 | Params.mewj=ones(1,Params.J); % Marginal distribution of households over age 158 | for jj=2:length(Params.mewj) 159 | Params.mewj(jj)=Params.sj(jj-1)*Params.mewj(jj-1)/(1+Params.n); 160 | end 161 | Params.mewj=Params.mewj./sum(Params.mewj); % Normalize to one 162 | 163 | AgeWeightsParamNames={'mewj'}; % So VFI Toolkit knows which parameter is the mass of agents of each age 164 | 165 | %% Test 166 | disp('Test StationaryDist') 167 | StationaryDist=StationaryDist_FHorz_Case1(jequaloneDist,AgeWeightsParamNames,Policy,n_d,n_a,n_z,N_j,pi_z,Params,simoptions); 168 | 169 | %% General eqm variables 170 | GEPriceParamNames={'r','pension','AccidentBeq','G','eta1'}; 171 | 172 | %% Set up the General Equilibrium conditions (on assets/interest rate, assuming a representative firm with Cobb-Douglas production function) 173 | % Note: we need to add both of each of the z & e to FnsToEvaluate inputs. 174 | 175 | % Stationary Distribution Aggregates (important that ordering of Names and Functions is the same) 176 | FnsToEvaluate.H = @(h1,h2,aprime,a,z1,z2,e1,e2) h1+h2; % Aggregate 'hours worked' 177 | FnsToEvaluate.L = @(h1,h2,aprime,a,z1,z2,e1,e2,kappa_j1,kappa_j2) kappa_j1*exp(z1+e1)*h1+kappa_j2*exp(z2+e2)*h2; % Aggregate labour supply in efficiency units 178 | FnsToEvaluate.K = @(h1,h2,aprime,a,z1,z2,e1,e2) a;% Aggregate physical capital 179 | FnsToEvaluate.PensionSpending = @(h1,h2,aprime,a,z1,z2,e1,e2,pension,agej,Jr) (agej>=Jr)*pension; % Total spending on pensions 180 | FnsToEvaluate.AccidentalBeqLeft = @(h1,h2,aprime,a,z1,z2,e1,e2,sj) aprime*(1-sj); % Accidental bequests left by people who die 181 | FnsToEvaluate.IncomeTaxRevenue = @(h1,h2,aprime,a,z1,z2,e1,e2,agej,Jr,r,kappa_j1,kappa_j2,A,alpha,delta,eta1,eta2) OLGModel12_ProgressiveIncomeTaxFn(h1,h2,aprime,a,z1,z2,e1,e2,agej,Jr,r,kappa_j1,kappa_j2,A,alpha,delta,eta1,eta2); % Revenue raised by the progressive income tax (needed own function to avoid log(0) causing problems) 182 | 183 | % General Equilibrium conditions (these should evaluate to zero in general equilbrium) 184 | GeneralEqmEqns.capitalmarket = @(r,K,L,alpha,delta,A) r-alpha*A*(K^(alpha-1))*(L^(1-alpha)); % interest rate equals marginal product of capital net of depreciation 185 | GeneralEqmEqns.pensions = @(PensionSpending,tau,L,r,A,alpha,delta) PensionSpending-tau*(A*(1-alpha)*((r+delta)/(alpha*A))^(alpha/(alpha-1)))*L; % Retirement benefits equal Payroll tax revenue: pension*fractionretired-tau*w*H 186 | GeneralEqmEqns.bequests = @(AccidentalBeqLeft,AccidentBeq,n) AccidentalBeqLeft/(1+n)-AccidentBeq; % Accidental bequests received equal accidental bequests left 187 | GeneralEqmEqns.Gtarget = @(G,GdivYtarget,A,K,L,alpha) G-GdivYtarget*(A*K^(alpha)*(L^(1-alpha))); % G is equal to the target, GdivYtarget*Y 188 | GeneralEqmEqns.govbudget = @(G,IncomeTaxRevenue) G-IncomeTaxRevenue; % Government budget balances (note that pensions are a seperate budget) 189 | % Note: the pensions general eqm condition looks more complicated just because we replaced w with the formula for w in terms of r. It is actually just the same formula as before. 190 | 191 | %% Test 192 | % Note: Because we used simoptions we must include this as an input 193 | disp('Test AggVars') 194 | AggVars=EvalFnOnAgentDist_AggVars_FHorz_Case1(StationaryDist, Policy, FnsToEvaluate, Params, [], n_d, n_a, n_z,N_j, d_grid, a_grid, z_grid,[],simoptions); 195 | 196 | %% Solve for the General Equilibrium 197 | heteroagentoptions.verbose=1; 198 | p_eqm=HeteroAgentStationaryEqm_Case1_FHorz(jequaloneDist,AgeWeightsParamNames,n_d, n_a, n_z, N_j, 0, pi_z, d_grid, a_grid, z_grid, ReturnFn, FnsToEvaluate, GeneralEqmEqns, Params, DiscountFactorParamNames, [], [], [], GEPriceParamNames, heteroagentoptions, simoptions, vfoptions); 199 | % p_eqm contains the general equilibrium parameter values 200 | % Put this into Params so we can calculate things about the initial equilibrium 201 | Params.r=p_eqm.r; 202 | Params.pension=p_eqm.pension; 203 | Params.AccidentBeq=p_eqm.AccidentBeq; 204 | Params.G=p_eqm.G; 205 | Params.eta1=p_eqm.eta1; 206 | 207 | % Add fraction of time worked for each spouse to FnsToEvaluate 208 | FnsToEvaluate.H1 = @(h1,h2,aprime,a,z1,z2,e1,e2) h1; % hours worked of first spouse 209 | FnsToEvaluate.H2 = @(h1,h2,aprime,a,z1,z2,e1,e2) h2; % hours worked of second spouse 210 | 211 | % Calculate a few things related to the general equilibrium. 212 | [V, Policy]=ValueFnIter_Case1_FHorz(n_d,n_a,n_z,N_j, d_grid, a_grid, z_grid, pi_z, ReturnFn, Params, DiscountFactorParamNames, [], vfoptions); 213 | StationaryDist=StationaryDist_FHorz_Case1(jequaloneDist,AgeWeightsParamNames,Policy,n_d,n_a,n_z,N_j,pi_z,Params,simoptions); 214 | % Can just use the same FnsToEvaluate as before. 215 | AgeConditionalStats=LifeCycleProfiles_FHorz_Case1(StationaryDist,Policy,FnsToEvaluate,Params,[],n_d,n_a,n_z,N_j,d_grid,a_grid,z_grid,simoptions); 216 | 217 | %% Plot the life cycle profiles of capital and labour for the inital and final eqm. 218 | 219 | % figure(1) 220 | % subplot(4,1,1); plot(1:1:Params.J,AgeConditionalStats.H.Mean) 221 | % title('Life Cycle Profile: Hours Worked') 222 | % subplot(4,1,2); plot(1:1:Params.J,AgeConditionalStats.L.Mean) 223 | % title('Life Cycle Profile: Labour Supply of household') 224 | % subplot(4,1,3); plot(1:1:Params.J,AgeConditionalStats.H1.Mean,1:1:Params.J,AgeConditionalStats.H2.Mean) 225 | % title('Life Cycle Profile: Fraction of time worked, of each spouse') 226 | % legend('First spouse','Second spouse') 227 | % subplot(4,1,4); plot(1:1:Params.J,AgeConditionalStats.K.Mean) 228 | % title('Life Cycle Profile: Assets') 229 | % saveas(figure_c,'./SavedOutput/Graphs/OLGModel6_LifeCycleProfiles','pdf') 230 | 231 | %% Calculate some aggregates and print findings about them 232 | 233 | % Add consumption to the FnsToEvaluate 234 | FnsToEvaluate.Consumption=@(h1,h2,aprime,a,z1,z2,e1,e2,agej,Jr,pension,r,kappa_j1,kappa_j2,A,alpha,delta,eta1,eta2,tau,AccidentBeq) OLGModel12_ConsumptionFn(h1,h2,aprime,a,z1,z2,e1,e2,agej,Jr,pension,r,kappa_j1,kappa_j2,A,alpha,delta,eta1,eta2,tau,AccidentBeq); 235 | 236 | AggVars=EvalFnOnAgentDist_AggVars_FHorz_Case1(StationaryDist, Policy, FnsToEvaluate, Params, [], n_d, n_a, n_z,N_j, d_grid, a_grid, z_grid,[],simoptions); 237 | 238 | % GDP 239 | Y=Params.A*(AggVars.K.Mean^Params.alpha)*(AggVars.L.Mean^(1-Params.alpha)); 240 | 241 | % wage (note that this is calculation is only valid because we have Cobb-Douglas production function and are looking at a stationary general equilibrium) 242 | KdivL=((Params.r+Params.delta)/(Params.alpha*Params.A))^(1/(Params.alpha-1)); 243 | w=Params.A*(1-Params.alpha)*(KdivL^Params.alpha); % wage rate (per effective labour unit) 244 | 245 | fprintf('Following are some aggregates of the model economy: \n') 246 | fprintf('Output: Y=%8.2f \n',Y) 247 | fprintf('Capital-Output ratio: K/Y=%8.2f \n',AggVars.K.Mean/Y) 248 | fprintf('Consumption-Output ratio: C/Y=%8.2f \n',AggVars.Consumption.Mean/Y) 249 | fprintf('Average labor productivity: Y/H=%8.2f \n', Y/AggVars.H.Mean) 250 | fprintf('Government-to-Output ratio: G/Y=%8.2f \n', Params.G/Y) 251 | fprintf('Accidental Bequests as fraction of GDP: %8.2f \n',Params.AccidentBeq/Y) 252 | fprintf('Wage: w=%8.2f \n',w) 253 | 254 | 255 | 256 | -------------------------------------------------------------------------------- /OLGModel12_ConsumptionFn.m: -------------------------------------------------------------------------------- 1 | function c=OLGModel12_ConsumptionFn(h1,h2,aprime,a,z1,z2,e1,e2,agej,Jr,pension,r,kappa_j1,kappa_j2,A,alpha,delta,eta1,eta2,tau,AccidentBeq) 2 | 3 | KdivL=((r+delta)/(alpha*A))^(1/(alpha-1)); 4 | w=A*(1-alpha)*(KdivL^alpha); % wage rate (per effective labour unit) 5 | 6 | % Progressive income tax 7 | if agej0 14 | IncomeTax=eta1+eta2*log(Income)*Income; 15 | end 16 | % Note: Have made pensions exempt from income tax. 17 | 18 | 19 | F=-Inf; 20 | if agej0 14 | IncomeTax=eta1+eta2*log(Income)*Income; 15 | end 16 | % Note: Have made pensions exempt from income tax. 17 | 18 | end -------------------------------------------------------------------------------- /OLGModel12_ReturnFn.m: -------------------------------------------------------------------------------- 1 | function F=OLGModel12_ReturnFn(h1,h2,aprime,a,z1,z2,e1,e2,sigma,psi,eta,agej,Jr,J,pension,r,kappa_j1,kappa_j2,A,alpha,delta,eta1,eta2,warmglow1,warmglow2,AccidentBeq,tau) 2 | % The first seven are the 'always required' decision variables, next period 3 | % endogenous states, this period endogenous states, exogenous states 4 | % After that we need all the parameters the return function uses, it 5 | % doesn't matter what order we put them here. 6 | 7 | 8 | KdivL=((r+delta)/(alpha*A))^(1/(alpha-1)); 9 | w=A*(1-alpha)*(KdivL^alpha); % wage rate (per effective labour unit) 10 | 11 | % Progressive income tax 12 | if agej0 19 | IncomeTax=eta1+eta2*log(Income)*Income; 20 | end 21 | % Note: Have made pensions exempt from income tax. 22 | 23 | 24 | F=-Inf; 25 | if agej0 32 | F=(c^(1-sigma))/(1-sigma) -psi*(h1^(1+eta))/(1+eta)-psi*(h2^(1+eta))/(1+eta); % The utility function 33 | end 34 | 35 | % Warm-glow bequest 36 | if agej==J % Final period 37 | warmglow=warmglow1*(aprime^(1-warmglow2))/(1-warmglow2); 38 | F=F+warmglow; 39 | end 40 | % Notice that we have modelled the warm-glow in such a way that you only 41 | % get it if you die in the last period (j=J). But we know there is a 1-sj 42 | % risk of dying every period. So we might prefer to model that we get the 43 | % warm glow bequest if we die at any age. The following commented out two lines 44 | % implement this alternative. [note: need to add sj to inputs of ReturnFn to use it] 45 | % warmglow=warmglowparam1*(aprime^(1-warmglowparam2))/(1-warmglowparam2); % Note: same formula as above 46 | % F=F+(1-sj)*warmglow 47 | % Note: if using this, have to make sure sj=0 for j=J. 48 | % Comment: I am not aware of any study saying which of these two 49 | % alternatives works better empirically. 50 | 51 | 52 | end 53 | -------------------------------------------------------------------------------- /OLGModel14_FirmCorporateTaxRevenue.m: -------------------------------------------------------------------------------- 1 | function revenue=OLGModel14_FirmCorporateTaxRevenue(dividend,kprime,k,z,w,delta,alpha_k,alpha_l,capadjconstant,tau_corp,phi) 2 | % Whether we set it up so that dividends or equity issuance is the decision 3 | % variable is unimportant, here I use dividends as the decision variable. 4 | 5 | % Note: r is not needed anywhere here, it is relevant to the firm via the discount factor. 6 | 7 | % We can solve a static problem to get the firm labor input 8 | l=(w/(alpha_l*z*(k^alpha_k)))^(1/(alpha_l-1)); % This is just w=Marg. Prod. Labor, but rearranged 9 | 10 | % Output 11 | y=z*(k^alpha_k)*(l^alpha_l); 12 | 13 | % Profit 14 | profit=y-w*l; 15 | 16 | % Investment 17 | invest=kprime-(1-delta)*k; 18 | 19 | % Capital-adjustment costs 20 | capitaladjcost=(capadjconstant/2)*((invest/k-delta)^2) *k; 21 | 22 | % Taxable corporate income 23 | T=profit-delta*k-phi*capitaladjcost; 24 | % -delta*k: investment expensing 25 | % phi is the fraction of capitaladjcost that can be deducted from corporate taxes 26 | 27 | revenue=tau_corp*T; 28 | 29 | end 30 | -------------------------------------------------------------------------------- /OLGModel14_FirmReturnFn.m: -------------------------------------------------------------------------------- 1 | function F=OLGModel14_FirmReturnFn(dividend,kprime,k,z,w,delta,alpha_k,alpha_l,capadjconstant,tau_corp,phi,tau_d,tau_cg) 2 | % Whether we set it up so that dividends or equity issuance is the decision 3 | % variable is unimportant, here I use dividends as the decision variable. 4 | 5 | % Note: r is not needed anywhere here, it is relevant to the firm via the discount factor. 6 | 7 | F=-Inf; 8 | 9 | % We can solve a static problem to get the firm labor input 10 | l=(w/(alpha_l*z*(k^alpha_k)))^(1/(alpha_l-1)); % This is just w=Marg. Prod. Labor, but rearranged 11 | 12 | % Output 13 | y=z*(k^alpha_k)*(l^alpha_l); 14 | 15 | % Profit 16 | profit=y-w*l; 17 | 18 | % Investment 19 | invest=kprime-(1-delta)*k; 20 | 21 | % Capital-adjustment costs 22 | capitaladjcost=(capadjconstant/2)*((invest/k-delta)^2) *k; 23 | 24 | % Taxable corporate income 25 | T=profit-delta*k-phi*capitaladjcost; 26 | % -delta*k: investment expensing 27 | % phi is the fraction of capitaladjcost that can be deducted from corporate taxes 28 | 29 | % Firms financing constraint gives the new equity issuance 30 | s=dividend+invest+capitaladjcost-(profit-tau_corp*T); 31 | 32 | % Firms per-period objective 33 | if s>=0 % enforce that 'no share repurchases allowed' 34 | F=((1-tau_d)/(1-tau_cg))*dividend-s; 35 | end 36 | 37 | % Note: dividend payments cannot be negative is enforced by the grid on 38 | % dividends which has a minimum value of zero 39 | 40 | end 41 | -------------------------------------------------------------------------------- /OLGModel14_FirmShareIssuance.m: -------------------------------------------------------------------------------- 1 | function s=OLGModel14_FirmShareIssuance(dividend,kprime,k,z,w,delta,alpha_k,alpha_l,capadjconstant,tau_corp,phi) 2 | % Whether we set it up so that dividends or equity issuance is the decision 3 | % variable is unimportant, here I use dividends as the decision variable. 4 | 5 | % Note: r is not needed anywhere here, it is relevant to the firm via the discount factor. 6 | 7 | % We can solve a static problem to get the firm labor input 8 | l=(w/(alpha_l*z*(k^alpha_k)))^(1/(alpha_l-1)); % This is just w=Marg. Prod. Labor, but rearranged 9 | 10 | % Output 11 | y=z*(k^alpha_k)*(l^alpha_l); 12 | 13 | % Profit 14 | profit=y-w*l; 15 | 16 | % Investment 17 | invest=kprime-(1-delta)*k; 18 | 19 | % Capital-adjustment costs 20 | capitaladjcost=(capadjconstant/2)*((invest/k-delta)^2) *k; 21 | 22 | % Taxable corporate income 23 | T=profit-delta*k-phi*capitaladjcost; 24 | % -delta*k: investment expensing 25 | % phi is the fraction of capitaladjcost that can be deducted from corporate taxes 26 | 27 | % Firms financing constraint gives the new equity issuance 28 | s=dividend+invest+capitaladjcost-(profit-tau_corp*T); 29 | 30 | end 31 | -------------------------------------------------------------------------------- /OLGModel14_HouseholdConsumptionFn.m: -------------------------------------------------------------------------------- 1 | function c=OLGModel14_HouseholdConsumptionFn(h,sprime,s,z,e,agej,Jr,pension,r,w,P0,D,kappa_j,AccidentBeq,tau_l,tau_d,tau_cg,Lhscale) 2 | % Replace assets with 'share holdings' 3 | % Get rid of progressive taxes 4 | % Add Lhnormalize 5 | 6 | % We can get P from the equation that defines r as the return to the mutual fund 7 | % 1+r = (P0 +(1-tau_d)D - tau_cg(P0-P))/Plag 8 | % We are looking at stationary general eqm, so 9 | % Plag=P; 10 | % And thus we have 11 | P=((1-tau_cg)*P0 + (1-tau_d)*D)/(1+r-tau_cg); 12 | 13 | Plag=P; % As stationary general eqm 14 | 15 | F=-Inf; 16 | if agej=0 is being implicitly imposed by grid on s 24 | 25 | end 26 | -------------------------------------------------------------------------------- /OLGModel14_HouseholdIncomeFn.m: -------------------------------------------------------------------------------- 1 | function income=OLGModel14_HouseholdIncomeFn(h,sprime,s,z,e,agej,Jr,pension,r,w,P0,D,kappa_j,AccidentBeq,tau_l,tau_d,tau_cg,Lhscale) 2 | % Replace assets with 'share holdings' 3 | % Get rid of progressive taxes 4 | % Add Lhnormalize 5 | 6 | % We can get P from the equation that defines r as the return to the mutual fund 7 | % 1+r = (P0 +(1-tau_d)D - tau_cg(P0-P))/Plag 8 | % We are looking at stationary general eqm, so 9 | % Plag=P; 10 | % And thus we have 11 | P=((1-tau_cg)*P0 + (1-tau_d)*D)/(1+r-tau_cg); 12 | 13 | Plag=P; % As stationary general eqm 14 | 15 | if agej=0 is being implicitly imposed by grid on s 24 | 25 | end 26 | -------------------------------------------------------------------------------- /OLGModel14_HouseholdReturnFn.m: -------------------------------------------------------------------------------- 1 | function F=OLGModel14_HouseholdReturnFn(h,sprime,s,z,e,sigma,psi,eta,agej,Jr,J,pension,r,w,P0,D,kappa_j,warmglow1,warmglow2,AccidentBeq,tau_l,tau_d,tau_cg,Lhscale) 2 | % Replace assets with 'share holdings' 3 | % Get rid of progressive taxes 4 | % Add Lhnormalize 5 | 6 | % We can get P from the equation that defines r as the return to the mutual fund 7 | % 1+r = (P0 +(1-tau_d)D - tau_cg(P0-P))/Plag 8 | % We are looking at stationary general eqm, so 9 | % Plag=P; 10 | % And thus we have 11 | P=((1-tau_cg)*P0 + (1-tau_d)*D)/(1+r-tau_cg); 12 | 13 | Plag=P; % As stationary general eqm 14 | 15 | F=-Inf; 16 | if agej0 24 | F=(c^(1-sigma))/(1-sigma) -psi*(h^(1+eta))/(1+eta); % The utility function 25 | end 26 | 27 | % Warm-glow bequest 28 | if agej==J % Final period 29 | warmglow=warmglow1*(sprime^(1-warmglow2))/(1-warmglow2); 30 | F=F+warmglow; 31 | end 32 | 33 | % Notice that sprime>=0 is being implicitly imposed by grid on s 34 | 35 | end 36 | -------------------------------------------------------------------------------- /OLGModel1_ReturnFn.m: -------------------------------------------------------------------------------- 1 | function F=OLGModel1_ReturnFn(h,aprime,a,agej,w,sigma,psi,eta,Jr,pension,tau) 2 | 3 | F=-Inf; 4 | 5 | if agej0 12 | F=(c^(1-sigma))/(1-sigma) -psi*(h^(1+eta))/(1+eta); 13 | end 14 | 15 | end 16 | -------------------------------------------------------------------------------- /OLGModel2.m: -------------------------------------------------------------------------------- 1 | %% OLG Model 2: use tax to fund pensions 2 | % In the first model households received pensions which simply 'fall from the sky' in the sense 3 | % that there was no government/tax to fund the pensions. 4 | % In the second model we will add a tax to fund pensions. 5 | % 6 | % The model already included a tax rate "tau" which was set equal to zero. 7 | % We will now consider tau as something to be determined in general 8 | % equilibrium based on the tax revenue of tau being enough to pay for the 9 | % pensions (that the pension system runs a balanced budget). 10 | 11 | %% Begin setting up to use VFI Toolkit to solve 12 | % Lets model agents from age 20 to age 100, so 81 periods 13 | 14 | Params.agejshifter=19; % Age 20 minus one. Makes keeping track of actual age easy in terms of model age 15 | Params.J=100-Params.agejshifter; % =81, Number of period in life-cycle 16 | 17 | % Grid sizes to use 18 | n_d=101; % Endogenous labour choice (fraction of time worked) 19 | n_a=1; 20 | n_z=0; % This is how the VFI Toolkit thinks about deterministic models 21 | N_j=Params.J; % Number of periods in finite horizon 22 | 23 | figure_c=0; % I like to use a counter for the figures. Makes it easier to keep track of them when editing. 24 | 25 | %% Parameters 26 | 27 | % Discount rate 28 | Params.beta = 0.99; 29 | % Preferences 30 | Params.sigma = 2; % Coeff of relative risk aversion (curvature of consumption) 31 | Params.eta = 1.5; % Curvature of leisure (This will end up being 1/Frisch elasty) 32 | Params.psi = 10; % Weight on leisure 33 | 34 | Params.A=1; % Aggregate TFP. Not actually used anywhere. 35 | % Production function 36 | Params.alpha = 0.3; % Share of capital 37 | Params.delta = 0.1; % Depreciation rate of capital 38 | 39 | % Demographics 40 | Params.Jr=67-Params.agejshifter; % Retirement age is 67 (remember j=1 is age 20) (You work when younger, not working from Jr on) 41 | Params.agej=(1:1:Params.J)'; % Current 'j' age, so can check when you retire. 42 | 43 | % The amount of pension that retirees receive 44 | Params.pension=0.3; 45 | 46 | %% Some initial values/guesses for variables that will be determined in general eqm 47 | Params.tau=0.1; % Initial guess (this will be determined in general eqm) 48 | Params.w=1; 49 | 50 | %% Grids 51 | % While there are no 'a' for 'z' in this model, VFI Toolkit requires them 52 | % to figure out what is going on. By making them just a single grid point, 53 | % and then not using them anywhere, we are essentially solving a model without them. 54 | a_grid=1; 55 | z_grid=1; % Note: n_z=0 means that z_grid and pi_z will be ignored, but we still need them as inputs to various commands 56 | pi_z=1; 57 | 58 | % Grid for labour choice 59 | h_grid=linspace(0,1,n_d)'; 60 | % Switch into toolkit notation 61 | d_grid=h_grid; 62 | 63 | %% Now, create the return function 64 | DiscountFactorParamNames={'beta'}; 65 | 66 | % Note: the following return function actually includes 'assets', but since 67 | % this very basic model has only one possible value for assets this ends up 68 | % irrelevant (VFI Toolkit is not really designed for models this simple with no endogenous state so it looks like it is just overkill when used to solve them). 69 | ReturnFn=@(h,aprime,a,agej,w,sigma,psi,eta,Jr,pension,tau)... 70 | OLGModel1_ReturnFn(h,aprime,a,agej,w,sigma,psi,eta,Jr,pension,tau); 71 | 72 | %% Now solve the value function iteration problem, just to check that things are working before we go to General Equilbrium 73 | disp('Test ValueFnIter') 74 | vfoptions=struct(); % Just using the defaults. 75 | tic; 76 | [V, Policy]=ValueFnIter_Case1_FHorz(n_d,n_a,n_z,N_j, d_grid, a_grid, z_grid, pi_z, ReturnFn, Params, DiscountFactorParamNames, [], vfoptions); 77 | toc 78 | 79 | %% Initial distribution of agents at birth (j=1) 80 | jequaloneDist=1; % n_a by n_z, but in current setup this is just 1-by-1 in anycase so 'everyone' is going to have to be born here. 81 | 82 | %% Agents age distribution 83 | % Many OLG models include some kind of population growth, and perhaps 84 | % some other things that create a weighting of different ages that needs to 85 | % be used to calculate the stationary distribution and aggregate variable. 86 | % This toy model does not have population growth, but there will be 87 | % different fractions of households of each age due to the probability of dying. 88 | % This toy model does not. 89 | Params.mewj=ones(1,Params.J)/Params.J; % This is the Marginal distribution of households over age 90 | % Agents are evenly spread across all ages. 91 | 92 | AgeWeightsParamNames={'mewj'}; % Many finite horizon models apply different weights to different 'ages'; eg., due to survival rates or population growth rates. 93 | 94 | %% Test 95 | disp('Test StationaryDist') 96 | simoptions=struct(); % Just use the defaults 97 | tic; 98 | StationaryDist=StationaryDist_FHorz_Case1(jequaloneDist,AgeWeightsParamNames,Policy,n_d,n_a,n_z,N_j,pi_z,Params,simoptions); 99 | toc 100 | 101 | %% Everything until this point is just the same as for Life-Cycle Models 102 | % For OLG models we need to add a few things 103 | % 1) GEPriceParamNames: the names of the parameters/prices to be determined in general equilibrium 104 | % 2) FnsToEvaluate: these are same as in Life-Cycle models 105 | % 3) GeneralEqmEqns: the general equilibrium equations, these will be equal to zero in general equilibrium 106 | % they take any price/parameter as inputs, and also any FnsToEvaluate as inputs 107 | % 4) That is it for set up, now just use HeteroAgentStationaryEqm_Case1_FHorz() command to solve for the general equilibrium 108 | % 5) p_eqm contains the general equilibrium values of parameters/prices determined in general 109 | % equilibrium, we can put these in Params and then just calculate anything like value 110 | % function, agent stationary distribution, life-cycle profiles, etc., as normal. 111 | 112 | %% General eqm variables 113 | GEPriceParamNames={'w','tau'}; 114 | 115 | %% Set up the General Equilibrium conditions (on assets/interest rate, assuming a representative firm with Cobb-Douglas production function) 116 | 117 | % Stationary Distribution Aggregates (important that ordering of Names and Functions is the same) 118 | FnsToEvaluate.L = @(h,aprime,a) h; % Aggregate labour supply 119 | % This version of the model is simple enough that tax revenues and pension expenditures can all just be calculated 'directly'. 120 | 121 | % General Equilibrium conditions (these should evaluate to zero in general equilbrium) 122 | GeneralEqmEqns.labormarket = @(w,alpha,L,A) w-(1-alpha)*A*L^(-alpha); % wage equals marginal product of labour 123 | GeneralEqmEqns.pensionbalance = @(pension,L,J,Jr,tau,w) pension*((J-Jr)/J)-tau*w*L; % Retirement benefits equal Payroll tax revenue: pension*fractionretired-tau*w*H 124 | % Note: Inputs to general equilibrium conditions must be either aggregate variables or parameters 125 | 126 | %% Test 127 | disp('Test AggVars') 128 | AggVars=EvalFnOnAgentDist_AggVars_FHorz_Case1(StationaryDist, Policy, FnsToEvaluate, Params, [], n_d, n_a, n_z,N_j, d_grid, a_grid, z_grid); 129 | 130 | % Advanced: If you did want to test the GeneralEqmEqns to makes sure they are doing what you expect the following commented out lines show how 131 | % % % To be able to test the general equilibrium conditions you need to add the aggregate variables into Params 132 | % % AggVarNames=fieldnames(AggVars); 133 | % % for ii=1:length(AggVarNames) 134 | % % Params.(AggVarNames{ii})=AggVars.(AggVarNames{ii}).Mean; 135 | % % end 136 | % % GeneralEqmConditionsVec=real(GeneralEqmConditions_Case1_v2(GeneralEqmEqns,Params, 2)); 137 | 138 | %% Solve for the General Equilibrium 139 | % Use the toolkit to find the equilibrium price index. 140 | % In what follows I use the (default) 'search' approach to calculate the General equilibrium. 141 | 142 | heteroagentoptions.verbose=1; 143 | p_eqm=HeteroAgentStationaryEqm_Case1_FHorz(jequaloneDist,AgeWeightsParamNames,n_d, n_a, n_z, N_j, 0, pi_z, d_grid, a_grid, z_grid, ReturnFn, FnsToEvaluate, GeneralEqmEqns, Params, DiscountFactorParamNames, [], [], [], GEPriceParamNames, heteroagentoptions, simoptions, vfoptions); 144 | 145 | %% p_eqm contains the general equilibrium 'prices', to calculate things about the model 146 | % economy in general equilibrium we must put these in Params, and then use them as standard. 147 | 148 | % p_eqm contains the general equilibrium parameter values 149 | % Put this into Params so we can calculate things about the general equilibrium 150 | Params.w=p_eqm.w; 151 | Params.tau=p_eqm.tau; 152 | 153 | % Calculate a few things related to the general equilibrium. 154 | [V, Policy]=ValueFnIter_Case1_FHorz(n_d,n_a,n_z,N_j, d_grid, a_grid, z_grid, pi_z, ReturnFn, Params, DiscountFactorParamNames, [], vfoptions); 155 | StationaryDist=StationaryDist_FHorz_Case1(jequaloneDist,AgeWeightsParamNames,Policy,n_d,n_a,n_z,N_j,pi_z,Params,simoptions); 156 | 157 | % We could of course also look at things like life-cycle profiles or 158 | % simulate panel data, but we will wait until later OLG Models to do so. 159 | % E.g., OLG Model 3 plots some life-cycle profiles, OLG Model 4 plots some 160 | % 'aggregates', like GDP and the capital-output ratio. 161 | -------------------------------------------------------------------------------- /OLGModel3.m: -------------------------------------------------------------------------------- 1 | %% OLG Model 3: Dependence on Age 2 | % We will just extend the model in three simple ways. We will let wages have 3 | % a 'life cycle profile'. We will include 'conditional survival 4 | % probabilities', so as people get older their probability of surviving one 5 | % more year (until next period) falls. This will give our model a 6 | % population an age-demographic that looks more realistic. 7 | % To further add realism to the age-demographics we will also add constant 8 | % population growth rate n. 9 | % We will look at two 'new' outputs: life-cycle profile, and demographic pyramid 10 | % 11 | % Note that this is not really changing anything much about general 12 | % equilibrium. It is more about adding a bit more realistic life-cycle. 13 | % 14 | % Just to show how easy it is I am also going to change so that instead of 15 | % fixing pensions and determining tax in general equilibrium (to balance 16 | % the budget of the pension system) we will instead fix the tax and 17 | % determine the pensions in general equilibrium. 18 | % Note that this essentially just involves changing GEPriceParamNames 19 | % 20 | % Comment: Normally when adding conditional survival probabilities you need 21 | % to take care about people leaving behind assets when they die, but this 22 | % model currently has no assets so it is not an issue yet. 23 | 24 | %% Changes from OLG Model 2 25 | % Add Params.kappa_j, the labor productivity units conditional on age 26 | % Add Params.sj, the survival probabilities 27 | % Adjust Params.mewj, based on Params.sj 28 | % Draw Life-Cycle Profiles 29 | % Draw demographic-pyramid 30 | % Modify FnsToEvaluate to give both labor supply and hours worked 31 | 32 | % Note that both sj and kappa_j are vectors that depend on age j. VFI 33 | % Toolkit detects this automatically and deals with them appropriately in 34 | % all the commands. (It detects that length() of the parameter shows a 35 | % vector of length N_j; which is set to be the number of periods/ages). 36 | 37 | %% Begin setting up to use VFI Toolkit to solve 38 | % Lets model agents from age 20 to age 100, so 81 periods 39 | 40 | Params.agejshifter=19; % Initial age 20 minus one. Makes keeping track of actual age easy in terms of model age 41 | Params.J=100-Params.agejshifter; % =81, Number of period in life-cycle 42 | 43 | % Grid sizes to use 44 | n_d=101; % Endogenous labour choice (fraction of time worked) 45 | n_a=1; 46 | n_z=0; % This is how the VFI Toolkit thinks about deterministic models 47 | N_j=Params.J; % Number of periods in finite horizon 48 | 49 | figure_c=0; % I like to use a counter for the figures. Makes it easier to keep track of them when editing. 50 | 51 | %% Parameters 52 | 53 | % Discount rate 54 | Params.beta = 0.99; 55 | % Preferences 56 | Params.sigma = 2; % Coeff of relative risk aversion (curvature of consumption) 57 | Params.eta = 1.5; % Curvature of leisure (This will end up being 1/Frisch elasty) 58 | Params.psi = 10; % Weight on leisure 59 | 60 | Params.A=1; % Aggregate TFP. Not actually used anywhere. 61 | % Production function 62 | Params.alpha = 0.3; % Share of capital 63 | Params.delta = 0.1; % Depreciation rate of capital 64 | 65 | % Demographics 66 | Params.Jr=67-Params.agejshifter; % Retirement age is 67 (remember j=1 is age 20) (You work when younger, not working from Jr on) 67 | Params.agej=(1:1:Params.J)'; % Current 'j' age, so can check when you retire. 68 | % Population growth rate 69 | Params.n=0.02; % percentage rate (expressed as fraction) at which population growths 70 | 71 | % Conditional survival probabilities: sj is the probability of surviving to be age j+1, given alive at age j 72 | % Most countries have calculations of these (as they are used by the government departments that oversee pensions) 73 | % In fact I will here get data on the conditional death probabilities, and then survival is just 1-death. 74 | % Here I just use them for the US, taken from "National Vital Statistics Report, volume 58, number 10, March 2010." 75 | % I took them from first column (qx) of Table 1 (Total Population) 76 | % Conditional death probabilities 77 | Params.dj=[0.006879, 0.000463, 0.000307, 0.000220, 0.000184, 0.000172, 0.000160, 0.000149, 0.000133, 0.000114, 0.000100, 0.000105, 0.000143, 0.000221, 0.000329, 0.000449, 0.000563, 0.000667, 0.000753, 0.000823,... 78 | 0.000894, 0.000962, 0.001005, 0.001016, 0.001003, 0.000983, 0.000967, 0.000960, 0.000970, 0.000994, 0.001027, 0.001065, 0.001115, 0.001154, 0.001209, 0.001271, 0.001351, 0.001460, 0.001603, 0.001769, 0.001943, 0.002120, 0.002311, 0.002520, 0.002747, 0.002989, 0.003242, 0.003512, 0.003803, 0.004118, 0.004464, 0.004837, 0.005217, 0.005591, 0.005963, 0.006346, 0.006768, 0.007261, 0.007866, 0.008596, 0.009473, 0.010450, 0.011456, 0.012407, 0.013320, 0.014299, 0.015323,... 79 | 0.016558, 0.018029, 0.019723, 0.021607, 0.023723, 0.026143, 0.028892, 0.031988, 0.035476, 0.039238, 0.043382, 0.047941, 0.052953, 0.058457, 0.064494,... 80 | 0.071107, 0.078342, 0.086244, 0.094861, 0.104242, 0.114432, 0.125479, 0.137427, 0.150317, 0.164187, 0.179066, 0.194979, 0.211941, 0.229957, 0.249020, 0.269112, 0.290198, 0.312231, 1.000000]; 81 | % dj covers Ages 0 to 100 82 | Params.sj=1-Params.dj(21:101); % Conditional survival probabilities 83 | 84 | % Labor efficiency units depend on age 85 | Params.kappa_j=[linspace(1,3,50-Params.agejshifter), linspace(3,2,(Params.Jr-1)-(50-Params.agejshifter)),zeros(1,Params.J-Params.Jr+1)]; 86 | % These are not done seriously, really they should be set to something like 'average hourly wage conditional on age' in the data. 87 | % I have made them increase until age 50 (j=31), then decrease, and then be zero from retirement at age 67. 88 | % For parameters that depend on age, we just make them a vector with a 89 | % length the same as the number of periods, VFI Toolkit then handles 90 | % them automatically. 91 | 92 | % Taxes 93 | Params.tau = 0.15; % Tax rate on labour income 94 | 95 | %% Some initial values/guesses for variables that will be determined in general eqm 96 | Params.pension=0.4; % Initial guess (this will be determined in general eqm) 97 | Params.w=1; 98 | 99 | %% Grids 100 | % While there are no 'a' for 'z' in this model, VFI Toolkit requires them 101 | % to figure out what is going on. By making them just a single grid point, 102 | % and then not using them anywhere, we are essentially solving a model without them. 103 | a_grid=1; 104 | z_grid=1; % Note: n_z=0 means that z_grid and pi_z will be ignored, but we still need them as inputs to various commands 105 | pi_z=1; 106 | 107 | % Grid for labour choice 108 | h_grid=linspace(0,1,n_d)'; 109 | % Switch into toolkit notation 110 | d_grid=h_grid; 111 | 112 | %% Now, create the return function 113 | DiscountFactorParamNames={'beta','sj'}; 114 | 115 | % We need to change the return function so that it includes kappa_j (compared to FiscalOLG1) 116 | ReturnFn=@(h,aprime,a,agej,w,sigma,psi,eta,Jr,pension,tau,kappa_j)... 117 | OLGModel3_ReturnFn(h,aprime,a,agej,w,sigma,psi,eta,Jr,pension,tau,kappa_j); 118 | 119 | %% Now solve the value function iteration problem, just to check that things are working before we go to General Equilbrium 120 | disp('Test ValueFnIter') 121 | vfoptions=struct(); % Just using the defaults. 122 | tic; 123 | [V, Policy]=ValueFnIter_Case1_FHorz(n_d,n_a,n_z,N_j, d_grid, a_grid, z_grid, pi_z, ReturnFn, Params, DiscountFactorParamNames, [], vfoptions); 124 | toc 125 | 126 | %% Initial distribution of agents at birth (j=1) 127 | jequaloneDist=1; % n_a by n_z, but in current setup this is just 1-by-1 in anycase so 'everyone' is going to have to be born here. 128 | 129 | %% Agents age distribution 130 | % Many OLG models include some kind of population growth, and perhaps 131 | % some other things that create a weighting of different ages that needs to 132 | % be used to calculate the stationary distribution and aggregate variable. 133 | Params.mewj=ones(1,Params.J); % Marginal distribution of households over age 134 | for jj=2:length(Params.mewj) 135 | Params.mewj(jj)=Params.sj(jj-1)*Params.mewj(jj-1)/(1+Params.n); 136 | end 137 | Params.mewj=Params.mewj./sum(Params.mewj); % Normalize to one 138 | 139 | AgeWeightsParamNames={'mewj'}; % Many finite horizon models apply different weights to different 'ages'; eg., due to survival rates or population growth rates. 140 | 141 | %% Test 142 | disp('Test StationaryDist') 143 | simoptions=struct(); % Just use the defaults 144 | tic; 145 | StationaryDist=StationaryDist_FHorz_Case1(jequaloneDist,AgeWeightsParamNames,Policy,n_d,n_a,n_z,N_j,pi_z,Params,simoptions); 146 | toc 147 | 148 | %% Plot the demographic pyramid 149 | % Note that because aging is completely exogenous it is not affected by the 150 | % general equilibrium (initial or final), nor does it change over the 151 | % transition. (We will allow this in a more advanced model later on.) 152 | figure_c=figure_c+1; 153 | figure(figure_c) 154 | hold on 155 | pyramidright = barh((1:1:Params.J)+Params.agejshifter,Params.mewj/2,'hist'); % I need the divided by two to get the symmetry (half on each 'side') 156 | pyramidleft = barh((1:1:Params.J)+Params.agejshifter,-Params.mewj/2,'hist'); % 'minus', so it goes to other 'side' 157 | set(pyramidright,'FaceColor','b') 158 | set(pyramidleft,'FaceColor','b') 159 | hold off 160 | ylabel('Age') 161 | xlabel('Fraction of population') 162 | % saveas(figure_c,'./SavedOutput/Graphs/OLGModel3_DemographicPyramid','pdf') 163 | 164 | %% General eqm variables 165 | GEPriceParamNames={'w','pension'}; 166 | 167 | %% Set up the General Equilibrium conditions (on assets/interest rate, assuming a representative firm with Cobb-Douglas production function) 168 | 169 | % Stationary Distribution Aggregates (important that ordering of Names and Functions is the same) 170 | FnsToEvaluate.L = @(h, aprime,a, kappa_j) kappa_j*h; % Aggregate labour supply 171 | FnsToEvaluate.H = @(h, aprime,a) h; % Aggregate hours worked 172 | FnsToEvaluate.PensionSpending = @(h,aprime,a,pension,agej,Jr) (agej>=Jr)*pension; % Total spending on pensions 173 | % This version of the model is simple enough that tax revenues can just be calculated 'directly'. 174 | % Because of the surivival probabilities it is no longer as trivial to 175 | % calculate pension spending. We could essentially pre-calculate it (it only depends on 176 | % mewj and on pension), but because of how the toolkit works it is just as simple to just get the code to do it for us. 177 | 178 | % General Equilibrium conditions (these should evaluate to zero in general equilbrium) 179 | GeneralEqmEqns.labormarket = @(w,alpha,L,A) w-(1-alpha)*A*L^(-alpha); % wage equals marginal product of labour 180 | GeneralEqmEqns.pensions = @(PensionSpending,tau,w,L) PensionSpending-tau*w*L; % Retirement benefits equal Payroll tax revenue: pension*fractionretired-tau*w*H 181 | 182 | %% Test 183 | disp('Test AggVars') 184 | AggVars=EvalFnOnAgentDist_AggVars_FHorz_Case1(StationaryDist, Policy, FnsToEvaluate, Params, [], n_d, n_a, n_z,N_j, d_grid, a_grid, z_grid); 185 | 186 | %% Solve for the General Equilibrium 187 | 188 | heteroagentoptions.verbose=1; 189 | p_eqm=HeteroAgentStationaryEqm_Case1_FHorz(jequaloneDist,AgeWeightsParamNames,n_d, n_a, n_z, N_j, 0, pi_z, d_grid, a_grid, z_grid, ReturnFn, FnsToEvaluate, GeneralEqmEqns, Params, DiscountFactorParamNames, [], [], [], GEPriceParamNames, heteroagentoptions, simoptions, vfoptions); 190 | % p_eqm contains the general equilibrium parameter values 191 | % Put this into Params so we can calculate things about the general equilibrium 192 | Params.w=p_eqm.w; 193 | Params.pension=p_eqm.pension; 194 | 195 | % Calculate a few things related to the general equilibrium. 196 | [V, Policy]=ValueFnIter_Case1_FHorz(n_d,n_a,n_z,N_j, d_grid, a_grid, z_grid, pi_z, ReturnFn, Params, DiscountFactorParamNames, [], vfoptions); 197 | StationaryDist=StationaryDist_FHorz_Case1(jequaloneDist,AgeWeightsParamNames,Policy,n_d,n_a,n_z,N_j,pi_z,Params,simoptions); 198 | % Can just use the same FnsToEvaluate as before. 199 | AgeConditionalStats=LifeCycleProfiles_FHorz_Case1(StationaryDist,Policy,FnsToEvaluate,Params,[],n_d,n_a,n_z,N_j,d_grid,a_grid,z_grid); 200 | 201 | %% Plot the life cycle profiles of hours worked and effective labour supply in the general eqm. 202 | figure_c=figure_c+1; 203 | figure(figure_c) 204 | subplot(2,1,1); plot(1:1:Params.J,AgeConditionalStats.H.Mean) 205 | title('Life Cycle Profile: Hours Worked') 206 | subplot(2,1,2); plot(1:1:Params.J,AgeConditionalStats.L.Mean) 207 | title('Life Cycle Profile: Labour Supply') 208 | % saveas(figure_c,'./SavedOutput/Graphs/OLGModel3_LifeCycleProfiles','pdf') 209 | -------------------------------------------------------------------------------- /OLGModel3_ReturnFn.m: -------------------------------------------------------------------------------- 1 | function F=OLGModel3_ReturnFn(h,aprime,a,agej,w,sigma,psi,eta,Jr,pension,tau,kappa_j) 2 | % Note: VFI Toolkit automatically deals with dependence of kappa_j (and 3 | % agej) on the age j, and the input to the return function is just the 4 | % relevant value for the 'current' age. 5 | 6 | F=-Inf; 7 | 8 | if agej0 15 | F=(c^(1-sigma))/(1-sigma) -psi*(h^(1+eta))/(1+eta); 16 | end 17 | 18 | end 19 | -------------------------------------------------------------------------------- /OLGModel4.m: -------------------------------------------------------------------------------- 1 | %% OLG Model 4: Assets and Aggregate Physical Capital 2 | % We add assets/savings. This involves adding household assets as an endogenous state. 3 | % To fit empirical fact that households often die with substantial asset 4 | % holdings we will include a 'warm glow of bequests' (utility from having 5 | % assets at death) 6 | % Still no government, just the pension system. 7 | % 8 | % When we add assets we now have a representative firm with Cobb-Douglas 9 | % production function, Y=A*(K^alpha)*(L^(1-alpha)); 10 | % Together with competitive labor and capital markets this means there is a 11 | % tight relationship (an isomorphic function) between r and w. We take 12 | % advantage of this to solve the model in terms of r, and get a formula for 13 | % w in terms of r as follows: 14 | % Rearranging that r=MPK-delta gives the following eqn (MPK is marginal product of capital) 15 | % KdivL=((r+delta)/(alpha*A))^(1/(alpha-1)); 16 | % From K/Y, substituting the production function gives 17 | % KdivY=(KdivL^(1-alpha))/A; % Don't use this, just including it for completeness. 18 | % Notice that discount factor beta plays an indirect role in determining K/Y via determining r 19 | % We know w=MPL (MPL is marginal product of labour) 20 | % w=A*(1-alpha)*(KdivL^alpha); % wage rate (per effective labour unit) 21 | % [You could solve model in terms of w, and use inverse of this formula to 22 | % get r. We simply follow tradition and solve in terms of r. It is easier to 23 | % get analytical initial guesses for r than for w.] 24 | % 25 | % Because people die unexpectedly (due to sj, the conditional surival 26 | % probabilities) some people will still have assets when they die. The warm 27 | % glow bequest is another reason why people will still have assets when 28 | % they die. We don't want these assets to simply disappear. We will 29 | % therefore redistribute them as a lump-sum to everyone, which we will call 30 | % accidental bequests. This involves adding them to the return function, 31 | % adding them as a function to evaluate, and adding a general equilibrium 32 | % condition that the accidental bequest people leave when they die are 33 | % equal to the received lump-sum transfers. 34 | % 35 | 36 | %% Begin setting up to use VFI Toolkit to solve 37 | % Lets model agents from age 20 to age 100, so 81 periods 38 | 39 | Params.agejshifter=19; % Age 20 minus one. Makes keeping track of actual age easy in terms of model age 40 | Params.J=100-Params.agejshifter; % =81, Number of period in life-cycle 41 | 42 | % Grid sizes to use 43 | n_d=101; % Endogenous labour choice (fraction of time worked) 44 | n_a=301; 45 | n_z=0; % This is how the VFI Toolkit thinks about deterministic models 46 | N_j=Params.J; % Number of periods in finite horizon 47 | 48 | figure_c=0; % I like to use a counter for the figures. Makes it easier to keep track of them when editing. 49 | 50 | %% Parameters 51 | 52 | % Discount rate 53 | Params.beta = 0.99; 54 | % Preferences 55 | Params.sigma = 2; % Coeff of relative risk aversion (curvature of consumption) 56 | Params.eta = 1.5; % Curvature of leisure (This will end up being 1/Frisch elasty) 57 | Params.psi = 10; % Weight on leisure 58 | 59 | Params.A=1; % Aggregate TFP. Not actually used anywhere. 60 | % Production function 61 | Params.alpha = 0.3; % Share of capital 62 | Params.delta = 0.1; % Depreciation rate of capital 63 | 64 | % Warm-glow of bequest 65 | Params.warmglowparam1=1; 66 | Params.warmglowparam2=2; 67 | 68 | % Demographics 69 | Params.Jr=67-Params.agejshifter; % Retirement age is 67 (remember j=1 is age 20) (You work when younger, not working from Jr on) 70 | Params.agej=(1:1:Params.J)'; % Current 'j' age, so can check when you retire. 71 | % Population growth rate 72 | Params.n=0.02; % percentage rate (expressed as fraction) at which population growths 73 | 74 | % Conditional survival probabilities: sj is the probability of surviving to be age j+1, given alive at age j 75 | % Most countries have calculations of these (as they are used by the government departments that oversee pensions) 76 | % In fact I will here get data on the conditional death probabilities, and then survival is just 1-death. 77 | % Here I just use them for the US, taken from "National Vital Statistics Report, volume 58, number 10, March 2010." 78 | % I took them from first column (qx) of Table 1 (Total Population) 79 | % Conditional death probabilities 80 | Params.dj=[0.006879, 0.000463, 0.000307, 0.000220, 0.000184, 0.000172, 0.000160, 0.000149, 0.000133, 0.000114, 0.000100, 0.000105, 0.000143, 0.000221, 0.000329, 0.000449, 0.000563, 0.000667, 0.000753, 0.000823,... 81 | 0.000894, 0.000962, 0.001005, 0.001016, 0.001003, 0.000983, 0.000967, 0.000960, 0.000970, 0.000994, 0.001027, 0.001065, 0.001115, 0.001154, 0.001209, 0.001271, 0.001351, 0.001460, 0.001603, 0.001769, 0.001943, 0.002120, 0.002311, 0.002520, 0.002747, 0.002989, 0.003242, 0.003512, 0.003803, 0.004118, 0.004464, 0.004837, 0.005217, 0.005591, 0.005963, 0.006346, 0.006768, 0.007261, 0.007866, 0.008596, 0.009473, 0.010450, 0.011456, 0.012407, 0.013320, 0.014299, 0.015323,... 82 | 0.016558, 0.018029, 0.019723, 0.021607, 0.023723, 0.026143, 0.028892, 0.031988, 0.035476, 0.039238, 0.043382, 0.047941, 0.052953, 0.058457, 0.064494,... 83 | 0.071107, 0.078342, 0.086244, 0.094861, 0.104242, 0.114432, 0.125479, 0.137427, 0.150317, 0.164187, 0.179066, 0.194979, 0.211941, 0.229957, 0.249020, 0.269112, 0.290198, 0.312231, 1.000000]; 84 | % dj covers Ages 0 to 100 85 | Params.sj=1-Params.dj(21:101); % Conditional survival probabilities 86 | Params.sj(end)=0; % We did not need this in the previous model, but now it is important to help keep track of accidental bequests (otherwise we would have to use a more complicated formula) 87 | 88 | % Labor efficiency units depend on age 89 | Params.kappa_j=[linspace(1,3,50-Params.agejshifter), linspace(3,2,(Params.Jr-1)-(50-Params.agejshifter)),zeros(1,Params.J-Params.Jr+1)]; 90 | % These are not done seriously, really they should be set to something like 'average hourly wage conditional on age' in the data. 91 | % I have made them increase until age 50 (j=31), then decrease, and then be zero from retirement at age 67. 92 | % For parameters that depend on age, we just make them a vector with a 93 | % length the same as the number of periods, VFI Toolkit then handles 94 | % them automatically. 95 | 96 | % Taxes 97 | Params.tau = 0.15; % Tax rate on labour income 98 | 99 | %% Some initial values/guesses for variables that will be determined in general eqm 100 | Params.pension=0.4; % Initial guess (this will be determined in general eqm) 101 | Params.r=0.03; 102 | Params.AccidentBeq=0.03; % Accidental bequests (this is the lump sum transfer) 103 | 104 | %% Grids 105 | Params.amax=5; % There is no easy way to figure out what amax should be. 106 | % It needs to be large enough that no agent would ever choose to go there 107 | % and stay there (you can use policy function to look at this). But we 108 | % don't want it larger than necessary, as this would 'waste' grid points 109 | % and so be less accurate. Because the current OLG has no 'idiosycratic 110 | % shocks' we don't need amax to be very high (relative to income). Later, 111 | % we will add idiosyncratic shocks and need to set a higher amax. 112 | a_grid=Params.amax*(linspace(0,1,n_a).^3)'; % The ^3 means most points are near zero, which is where the derivative of the value fn changes most. 113 | % Note: Implicitly, we are imposing borrowing constraint a'>=0 114 | z_grid=1; 115 | pi_z=1; 116 | 117 | % Grid for labour choice 118 | h_grid=linspace(0,1,n_d)'; 119 | % Switch into toolkit notation 120 | d_grid=h_grid; 121 | 122 | %% 123 | DiscountFactorParamNames={'beta','sj'}; 124 | 125 | % We need to change the return function so that it uses r and includes assets 126 | ReturnFn=@(h,aprime,a,agej,r,A,delta,alpha,sigma,psi,eta,Jr,pension,tau,kappa_j,J,warmglowparam1,warmglowparam2,AccidentBeq)... 127 | OLGModel4_ReturnFn(h,aprime,a,agej,r,A,delta,alpha,sigma,psi,eta,Jr,pension,tau,kappa_j,J,warmglowparam1,warmglowparam2, AccidentBeq); 128 | 129 | %% Now solve the value function iteration problem, just to check that things are working before we go to General Equilbrium 130 | disp('Test ValueFnIter') 131 | vfoptions=struct(); % Just using the defaults. 132 | tic; 133 | [V, Policy]=ValueFnIter_Case1_FHorz(n_d,n_a,n_z,N_j, d_grid, a_grid, z_grid, pi_z, ReturnFn, Params, DiscountFactorParamNames, [], vfoptions); 134 | toc 135 | 136 | %% Initial distribution of agents at birth (j=1) 137 | jequaloneDist=zeros(n_a,1); % n_a by 1. 138 | jequaloneDist(1)=1; % Everyone is born with zero assets 139 | 140 | %% Agents age distribution 141 | % Many OLG models include some kind of population growth, and perhaps 142 | % some other things that create a weighting of different ages that needs to 143 | % be used to calculate the stationary distribution and aggregate variable. 144 | Params.mewj=ones(1,Params.J); % Marginal distribution of households over age 145 | for jj=2:length(Params.mewj) 146 | Params.mewj(jj)=Params.sj(jj-1)*Params.mewj(jj-1)/(1+Params.n); 147 | end 148 | Params.mewj=Params.mewj./sum(Params.mewj); % Normalize to one 149 | 150 | AgeWeightsParamNames={'mewj'}; % Many finite horizon models apply different weights to different 'ages'; eg., due to survival rates or population growth rates. 151 | 152 | %% Test 153 | disp('Test StationaryDist') 154 | simoptions=struct(); % Just use the defaults 155 | tic; 156 | StationaryDist=StationaryDist_FHorz_Case1(jequaloneDist,AgeWeightsParamNames,Policy,n_d,n_a,n_z,N_j,pi_z,Params,simoptions); 157 | toc 158 | 159 | %% General eqm variables 160 | GEPriceParamNames={'r','pension','AccidentBeq'}; 161 | 162 | %% Set up the General Equilibrium conditions (on assets/interest rate, assuming a representative firm with Cobb-Douglas production function) 163 | 164 | % Stationary Distribution Aggregates (important that ordering of Names and Functions is the same) 165 | FnsToEvaluate.H = @(h,aprime,a) h; % Aggregate labour supply 166 | FnsToEvaluate.L = @(h,aprime,a,kappa_j) kappa_j*h; % Aggregate labour supply (in efficiency units) 167 | FnsToEvaluate.K = @(h,aprime,a) a; % Aggregate physical capital 168 | FnsToEvaluate.PensionSpending = @(h,aprime,a,pension,agej,Jr) (agej>=Jr)*pension; % Total spending on pensions 169 | FnsToEvaluate.AccidentalBeqLeft = @(h,aprime,a,sj) aprime*(1-sj); % Accidental bequests left by people who die 170 | 171 | % General Equilibrium conditions (these should evaluate to zero in general equilbrium) 172 | GeneralEqmEqns.capitalmarket = @(r,K,L,alpha,delta,A) r-alpha*A*(K^(alpha-1))*(L^(1-alpha)); % interest rate equals marginal product of capital net of depreciation 173 | GeneralEqmEqns.pensions = @(PensionSpending,tau,L,r,A,alpha,delta) PensionSpending-tau*(A*(1-alpha)*((r+delta)/(alpha*A))^(alpha/(alpha-1)))*L; % Retirement benefits equal Payroll tax revenue: pension*fractionretired-tau*w*H 174 | GeneralEqmEqns.bequests = @(AccidentalBeqLeft,AccidentBeq,n) AccidentalBeqLeft/(1+n)-AccidentBeq; % Accidental bequests received equal accidental bequests left 175 | % Note: the pensions general eqm condition looks more complicated just because we replaced w with the formula for w in terms of r. It is actually just the same formula as before. 176 | 177 | 178 | %% Test 179 | disp('Test AggVars') 180 | AggVars=EvalFnOnAgentDist_AggVars_FHorz_Case1(StationaryDist, Policy, FnsToEvaluate, Params, [], n_d, n_a, n_z,N_j, d_grid, a_grid, z_grid); 181 | 182 | %% Solve for the General Equilibrium 183 | heteroagentoptions.verbose=1; 184 | p_eqm=HeteroAgentStationaryEqm_Case1_FHorz(jequaloneDist,AgeWeightsParamNames,n_d, n_a, n_z, N_j, 0, pi_z, d_grid, a_grid, z_grid, ReturnFn, FnsToEvaluate, GeneralEqmEqns, Params, DiscountFactorParamNames, [], [], [], GEPriceParamNames, heteroagentoptions, simoptions, vfoptions); 185 | % p_eqm contains the general equilibrium parameter values 186 | % Put this into Params so we can calculate things about the initial equilibrium 187 | Params.r=p_eqm.r; 188 | Params.pension=p_eqm.pension; 189 | Params.AccidentBeq=p_eqm.AccidentBeq; 190 | 191 | % Calculate a few things related to the general equilibrium. 192 | [V, Policy]=ValueFnIter_Case1_FHorz(n_d,n_a,n_z,N_j, d_grid, a_grid, z_grid, pi_z, ReturnFn, Params, DiscountFactorParamNames, [], vfoptions); 193 | StationaryDist=StationaryDist_FHorz_Case1(jequaloneDist,AgeWeightsParamNames,Policy,n_d,n_a,n_z,N_j,pi_z,Params,simoptions); 194 | % Can just use the same FnsToEvaluate as before. 195 | AgeConditionalStats=LifeCycleProfiles_FHorz_Case1(StationaryDist,Policy,FnsToEvaluate,Params,[],n_d,n_a,n_z,N_j,d_grid,a_grid,z_grid); 196 | 197 | %% Plot the life cycle profiles of capital and labour for the general eqm. 198 | 199 | figure_c=figure_c+1; 200 | figure(figure_c) 201 | subplot(3,1,1); plot(1:1:Params.J,AgeConditionalStats.H.Mean) 202 | title('Life Cycle Profile: Hours Worked') 203 | subplot(3,1,2); plot(1:1:Params.J,AgeConditionalStats.L.Mean) 204 | title('Life Cycle Profile: Labour Supply') 205 | subplot(3,1,3); plot(1:1:Params.J,AgeConditionalStats.K.Mean) 206 | title('Life Cycle Profile: Assets') 207 | % saveas(figure_c,'./SavedOutput/Graphs/OLGModel4_LifeCycleProfiles','pdf') 208 | 209 | %% Often in OLG models we are interested in things like the aggregate capital-output (a.k.a, wealth-income) 210 | % ratio. Let's calculate some aggregates and ratios of these. 211 | 212 | % Add consumption to the FnsToEvaluate 213 | FnsToEvaluate.Consumption=@(h,aprime,a,agej,Jr,r,pension,tau,kappa_j,alpha,delta,A) OLGModel4_ConsumptionFn(h,aprime,a,agej,Jr,r,pension,tau,kappa_j,alpha,delta,A); 214 | 215 | AggVars=EvalFnOnAgentDist_AggVars_FHorz_Case1(StationaryDist, Policy, FnsToEvaluate, Params, [], n_d, n_a, n_z,N_j, d_grid, a_grid, z_grid); 216 | 217 | % GDP 218 | Y=Params.A*(AggVars.K.Mean^Params.alpha)*(AggVars.L.Mean^(1-Params.alpha)); 219 | 220 | fprintf('Following are some aggregates of the model economy: \n') 221 | fprintf('Output: Y=%8.2f (this number is fairly meaningless in and of itself) \n',Y) 222 | fprintf('Capital-Output ratio: K/Y=%8.2f \n',AggVars.K.Mean/Y) 223 | fprintf('Consumption-Output ratio: C/Y=%8.2f \n',AggVars.Consumption.Mean/Y) 224 | fprintf('Average labor productivity: Y/H=%8.2f \n', Y/AggVars.H.Mean) 225 | fprintf('Accidental Bequests as fraction of GDP: %8.2f \n',Params.AccidentBeq/Y) 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | -------------------------------------------------------------------------------- /OLGModel4_ConsumptionFn.m: -------------------------------------------------------------------------------- 1 | function c=OLGModel4_ConsumptionFn(h,aprime,a,agej,Jr,r,pension,tau,kappa_j,alpha,delta,A) 2 | % Note: these lines are essentially just a copy of the relevant part of the return fn 3 | 4 | KdivL=((r+delta)/(alpha*A))^(1/(alpha-1)); 5 | w=A*(1-alpha)*(KdivL^alpha); % wage rate (per effective labour unit) 6 | 7 | if agej0 34 | F=(c^(1-sigma))/(1-sigma) -psi*(h^(1+eta))/(1+eta); 35 | end 36 | 37 | % Warm-glow bequest 38 | if agej==J % Final period 39 | warmglow=warmglowparam1*(aprime^(1-warmglowparam2))/(1-warmglowparam2); 40 | F=F+warmglow; 41 | end 42 | % Notice that we have modelled the warm-glow in such a way that you only 43 | % get it if you die in the last period (j=J). But we know there is a 1-sj 44 | % risk of dying every period. So we might prefer to model that we get the 45 | % warm glow bequest if we die at any age. The following commented out two lines 46 | % implement this alternative. [note: need to add sj to inputs of ReturnFn to use it] 47 | % warmglow=warmglowparam1*(aprime^(1-warmglowparam2))/(1-warmglowparam2); % Note: same formula as above 48 | % F=F+(1-sj)*warmglow 49 | % Note: if using this, have to make sure sj=0 for j=J. 50 | % Comment: I am not aware of any study saying which of these two 51 | % alternatives works better empirically. 52 | 53 | end 54 | -------------------------------------------------------------------------------- /OLGModel5.m: -------------------------------------------------------------------------------- 1 | %% OLG Model 5: Progressive Taxation and Government Budget Balance 2 | % Add 'more government' 3 | % (and resulting changes in calculating aggregates and general eqm condns) 4 | % 5 | % This kind of model is widely used/studied, and often associated with Auerbach & Kotlikoff (1987). 6 | % 7 | % Lets model agents from age 20 to age 100, so 81 periods 8 | 9 | Params.agejshifter=19; % Age 20 minus one. Makes keeping track of actual age easy in terms of model age 10 | Params.J=100-Params.agejshifter; % =81, Number of period in life-cycle 11 | 12 | % Grid sizes to use 13 | n_d=101; % Endogenous labour choice (fraction of time worked) 14 | n_a=301; 15 | n_z=0; % This is how the VFI Toolkit thinks about deterministic models 16 | N_j=Params.J; % Number of periods in finite horizon 17 | 18 | figure_c=0; % I like to use a counter for the figures. Makes it easier to keep track of them when editing. 19 | 20 | 21 | %% Parameters 22 | 23 | % Discount rate 24 | Params.beta = 0.99; 25 | % Preferences 26 | Params.sigma = 2; % Coeff of relative risk aversion (curvature of consumption) 27 | Params.eta = 1.5; % Curvature of leisure (This will end up being 1/Frisch elasty) 28 | Params.psi = 10; % Weight on leisure 29 | 30 | Params.A=1; % Aggregate TFP. Not actually used anywhere. 31 | % Production function 32 | Params.alpha = 0.3; % Share of capital 33 | Params.delta = 0.1; % Depreciation rate of capital 34 | 35 | % Warm-glow of bequest 36 | Params.warmglowparam1=1; 37 | Params.warmglowparam2=2; 38 | 39 | % Demographics 40 | Params.Jr=67-Params.agejshifter; % Retirement age is 67 (remember j=1 is age 20) (You work when younger, not working from Jr on) 41 | Params.agej=(1:1:Params.J)'; % Current 'j' age, so can check when you retire. 42 | % Population growth rate 43 | Params.n=0.02; % percentage rate (expressed as fraction) at which population growths 44 | 45 | % Conditional survival probabilities: sj is the probability of surviving to be age j+1, given alive at age j 46 | % Most countries have calculations of these (as they are used by the government departments that oversee pensions) 47 | % In fact I will here get data on the conditional death probabilities, and then survival is just 1-death. 48 | % Here I just use them for the US, taken from "National Vital Statistics Report, volume 58, number 10, March 2010." 49 | % I took them from first column (qx) of Table 1 (Total Population) 50 | % Conditional death probabilities 51 | Params.dj=[0.006879, 0.000463, 0.000307, 0.000220, 0.000184, 0.000172, 0.000160, 0.000149, 0.000133, 0.000114, 0.000100, 0.000105, 0.000143, 0.000221, 0.000329, 0.000449, 0.000563, 0.000667, 0.000753, 0.000823,... 52 | 0.000894, 0.000962, 0.001005, 0.001016, 0.001003, 0.000983, 0.000967, 0.000960, 0.000970, 0.000994, 0.001027, 0.001065, 0.001115, 0.001154, 0.001209, 0.001271, 0.001351, 0.001460, 0.001603, 0.001769, 0.001943, 0.002120, 0.002311, 0.002520, 0.002747, 0.002989, 0.003242, 0.003512, 0.003803, 0.004118, 0.004464, 0.004837, 0.005217, 0.005591, 0.005963, 0.006346, 0.006768, 0.007261, 0.007866, 0.008596, 0.009473, 0.010450, 0.011456, 0.012407, 0.013320, 0.014299, 0.015323,... 53 | 0.016558, 0.018029, 0.019723, 0.021607, 0.023723, 0.026143, 0.028892, 0.031988, 0.035476, 0.039238, 0.043382, 0.047941, 0.052953, 0.058457, 0.064494,... 54 | 0.071107, 0.078342, 0.086244, 0.094861, 0.104242, 0.114432, 0.125479, 0.137427, 0.150317, 0.164187, 0.179066, 0.194979, 0.211941, 0.229957, 0.249020, 0.269112, 0.290198, 0.312231, 1.000000]; 55 | % dj covers Ages 0 to 100 56 | Params.sj=1-Params.dj(21:101); % Conditional survival probabilities 57 | Params.sj(end)=0; 58 | 59 | % Labor efficiency units depend on age 60 | Params.kappa_j=[linspace(1,3,50-Params.agejshifter), linspace(3,2,(Params.Jr-1)-(50-Params.agejshifter)),zeros(1,Params.J-Params.Jr+1)]; 61 | % These are not done seriously, really they should be set to something like 'average hourly wage conditional on age' in the data. 62 | % I have made them increase until age 50 (j=31), then decrease, and then be zero from retirement at age 67. 63 | % For parameters that depend on age, we just make them a vector with a 64 | % length the same as the number of periods, VFI Toolkit then handles 65 | % them automatically. 66 | 67 | % Taxes 68 | Params.tau = 0.15; % Tax rate on labour income 69 | % In addition to payroll tax rate tau, which funds the pension system we will add a progressive 70 | % income tax which funds government spending. 71 | % The progressive income tax takes the functional form: 72 | % IncomeTax=eta1+eta2*log(Income)*Income; % This functional form is empirically a decent fit for the US tax system 73 | % And is determined by the two parameters 74 | Params.eta1=0.09; % eta1 will be determined in equilibrium to balance gov budget constraint 75 | Params.eta2=0.053; 76 | 77 | % Government spending 78 | Params.GdivYtarget = 0.15; % Government spending as a fraction of GDP (this is essentially just used as a target to define a general equilibrium condition) 79 | 80 | %% Some initial values/guesses for variables that will be determined in general eqm 81 | Params.pension=0.4; % Initial guess (this will be determined in general eqm) 82 | Params.r=0.06; 83 | Params.AccidentBeq=0.03; % Accidental bequests (this is the lump sum transfer) 84 | Params.G=0.2; % Government expenditure 85 | % Params.eta1=0.09; 86 | 87 | %% Grids 88 | Params.amax=5; 89 | a_grid=Params.amax*(linspace(0,1,n_a).^3)'; % The ^3 means most points are near zero, which is where the derivative of the value fn changes most. 90 | % Note: Implicitly, we are imposing borrowing constraint a'>=0 91 | z_grid=1; % Note: n_z=0 means that z_grid and pi_z will be ignored, but we still need them as inputs to various commands 92 | pi_z=1; 93 | 94 | % Grid for labour choice 95 | h_grid=linspace(0,1,n_d)'; 96 | % Switch into toolkit notation 97 | d_grid=h_grid; 98 | 99 | %% Now, create the return function 100 | DiscountFactorParamNames={'beta','sj'}; 101 | 102 | ReturnFn=@(h,aprime,a,agej,r,A,delta,alpha,sigma,psi,eta,Jr,pension,tau,kappa_j,J,warmglowparam1,warmglowparam2,AccidentBeq, eta1,eta2)... 103 | OLGModel5_ReturnFn(h,aprime,a,agej,r,A,delta,alpha,sigma,psi,eta,Jr,pension,tau,kappa_j,J,warmglowparam1,warmglowparam2,AccidentBeq, eta1,eta2); 104 | 105 | %% Now solve the value function iteration problem, just to check that things are working before we go to General Equilbrium 106 | disp('Test ValueFnIter') 107 | vfoptions=struct(); % Just using the defaults. 108 | tic; 109 | [V, Policy]=ValueFnIter_Case1_FHorz(n_d,n_a,n_z,N_j, d_grid, a_grid, z_grid, pi_z, ReturnFn, Params, DiscountFactorParamNames, [], vfoptions); 110 | toc 111 | 112 | %% Initial distribution of agents at birth (j=1) 113 | jequaloneDist=zeros(n_a,1); % n_a by n_z. 114 | jequaloneDist(1)=1; % Everyone is born with zero assets 115 | 116 | %% Agents age distribution 117 | % Many OLG models include some kind of population growth, and perhaps 118 | % some other things that create a weighting of different ages that needs to 119 | % be used to calculate the stationary distribution and aggregate variable. 120 | Params.mewj=ones(1,Params.J); % Marginal distribution of households over age 121 | for jj=2:length(Params.mewj) 122 | Params.mewj(jj)=Params.sj(jj-1)*Params.mewj(jj-1)/(1+Params.n); 123 | end 124 | Params.mewj=Params.mewj./sum(Params.mewj); % Normalize to one 125 | 126 | AgeWeightsParamNames={'mewj'}; % Many finite horizon models apply different weights to different 'ages'; eg., due to survival rates or population growth rates. 127 | 128 | %% Test 129 | disp('Test StationaryDist') 130 | simoptions=struct(); % Just use the defaults 131 | tic; 132 | StationaryDist=StationaryDist_FHorz_Case1(jequaloneDist,AgeWeightsParamNames,Policy,n_d,n_a,n_z,N_j,pi_z,Params,simoptions); 133 | toc 134 | 135 | %% General eqm variables 136 | GEPriceParamNames={'r','pension','AccidentBeq','G','eta1'}; 137 | 138 | %% Set up the General Equilibrium conditions (on assets/interest rate, assuming a representative firm with Cobb-Douglas production function) 139 | 140 | % Stationary Distribution Aggregates (important that ordering of Names and Functions is the same) 141 | FnsToEvaluate.H = @(h,aprime,a) h; % Aggregate labour supply (in efficiency units) 142 | FnsToEvaluate.L = @(h,aprime,a,kappa_j) kappa_j*h; % Aggregate physical capital 143 | FnsToEvaluate.K = @(h,aprime,a) a; % Aggregate labour supply (in efficiency units) 144 | FnsToEvaluate.PensionSpending = @(h,aprime,a,pension,agej,Jr) (agej>=Jr)*pension; % Total spending on pensions 145 | FnsToEvaluate.AccidentalBeqLeft = @(h,aprime,a,sj) aprime*(1-sj); % Accidental bequests left by people who die 146 | FnsToEvaluate.IncomeTaxRevenue = @(h,aprime,a,eta1,eta2,kappa_j,r,delta,alpha,A) OLGModel5_ProgressiveIncomeTaxFn(h,aprime,a,eta1,eta2,kappa_j,r,delta,alpha,A); % Revenue raised by the progressive income tax (needed own function to avoid log(0) causing problems) 147 | 148 | % General Equilibrium conditions (these should evaluate to zero in general equilbrium) 149 | GeneralEqmEqns.capitalmarket = @(r,K,L,alpha,delta,A) r-alpha*A*(K^(alpha-1))*(L^(1-alpha)); % interest rate equals marginal product of capital net of depreciation 150 | GeneralEqmEqns.pensions = @(PensionSpending,tau,L,r,A,alpha,delta) PensionSpending-tau*(A*(1-alpha)*((r+delta)/(alpha*A))^(alpha/(alpha-1)))*L; % Retirement benefits equal Payroll tax revenue: pension*fractionretired-tau*w*H 151 | GeneralEqmEqns.bequests = @(AccidentalBeqLeft,AccidentBeq,n) AccidentalBeqLeft/(1+n)-AccidentBeq; % Accidental bequests received equal accidental bequests left 152 | GeneralEqmEqns.Gtarget = @(G,GdivYtarget,A,K,L,alpha) G-GdivYtarget*(A*K^(alpha)*(L^(1-alpha))); % G is equal to the target, GdivYtarget*Y 153 | GeneralEqmEqns.govbudget = @(G,IncomeTaxRevenue) G-IncomeTaxRevenue; % Government budget balances (note that pensions are a seperate budget) 154 | % Note: the pensions general eqm condition looks more complicated just because we replaced w with the formula for w in terms of r. It is actually just the same formula as before. 155 | 156 | %% Test 157 | disp('Test AggVars') 158 | AggVars=EvalFnOnAgentDist_AggVars_FHorz_Case1(StationaryDist, Policy, FnsToEvaluate, Params, [], n_d, n_a, n_z,N_j, d_grid, a_grid, z_grid); 159 | 160 | %% Solve for the General Equilibrium 161 | heteroagentoptions.verbose=1; 162 | p_eqm=HeteroAgentStationaryEqm_Case1_FHorz(jequaloneDist,AgeWeightsParamNames,n_d, n_a, n_z, N_j, 0, pi_z, d_grid, a_grid, z_grid, ReturnFn, FnsToEvaluate, GeneralEqmEqns, Params, DiscountFactorParamNames, [], [], [], GEPriceParamNames, heteroagentoptions, simoptions, vfoptions); 163 | % p_eqm contains the general equilibrium parameter values 164 | % Put this into Params so we can calculate things about the initial equilibrium 165 | Params.r=p_eqm.r; 166 | Params.pension=p_eqm.pension; 167 | Params.AccidentBeq=p_eqm.AccidentBeq; 168 | Params.G=p_eqm.G; 169 | Params.eta1=p_eqm.eta1; 170 | 171 | % Calculate a few things related to the general equilibrium. 172 | [V, Policy]=ValueFnIter_Case1_FHorz(n_d,n_a,n_z,N_j, d_grid, a_grid, z_grid, pi_z, ReturnFn, Params, DiscountFactorParamNames, [], vfoptions); 173 | StationaryDist=StationaryDist_FHorz_Case1(jequaloneDist,AgeWeightsParamNames,Policy,n_d,n_a,n_z,N_j,pi_z,Params,simoptions); 174 | % Can just use the same FnsToEvaluate as before. 175 | AgeConditionalStats=LifeCycleProfiles_FHorz_Case1(StationaryDist,Policy,FnsToEvaluate,Params,[],n_d,n_a,n_z,N_j,d_grid,a_grid,z_grid); 176 | 177 | %% Plot the life cycle profiles of capital and labour for the inital and final eqm. 178 | 179 | figure_c=figure_c+1; 180 | figure(figure_c) 181 | subplot(3,1,1); plot(1:1:Params.J,AgeConditionalStats.H.Mean) 182 | title('Life Cycle Profile: Hours Worked') 183 | subplot(3,1,2); plot(1:1:Params.J,AgeConditionalStats.L.Mean) 184 | title('Life Cycle Profile: Labour Supply') 185 | subplot(3,1,3); plot(1:1:Params.J,AgeConditionalStats.K.Mean) 186 | title('Life Cycle Profile: Assets') 187 | % saveas(figure_c,'./SavedOutput/Graphs/OLGModel5_LifeCycleProfiles','pdf') 188 | 189 | %% Calculate some aggregates and print findings about them 190 | 191 | % Add consumption to the FnsToEvaluate 192 | FnsToEvaluate.Consumption=@(h,aprime,a,agej,Jr,r,pension,tau,kappa_j,alpha,delta,A,eta1,eta2) OLGModel5_ConsumptionFn(h,aprime,a,agej,Jr,r,pension,tau,kappa_j,alpha,delta,A,eta1,eta2); 193 | 194 | AggVars=EvalFnOnAgentDist_AggVars_FHorz_Case1(StationaryDist, Policy, FnsToEvaluate, Params, [], n_d, n_a, n_z,N_j, d_grid, a_grid, z_grid); 195 | 196 | % GDP 197 | Y=Params.A*(AggVars.K.Mean^Params.alpha)*(AggVars.L.Mean^(1-Params.alpha)); 198 | 199 | % wage (note that this is calculation is only valid because we have Cobb-Douglas production function and are looking at a stationary general equilibrium) 200 | KdivL=((Params.r+Params.delta)/(Params.alpha*Params.A))^(1/(Params.alpha-1)); 201 | w=Params.A*(1-Params.alpha)*(KdivL^Params.alpha); % wage rate (per effective labour unit) 202 | 203 | fprintf('Following are some aggregates of the model economy: \n') 204 | fprintf('Output: Y=%8.2f \n',Y) 205 | fprintf('Capital-Output ratio: K/Y=%8.2f \n',AggVars.K.Mean/Y) 206 | fprintf('Consumption-Output ratio: C/Y=%8.2f \n',AggVars.Consumption.Mean/Y) 207 | fprintf('Average labor productivity: Y/H=%8.2f \n', Y/AggVars.H.Mean) 208 | fprintf('Government-to-Output ratio: G/Y=%8.2f \n', Params.G/Y) 209 | fprintf('Accidental Bequests as fraction of GDP: %8.2f \n',Params.AccidentBeq/Y) 210 | fprintf('Wage: w=%8.2f \n',w) 211 | 212 | 213 | 214 | -------------------------------------------------------------------------------- /OLGModel5_ConsumptionFn.m: -------------------------------------------------------------------------------- 1 | function c=OLGModel5_ConsumptionFn(h,aprime,a,agej,Jr,r,pension,tau,kappa_j,alpha,delta,A,eta1,eta2) 2 | % Note: these lines are essentially just a copy of the relevant part of the return fn 3 | 4 | KdivL=((r+delta)/(alpha*A))^(1/(alpha-1)); 5 | w=A*(1-alpha)*(KdivL^alpha); % wage rate (per effective labour unit) 6 | 7 | % Progressive income tax 8 | Income=w*kappa_j*h+r*a; % Income is labor income and capital income 9 | IncomeTax=eta1+eta2*log(Income)*Income; 10 | 11 | if agej0 10 | IncomeTax=eta1+eta2*log(Income)*Income; 11 | end 12 | % Note: Have made pensions exempt from income tax. 13 | 14 | end -------------------------------------------------------------------------------- /OLGModel5_ReturnFn.m: -------------------------------------------------------------------------------- 1 | function F=OLGModel5_ReturnFn(h,aprime,a,agej,r,A,delta,alpha,sigma,psi,eta,Jr,pension,tau,kappa_j,J,warmglow1,warmglow2,AccidentBeq, eta1,eta2) 2 | % Only change from OLGModel4_ReturnFn is to include a progressive income tax 3 | 4 | KdivL=((r+delta)/(alpha*A))^(1/(alpha-1)); 5 | w=A*(1-alpha)*(KdivL^alpha); % wage rate (per effective labour unit) 6 | 7 | % Progressive income tax 8 | if agej0 15 | IncomeTax=eta1+eta2*log(Income)*Income; 16 | end 17 | % Note: Have made pensions exempt from income tax. 18 | 19 | F=-Inf; 20 | 21 | if agej0 28 | F=(c^(1-sigma))/(1-sigma) -psi*(h^(1+eta))/(1+eta); 29 | end 30 | 31 | % Warm-glow bequest 32 | if agej==J % Final period 33 | warmglow=warmglow1*(aprime^(1-warmglow2))/(1-warmglow2); 34 | F=F+warmglow; 35 | end 36 | % Notice that we have modelled the warm-glow in such a way that you only 37 | % get it if you die in the last period (j=J). But we know there is a 1-sj 38 | % risk of dying every period. So we might prefer to model that we get the 39 | % warm glow bequest if we die at any age. The following commented out two lines 40 | % implement this alternative. [note: need to add sj to inputs of ReturnFn to use it] 41 | % warmglow=warmglowparam1*(aprime^(1-warmglowparam2))/(1-warmglowparam2); % Note: same formula as above 42 | % F=F+(1-sj)*warmglow 43 | % Note: if using this, have to make sure sj=0 for j=J. 44 | % Comment: I am not aware of any study saying which of these two 45 | % alternatives works better empirically. 46 | 47 | end 48 | -------------------------------------------------------------------------------- /OLGModel6.m: -------------------------------------------------------------------------------- 1 | %% OLG Model 6: Stochastic OLG Model 2 | % Add idiosyncratic shocks, so we now have an incomplete markets OLG model. 3 | % We introduce z and e. z is a (log) AR(1) process with age-dependent parameters, which is 4 | % an idiosyncratic shock to 'hourly-earnings' (technically, earnings per 5 | % unit of time, our model does not contain a concept of 'hours'). e is an 6 | % iid (log) normal shock to hourly-earnings. 7 | 8 | %% Begin setting up to use VFI Toolkit to solve 9 | % Lets model agents from age 20 to age 100, so 81 periods 10 | 11 | Params.agejshifter=19; % Age 20 minus one. Makes keeping track of actual age easy in terms of model age 12 | Params.J=100-Params.agejshifter; % =81, Number of period in life-cycle 13 | 14 | % Grid sizes to use 15 | n_d=51; % Endogenous labour choice (fraction of time worked) 16 | n_a=301; % Endogenous asset holdings 17 | % Exogenous labor productivity units shocks (next two lines) 18 | n_z=15; % AR(1) with age-dependent params 19 | vfoptions.n_e=3; % iid 20 | N_j=Params.J; % Number of periods in finite horizon 21 | 22 | %% Parameters 23 | 24 | % Discount rate 25 | Params.beta = 0.96; 26 | % Preferences 27 | Params.sigma = 2; % Coeff of relative risk aversion (curvature of consumption) 28 | Params.eta = 1.5; % Curvature of leisure (This will end up being 1/Frisch elasty) 29 | Params.psi = 10; % Weight on leisure 30 | 31 | Params.A=1; % Aggregate TFP. Not actually used anywhere. 32 | % Production function 33 | Params.alpha = 0.3; % Share of capital 34 | Params.delta = 0.1; % Depreciation rate of capital 35 | 36 | % Demographics 37 | Params.agej=1:1:Params.J; % Is a vector of all the agej: 1,2,3,...,J 38 | Params.Jr=46; 39 | % Population growth rate 40 | Params.n=0.02; % percentage rate (expressed as fraction) at which population growths 41 | 42 | % Age-dependent labor productivity units 43 | Params.kappa_j=[linspace(0.5,2,Params.Jr-15),linspace(2,1,14),zeros(1,Params.J-Params.Jr+1)]; 44 | % Life-cycle AR(1) process z, on (log) labor productivity units 45 | % Chosen following Karahan & Ozkan (2013) [as used by Fella, Gallipoli & Pan (2019)] 46 | % Originals just cover ages 24 to 60, so I create these, and then repeat first and last periods to fill it out 47 | Params.rho_z=0.7596+0.2039*((1:1:37)/10)-0.0535*((1:1:37)/10).^2+0.0028*((1:1:37)/10).^3; % Chosen following Karahan & Ozkan (2013) [as used by Fella, Gallipoli & Pan (2019)] 48 | Params.sigma_epsilon_z=0.0518-0.0405*((1:1:37)/10)+0.0105*((1:1:37)/10).^2-0.0002*((1:1:37)/10).^3; % Chosen following Karahan & Ozkan (2013) [as used by Fella, Gallipoli & Pan (2019)] 49 | % Note that 37 covers 24 to 60 inclusive 50 | % Now repeat the first and last values to fill in working age, and put zeros for retirement (where it is anyway irrelevant) 51 | Params.rho_z=[Params.rho_z(1)*ones(1,4),Params.rho_z,Params.rho_z(end)*ones(1,4),zeros(1,100-65+1)]; 52 | Params.sigma_epsilon_z=[Params.sigma_epsilon_z(1)*ones(1,4),Params.sigma_epsilon_z,Params.sigma_epsilon_z(end)*ones(1,4),Params.sigma_epsilon_z(end)*ones(1,100-65+1)]; 53 | % Transitory iid shock 54 | Params.sigma_e=0.0410+0.0221*((24:1:60)/10)-0.0069*((24:1:60)/10).^2+0.0008*((24:1:60)/10).^3; 55 | % Now repeat the first and last values to fill in working age, and put zeros for retirement (where it is anyway irrelevant) 56 | Params.sigma_e=[Params.sigma_e(1)*ones(1,4),Params.sigma_e,Params.sigma_e(end)*ones(1,4),Params.sigma_e(end)*ones(1,100-65+1)]; 57 | % Note: These will interact with the endogenous labor so the final labor 58 | % earnings process will not equal that of Karahan & Ozkan (2013) 59 | % Note: Karahan & Ozkan (2013) also have a fixed effect (which they call alpha) and which I ignore here. 60 | 61 | % Conditional survival probabilities: sj is the probability of surviving to be age j+1, given alive at age j 62 | % Most countries have calculations of these (as they are used by the government departments that oversee pensions) 63 | % In fact I will here get data on the conditional death probabilities, and then survival is just 1-death. 64 | % Here I just use them for the US, taken from "National Vital Statistics Report, volume 58, number 10, March 2010." 65 | % I took them from first column (qx) of Table 1 (Total Population) 66 | % Conditional death probabilities 67 | Params.dj=[0.006879, 0.000463, 0.000307, 0.000220, 0.000184, 0.000172, 0.000160, 0.000149, 0.000133, 0.000114, 0.000100, 0.000105, 0.000143, 0.000221, 0.000329, 0.000449, 0.000563, 0.000667, 0.000753, 0.000823,... 68 | 0.000894, 0.000962, 0.001005, 0.001016, 0.001003, 0.000983, 0.000967, 0.000960, 0.000970, 0.000994, 0.001027, 0.001065, 0.001115, 0.001154, 0.001209, 0.001271, 0.001351, 0.001460, 0.001603, 0.001769, 0.001943, 0.002120, 0.002311, 0.002520, 0.002747, 0.002989, 0.003242, 0.003512, 0.003803, 0.004118, 0.004464, 0.004837, 0.005217, 0.005591, 0.005963, 0.006346, 0.006768, 0.007261, 0.007866, 0.008596, 0.009473, 0.010450, 0.011456, 0.012407, 0.013320, 0.014299, 0.015323,... 69 | 0.016558, 0.018029, 0.019723, 0.021607, 0.023723, 0.026143, 0.028892, 0.031988, 0.035476, 0.039238, 0.043382, 0.047941, 0.052953, 0.058457, 0.064494,... 70 | 0.071107, 0.078342, 0.086244, 0.094861, 0.104242, 0.114432, 0.125479, 0.137427, 0.150317, 0.164187, 0.179066, 0.194979, 0.211941, 0.229957, 0.249020, 0.269112, 0.290198, 0.312231, 1.000000]; 71 | % dj covers Ages 0 to 100 72 | Params.sj=1-Params.dj(21:101); % Conditional survival probabilities 73 | Params.sj(end)=0; % In the present model the last period (j=J) value of sj is actually irrelevant 74 | 75 | % Warm glow of bequest 76 | Params.warmglow1=0.3; % (relative) importance of bequests 77 | Params.warmglow2=3; % bliss point of bequests (essentially, the target amount) 78 | Params.warmglow3=Params.sigma; % By using the same curvature as the utility of consumption it makes it much easier to guess appropraite parameter values for the warm glow 79 | 80 | % Taxes 81 | Params.tau = 0.15; % Tax rate on labour income 82 | Params.tau_final=0.1; % We will look at transition path resulting from reduction in tax rate to this level 83 | % In addition to payroll tax rate tau, which funds the pension system we will add a progressive 84 | % income tax which funds government spending. 85 | % The progressive income tax takes the functional form: 86 | % IncomeTax=eta1+eta2*log(Income)*Income; % This functional form is empirically a decent fit for the US tax system 87 | % And is determined by the two parameters 88 | Params.eta1=0.09; % eta1 will be determined in equilibrium to balance gov budget constraint 89 | Params.eta2=0.053; 90 | 91 | % Government spending 92 | Params.GdivYtarget = 0.15; % Government spending as a fraction of GDP (this is essentially just used as a target to define a general equilibrium condition) 93 | 94 | %% Some initial values/guesses for variables that will be determined in general eqm 95 | Params.pension=0.4; % Initial guess (this will be determined in general eqm) 96 | Params.r=0.1; 97 | Params.AccidentBeq=0.03; % Accidental bequests (this is the lump sum transfer) 98 | Params.G=0.2; % Government expenditure 99 | % Params.eta1=0.09; % already set above 100 | 101 | %% Grids 102 | a_grid=10*(linspace(0,1,n_a).^3)'; % The ^3 means most points are near zero, which is where the derivative of the value fn changes most. 103 | 104 | % First, z, the AR(1) with age-dependent parameters 105 | [z_grid_J, pi_z_J] = discretizeLifeCycleAR1_FellaGallipoliPan(Params.rho_z,Params.sigma_epsilon_z,n_z,Params.J); 106 | % z_grid_J is n_z-by-J, so z_grid_J(:,j) is the grid for age j 107 | % pi_z_J is n_z-by-n_z-by-J, so pi_z_J(:,:,j) is the transition matrix for age j 108 | 109 | % Second, e, the iid normal with age-dependent parameters 110 | [e_grid_J, pi_e_J] = discretizeLifeCycleAR1_FellaGallipoliPan(zeros(1,Params.J),Params.sigma_e,vfoptions.n_e,Params.J); % Note: AR(1) with rho=0 is iid normal 111 | % Because e is iid we actually just use 112 | pi_e_J=shiftdim(pi_e_J(1,:,:),1); 113 | 114 | % Any (iid) e variable always has to go into vfoptions and simoptions 115 | vfoptions.e_grid=e_grid_J; 116 | vfoptions.pi_e=pi_e_J; 117 | simoptions.n_e=vfoptions.n_e; 118 | simoptions.e_grid=e_grid_J; 119 | simoptions.pi_e=pi_e_J; 120 | 121 | 122 | % Grid for labour choice 123 | h_grid=linspace(0,1,n_d)'; % Notice that it is imposing the 0<=h<=1 condition implicitly 124 | % Switch into toolkit notation 125 | d_grid=h_grid; 126 | 127 | %% Now, create the return function 128 | DiscountFactorParamNames={'beta','sj'}; 129 | 130 | % Notice we use 'OLGModel6_ReturnFn' 131 | ReturnFn=@(h,aprime,a,z,e,sigma,psi,eta,agej,Jr,J,pension,r,A,delta,alpha,kappa_j,warmglow1,warmglow2,AccidentBeq, eta1,eta2,tau)... 132 | OLGModel6_ReturnFn(h,aprime,a,z,e,sigma,psi,eta,agej,Jr,J,pension,r,A,delta,alpha,kappa_j,warmglow1,warmglow2,AccidentBeq, eta1,eta2,tau); 133 | 134 | %% Now solve the value function iteration problem, just to check that things are working before we go to General Equilbrium 135 | disp('Test ValueFnIter') 136 | tic; 137 | [V, Policy]=ValueFnIter_Case1_FHorz(n_d,n_a,n_z,N_j, d_grid, a_grid, z_grid_J, pi_z_J, ReturnFn, Params, DiscountFactorParamNames, [], vfoptions); 138 | toc 139 | 140 | %% Initial distribution of agents at birth (j=1) 141 | % Before we plot the life-cycle profiles we have to define how agents are 142 | % at age j=1. We will give them all zero assets. 143 | jequaloneDist=zeros([n_a,n_z,vfoptions.n_e],'gpuArray'); % Put no households anywhere on grid 144 | jequaloneDist(1,floor((n_z+1)/2),floor((simoptions.n_e+1)/2))=1; % All agents start with zero assets, and the median shock 145 | 146 | %% Agents age distribution 147 | % Many OLG models include some kind of population growth, and perhaps 148 | % some other things that create a weighting of different ages that needs to 149 | % be used to calculate the stationary distribution and aggregate variable. 150 | % Many OLG models include some kind of population growth, and perhaps 151 | % some other things that create a weighting of different ages that needs to 152 | % be used to calculate the stationary distribution and aggregate variable. 153 | Params.mewj=ones(1,Params.J); % Marginal distribution of households over age 154 | for jj=2:length(Params.mewj) 155 | Params.mewj(jj)=Params.sj(jj-1)*Params.mewj(jj-1)/(1+Params.n); 156 | end 157 | Params.mewj=Params.mewj./sum(Params.mewj); % Normalize to one 158 | 159 | AgeWeightsParamNames={'mewj'}; % So VFI Toolkit knows which parameter is the mass of agents of each age 160 | 161 | %% Test 162 | disp('Test StationaryDist') 163 | StationaryDist=StationaryDist_FHorz_Case1(jequaloneDist,AgeWeightsParamNames,Policy,n_d,n_a,n_z,N_j,pi_z_J,Params,simoptions); 164 | 165 | %% General eqm variables 166 | GEPriceParamNames={'r','pension','AccidentBeq','G','eta1'}; 167 | 168 | %% Set up the General Equilibrium conditions (on assets/interest rate, assuming a representative firm with Cobb-Douglas production function) 169 | % Note: we need to add z & e to FnsToEvaluate inputs. 170 | 171 | % Stationary Distribution Aggregates (important that ordering of Names and Functions is the same) 172 | FnsToEvaluate.H = @(h,aprime,a,z,e) h; % Aggregate labour supply 173 | FnsToEvaluate.L = @(h,aprime,a,z,e,kappa_j) kappa_j*exp(z+e)*h; % Aggregate labour supply in efficiency units 174 | FnsToEvaluate.K = @(h,aprime,a,z,e) a;% Aggregate physical capital 175 | FnsToEvaluate.PensionSpending = @(h,aprime,a,z,e,pension,agej,Jr) (agej>=Jr)*pension; % Total spending on pensions 176 | FnsToEvaluate.AccidentalBeqLeft = @(h,aprime,a,z,e,sj) aprime*(1-sj); % Accidental bequests left by people who die 177 | FnsToEvaluate.IncomeTaxRevenue = @(h,aprime,a,z,e,eta1,eta2,kappa_j,r,delta,alpha,A) OLGModel6_ProgressiveIncomeTaxFn(h,aprime,a,z,e,eta1,eta2,kappa_j,r,delta,alpha,A); % Revenue raised by the progressive income tax (needed own function to avoid log(0) causing problems) 178 | 179 | % General Equilibrium conditions (these should evaluate to zero in general equilbrium) 180 | GeneralEqmEqns.capitalmarket = @(r,K,L,alpha,delta,A) r-alpha*A*(K^(alpha-1))*(L^(1-alpha)); % interest rate equals marginal product of capital net of depreciation 181 | GeneralEqmEqns.pensions = @(PensionSpending,tau,L,r,A,alpha,delta) PensionSpending-tau*(A*(1-alpha)*((r+delta)/(alpha*A))^(alpha/(alpha-1)))*L; % Retirement benefits equal Payroll tax revenue: pension*fractionretired-tau*w*H 182 | GeneralEqmEqns.bequests = @(AccidentalBeqLeft,AccidentBeq,n) AccidentalBeqLeft/(1+n)-AccidentBeq; % Accidental bequests received equal accidental bequests left 183 | GeneralEqmEqns.Gtarget = @(G,GdivYtarget,A,K,L,alpha) G-GdivYtarget*(A*K^(alpha)*(L^(1-alpha))); % G is equal to the target, GdivYtarget*Y 184 | GeneralEqmEqns.govbudget = @(G,IncomeTaxRevenue) G-IncomeTaxRevenue; % Government budget balances (note that pensions are a seperate budget) 185 | % Note: the pensions general eqm condition looks more complicated just because we replaced w with the formula for w in terms of r. It is actually just the same formula as before. 186 | 187 | %% Test 188 | % Note: Because we used simoptions we must include this as an input 189 | disp('Test AggVars') 190 | AggVars=EvalFnOnAgentDist_AggVars_FHorz_Case1(StationaryDist, Policy, FnsToEvaluate, Params, [], n_d, n_a, n_z,N_j, d_grid, a_grid, z_grid_J,[],simoptions); 191 | 192 | %% Solve for the General Equilibrium 193 | heteroagentoptions.verbose=1; 194 | p_eqm=HeteroAgentStationaryEqm_Case1_FHorz(jequaloneDist,AgeWeightsParamNames,n_d, n_a, n_z, N_j, 0, pi_z_J, d_grid, a_grid, z_grid_J, ReturnFn, FnsToEvaluate, GeneralEqmEqns, Params, DiscountFactorParamNames, [], [], [], GEPriceParamNames, heteroagentoptions, simoptions, vfoptions); 195 | % p_eqm contains the general equilibrium parameter values 196 | % Put this into Params so we can calculate things about the initial equilibrium 197 | Params.r=p_eqm.r; 198 | Params.pension=p_eqm.pension; 199 | Params.AccidentBeq=p_eqm.AccidentBeq; 200 | Params.G=p_eqm.G; 201 | Params.eta1=p_eqm.eta1; 202 | 203 | % Calculate a few things related to the general equilibrium. 204 | [V, Policy]=ValueFnIter_Case1_FHorz(n_d,n_a,n_z,N_j, d_grid, a_grid, z_grid_J, pi_z_J, ReturnFn, Params, DiscountFactorParamNames, [], vfoptions); 205 | StationaryDist=StationaryDist_FHorz_Case1(jequaloneDist,AgeWeightsParamNames,Policy,n_d,n_a,n_z,N_j,pi_z_J,Params,simoptions); 206 | % Can just use the same FnsToEvaluate as before. 207 | AgeConditionalStats=LifeCycleProfiles_FHorz_Case1(StationaryDist,Policy,FnsToEvaluate,Params,[],n_d,n_a,n_z,N_j,d_grid,a_grid,z_grid_J,simoptions); 208 | 209 | %% Plot the life cycle profiles of capital and labour for the inital and final eqm. 210 | 211 | figure(1) 212 | subplot(3,1,1); plot(1:1:Params.J,AgeConditionalStats.H.Mean) 213 | title('Life Cycle Profile: Hours Worked') 214 | subplot(3,1,2); plot(1:1:Params.J,AgeConditionalStats.L.Mean) 215 | title('Life Cycle Profile: Labour Supply') 216 | subplot(3,1,3); plot(1:1:Params.J,AgeConditionalStats.K.Mean) 217 | title('Life Cycle Profile: Assets') 218 | % saveas(figure_c,'./SavedOutput/Graphs/OLGModel6_LifeCycleProfiles','pdf') 219 | 220 | %% Calculate some aggregates and print findings about them 221 | 222 | % Add consumption to the FnsToEvaluate 223 | FnsToEvaluate.Consumption=@(h,aprime,a,z,e,agej,Jr,r,pension,tau,kappa_j,alpha,delta,A,eta1,eta2,AccidentBeq) OLGModel6_ConsumptionFn(h,aprime,a,z,e,agej,Jr,r,pension,tau,kappa_j,alpha,delta,A,eta1,eta2,AccidentBeq); 224 | 225 | AggVars=EvalFnOnAgentDist_AggVars_FHorz_Case1(StationaryDist, Policy, FnsToEvaluate, Params, [], n_d, n_a, n_z,N_j, d_grid, a_grid, z_grid_J,[],simoptions); 226 | 227 | % GDP 228 | Y=Params.A*(AggVars.K.Mean^Params.alpha)*(AggVars.L.Mean^(1-Params.alpha)); 229 | 230 | % wage (note that this is calculation is only valid because we have Cobb-Douglas production function and are looking at a stationary general equilibrium) 231 | KdivL=((Params.r+Params.delta)/(Params.alpha*Params.A))^(1/(Params.alpha-1)); 232 | w=Params.A*(1-Params.alpha)*(KdivL^Params.alpha); % wage rate (per effective labour unit) 233 | 234 | fprintf('Following are some aggregates of the model economy: \n') 235 | fprintf('Output: Y=%8.2f \n',Y) 236 | fprintf('Capital-Output ratio: K/Y=%8.2f \n',AggVars.K.Mean/Y) 237 | fprintf('Consumption-Output ratio: C/Y=%8.2f \n',AggVars.Consumption.Mean/Y) 238 | fprintf('Average labor productivity: Y/H=%8.2f \n', Y/AggVars.H.Mean) 239 | fprintf('Government-to-Output ratio: G/Y=%8.2f \n', Params.G/Y) 240 | fprintf('Accidental Bequests as fraction of GDP: %8.2f \n',Params.AccidentBeq/Y) 241 | fprintf('Wage: w=%8.2f \n',w) 242 | 243 | 244 | 245 | -------------------------------------------------------------------------------- /OLGModel6_ConsumptionFn.m: -------------------------------------------------------------------------------- 1 | function c=OLGModel6_ConsumptionFn(h,aprime,a,z,e,agej,Jr,r,pension,tau,kappa_j,alpha,delta,A,eta1,eta2,AccidentBeq) 2 | % Note: these lines are essentially just a copy of the relevant part of the return fn 3 | 4 | KdivL=((r+delta)/(alpha*A))^(1/(alpha-1)); 5 | w=A*(1-alpha)*(KdivL^alpha); % wage rate (per effective labour unit) 6 | 7 | 8 | % Progressive income tax 9 | if agej0 16 | IncomeTax=eta1+eta2*log(Income)*Income; 17 | end 18 | % Note: Have made pensions exempt from income tax. 19 | 20 | if agej0 10 | IncomeTax=eta1+eta2*log(Income)*Income; 11 | end 12 | % Note: Have made pensions exempt from income tax. 13 | 14 | end -------------------------------------------------------------------------------- /OLGModel6_ReturnFn.m: -------------------------------------------------------------------------------- 1 | function F=OLGModel6_ReturnFn(h,aprime,a,z,e,sigma,psi,eta,agej,Jr,J,pension,r,A,delta,alpha,kappa_j,warmglow1,warmglow2,AccidentBeq, eta1,eta2,tau) 2 | % Add idiosyncratic shocks z and e (compared to OLGModel5_ReturnFn) 3 | 4 | KdivL=((r+delta)/(alpha*A))^(1/(alpha-1)); 5 | w=A*(1-alpha)*(KdivL^alpha); % wage rate (per effective labour unit) 6 | 7 | % Progressive income tax 8 | if agej0 15 | IncomeTax=eta1+eta2*log(Income)*Income; 16 | end 17 | % Note: Have made pensions exempt from income tax. 18 | 19 | 20 | F=-Inf; 21 | if agej0 28 | F=(c^(1-sigma))/(1-sigma) -psi*(h^(1+eta))/(1+eta); % The utility function 29 | end 30 | 31 | % Warm-glow bequest 32 | if agej==J % Final period 33 | warmglow=warmglow1*(aprime^(1-warmglow2))/(1-warmglow2); 34 | F=F+warmglow; 35 | end 36 | % Notice that we have modelled the warm-glow in such a way that you only 37 | % get it if you die in the last period (j=J). But we know there is a 1-sj 38 | % risk of dying every period. So we might prefer to model that we get the 39 | % warm glow bequest if we die at any age. The following commented out two lines 40 | % implement this alternative. [note: need to add sj to inputs of ReturnFn to use it] 41 | % warmglow=warmglowparam1*(aprime^(1-warmglowparam2))/(1-warmglowparam2); % Note: same formula as above 42 | % F=F+(1-sj)*warmglow 43 | % Note: if using this, have to make sure sj=0 for j=J. 44 | % Comment: I am not aware of any study saying which of these two 45 | % alternatives works better empirically. 46 | 47 | end 48 | -------------------------------------------------------------------------------- /OLGModel7_DisposableIncomeFn.m: -------------------------------------------------------------------------------- 1 | function disposableincome=OLGModel7_DisposableIncomeFn(h,aprime,a,z,e,agej,Jr,r,pension,tau,kappa_j,alpha,delta,A,eta1,eta2) 2 | % Note: these lines are essentially just a copy of the relevant part of the return fn 3 | 4 | KdivL=((r+delta)/(alpha*A))^(1/(alpha-1)); 5 | w=A*(1-alpha)*(KdivL^alpha); % wage rate (per effective labour unit) 6 | 7 | % Progressive income tax 8 | if agej0 15 | IncomeTax=eta1+eta2*log(Income)*Income; 16 | end 17 | % Note: Have made pensions exempt from income tax. 18 | 19 | 20 | if agej=Jr)*pension; % Total spending on pensions 194 | FnsToEvaluate.AccidentalBeqLeft = @(h,aprime,a,z,e,sj) aprime*(1-sj); % Accidental bequests left by people who die 195 | FnsToEvaluate.IncomeTaxRevenue = @(h,aprime,a,z,e,eta1,eta2,kappa_j,r,delta,alpha,A) OLGModel6_ProgressiveIncomeTaxFn(h,aprime,a,z,e,eta1,eta2,kappa_j,r,delta,alpha,A); % Revenue raised by the progressive income tax (needed own function to avoid log(0) causing problems) 196 | 197 | % General Equilibrium conditions (these should evaluate to zero in general equilbrium) 198 | GeneralEqmEqns.capitalmarket = @(r,K,L,alpha,delta,A) r-alpha*A*(K^(alpha-1))*(L^(1-alpha)); % interest rate equals marginal product of capital net of depreciation 199 | GeneralEqmEqns.pensions = @(PensionSpending,tau,L,r,A,alpha,delta) PensionSpending-tau*(A*(1-alpha)*((r+delta)/(alpha*A))^(alpha/(alpha-1)))*L; % Retirement benefits equal Payroll tax revenue: pension*fractionretired-tau*w*H 200 | GeneralEqmEqns.bequests = @(AccidentalBeqLeft,AccidentBeq,n,g) AccidentalBeqLeft/((1+n)*(1+g))-AccidentBeq; % Accidental bequests received equal accidental bequests left 201 | GeneralEqmEqns.Gtarget = @(G,GdivYtarget,A,K,L,alpha) G-GdivYtarget*(A*K^(alpha)*(L^(1-alpha))); % G is equal to the target, GdivYtarget*Y 202 | GeneralEqmEqns.govbudget = @(G,IncomeTaxRevenue) G-IncomeTaxRevenue; % Government budget balances (note that pensions are a seperate budget) 203 | % Note: the pensions general eqm condition looks more complicated just because we replaced w with the formula for w in terms of r. It is actually just the same formula as before. 204 | 205 | %% Test 206 | % Note: Because we used simoptions we must include this as an input 207 | disp('Test AggVars') 208 | AggVars=EvalFnOnAgentDist_AggVars_FHorz_Case1(StationaryDist, Policy, FnsToEvaluate, Params, [], n_d, n_a, n_z,N_j, d_grid, a_grid, z_grid_J,[],simoptions); 209 | 210 | %% Solve for the General Equilibrium 211 | heteroagentoptions.verbose=1; 212 | p_eqm=HeteroAgentStationaryEqm_Case1_FHorz(jequaloneDist,AgeWeightsParamNames,n_d, n_a, n_z, N_j, 0, pi_z_J, d_grid, a_grid, z_grid_J, ReturnFn, FnsToEvaluate, GeneralEqmEqns, Params, DiscountFactorParamNames, [], [], [], GEPriceParamNames, heteroagentoptions, simoptions, vfoptions); 213 | % p_eqm contains the general equilibrium parameter values 214 | % Put this into Params so we can calculate things about the initial equilibrium 215 | Params.r=p_eqm.r; 216 | Params.pension=p_eqm.pension; 217 | Params.AccidentBeq=p_eqm.AccidentBeq; 218 | Params.G=p_eqm.G; 219 | Params.eta1=p_eqm.eta1; 220 | 221 | % Calculate a few things related to the general equilibrium. 222 | [V, Policy]=ValueFnIter_Case1_FHorz(n_d,n_a,n_z,N_j, d_grid, a_grid, z_grid_J, pi_z_J, ReturnFn, Params, DiscountFactorParamNames, [], vfoptions); 223 | StationaryDist=StationaryDist_FHorz_Case1(jequaloneDist,AgeWeightsParamNames,Policy,n_d,n_a,n_z,N_j,pi_z_J,Params,simoptions); 224 | % Can just use the same FnsToEvaluate as before. 225 | AgeConditionalStats=LifeCycleProfiles_FHorz_Case1(StationaryDist,Policy,FnsToEvaluate,Params,[],n_d,n_a,n_z,N_j,d_grid,a_grid,z_grid_J,simoptions); 226 | 227 | %% Plot the life cycle profiles of capital and labour for the inital and final eqm. 228 | 229 | figure(1) 230 | subplot(3,1,1); plot(1:1:Params.J,AgeConditionalStats.H.Mean) 231 | title('Life Cycle Profile: Hours Worked') 232 | subplot(3,1,2); plot(1:1:Params.J,AgeConditionalStats.L.Mean) 233 | title('Life Cycle Profile: Labour Supply') 234 | subplot(3,1,3); plot(1:1:Params.J,AgeConditionalStats.K.Mean) 235 | title('Life Cycle Profile: Assets') 236 | % saveas(figure_c,'./SavedOutput/Graphs/OLGModel6_LifeCycleProfiles','pdf') 237 | 238 | %% Calculate some aggregates and print findings about them 239 | 240 | % Add consumption to the FnsToEvaluate 241 | FnsToEvaluate.Consumption=@(h,aprime,a,z,e,agej,Jr,r,pension,tau,kappa_j,alpha,delta,A,eta1,eta2,AccidentBeq) OLGModel6_ConsumptionFn(h,aprime,a,z,e,agej,Jr,r,pension,tau,kappa_j,alpha,delta,A,eta1,eta2,AccidentBeq); 242 | 243 | AggVars=EvalFnOnAgentDist_AggVars_FHorz_Case1(StationaryDist, Policy, FnsToEvaluate, Params, [], n_d, n_a, n_z,N_j, d_grid, a_grid, z_grid_J,[],simoptions); 244 | 245 | % GDP 246 | Y=Params.A*(AggVars.K.Mean^Params.alpha)*(AggVars.L.Mean^(1-Params.alpha)); 247 | 248 | % wage (note that this is calculation is only valid because we have Cobb-Douglas production function and are looking at a stationary general equilibrium) 249 | KdivL=((Params.r+Params.delta)/(Params.alpha*Params.A))^(1/(Params.alpha-1)); 250 | w=Params.A*(1-Params.alpha)*(KdivL^Params.alpha); % wage rate (per effective labour unit) 251 | 252 | fprintf('Following are some aggregates of the model economy: \n') 253 | fprintf('Output: Y=%8.2f \n',Y) 254 | fprintf('Capital-Output ratio: K/Y=%8.2f \n',AggVars.K.Mean/Y) 255 | fprintf('Consumption-Output ratio: C/Y=%8.2f \n',AggVars.Consumption.Mean/Y) 256 | fprintf('Average labor productivity: Y/H=%8.2f \n', Y/AggVars.H.Mean) 257 | fprintf('Government-to-Output ratio: G/Y=%8.2f \n', Params.G/Y) 258 | fprintf('Accidental Bequests as fraction of GDP: %8.2f \n',Params.AccidentBeq/Y) 259 | fprintf('Wage: w=%8.2f \n',w) 260 | 261 | %% Now, restore the growth into the economy. 262 | % We need an aribitrary starting point. 263 | % We already have Params.A, just add 264 | Params.N0=1; 265 | 266 | % Number of time periods 267 | T=60; 268 | 269 | % Create a time series for output 270 | % There are essentially just the formulae we used to define the 'hat' 271 | % variables (detrended/removing the deterministic growth), just rearranged. 272 | Y_timeseries=Y*cumprod((1+Params.g)*ones(1,T)).*cumprod((1+Params.n)*ones(1,T))*Params.N0; % Note: this is just how we defined Yhat, but rearranged to instead recover Y 273 | 274 | Ypercapita_timeseries=Y*cumprod((1+Params.g)*ones(1,T)); 275 | 276 | w_timeseries=w*cumprod((1+Params.g)*ones(1,T)); 277 | 278 | r_timeseries=Params.r*ones(1,T); 279 | 280 | K_timeseries=AggVars.K.Mean*cumprod((1+Params.g)*ones(1,T)).*cumprod((1+Params.n)*ones(1,T))*Params.N0; 281 | 282 | effectiveL_timeseries=AggVars.L.Mean*cumprod((1+Params.g)*ones(1,T)).*cumprod((1+Params.n)*ones(1,T))*Params.N0; % This is the term that goes into the Cobb-Douglas production function [the whole (1+g)^t*L term] 283 | 284 | N_timeseries=cumprod((1+Params.n)*ones(1,T))*Params.N0; % Population 285 | 286 | figure(2) 287 | subplot(2,2,1); plot(1:1:T, Y_timeseries,1:1:T, K_timeseries,1:1:T, effectiveL_timeseries) 288 | legend('Output','Physical Capital','Effective Labor input') 289 | subplot(2,2,2); plot(1:1:T, Ypercapita_timeseries,1:1:T, w_timeseries) 290 | legend('Output per capita','wage') 291 | subplot(2,2,3); plot(1:1:T, N_timeseries) 292 | legend('Population') 293 | subplot(2,2,4); plot(1:1:T, r_timeseries) 294 | legend('Interest rate') 295 | 296 | 297 | 298 | -------------------------------------------------------------------------------- /OLGModel8_ReturnFn.m: -------------------------------------------------------------------------------- 1 | function F=OLGModel8_ReturnFn(h,aprime,a,z,e,sigma1,sigma2,agej,Jr,pension,r,A,delta,alpha,kappa_j,warmglow1,warmglow2,warmglow3,beta,sj,tau,g) 2 | % Add deterministic growth g (compared to OLGModel6_ReturnFn) 3 | 4 | KdivL=((r+delta)/(alpha*A))^(1/(alpha-1)); 5 | w=A*(1-alpha)*(KdivL^alpha); % wage rate (per effective labour unit) 6 | 7 | F=-Inf; 8 | if agej0 15 | F=( ((c^sigma1)*((1-h)^sigma2))^(1-sigma2) )/(1-sigma2); % The utility function 16 | end 17 | 18 | % add the warm glow to the return, but only near end of life 19 | if agej>=Jr+10 20 | % Warm glow of bequests 21 | warmglow=warmglow1*(((1+g)*aprime-warmglow2)^(1-warmglow3))/(1-warmglow3); 22 | % Modify for beta and sj (get the warm glow next period if die) 23 | warmglow=beta*(1-sj)*warmglow; 24 | % add the warm glow to the return 25 | F=F+warmglow; 26 | end 27 | 28 | end 29 | -------------------------------------------------------------------------------- /OLGModel9A.m: -------------------------------------------------------------------------------- 1 | %% OLG Model 9A: Quasi-hyperbolic discounting 2 | % Essentially, we just use vfoptions to say we are using quasi-hyperbolic 3 | % discounting, add the parameters we need, and modify 4 | % DiscountFactorParamNames. Both the value function and general equilibrium 5 | % commands know what to do thanks to vfoptions, and there is actually no 6 | % difference to how to do things like agent distribution and evaluating 7 | % functions (so those commands don't need to know we are using 8 | % quasi-hyperbolic discounting) 9 | 10 | % There are essentially three parts to using Quasi-Hyperbolic discounting. 11 | % 1. Use vfoptions to state that you are using Quasi-Hyperbolic discounting (and naive/sophisticated). 12 | % 2. Set the appropriate preference parameter 13 | % 3. Minor adjustment to 'discount factors' 14 | % I have put them all near the top so as to make it easy to see the changes. 15 | 16 | vfoptions.exoticpreferences='QuasiHyperbolic'; % Use the quasi-hyperbolic preferences 17 | % To turn off, either don't declare vfoptions.exoticpreferences, or set vfoptions.exoticpreferences='None' 18 | 19 | % (Optional) Use vfoptions to state whether you want 'naive' or 20 | % 'sophisticated' Quasi-Hyperbolic discounting (optional as naive by default) 21 | vfoptions.quasi_hyperbolic='Naive'; % This is the default 22 | % vfoptions.quasi_hyperbolic='Sopisticated'; 23 | 24 | % Set the appropriate preference parameters 25 | Params.beta0=0.85; % The quasi-hyperbolic discounting parameter controlling 'additional' discounting between 'today and tomorrow' 26 | Params.beta=0.96; % The quasi-hyperbolic discounting parameter controlling discounting between any two periods 27 | % Note that setting beta0=1 would give standard exponential discounting 28 | 29 | % Set up the discount parameters 30 | DiscountFactorParamNames={'beta','sj','beta0'}; 31 | % For quasi-hyperbolic discounting the last element of DiscountFactorParamNames must be the 'additional' discounting from today-to-tomorrow parameter. 32 | 33 | % Done! Not a single change from OLGModel6 from here on :) 34 | 35 | %% Begin setting up to use VFI Toolkit to solve 36 | % Lets model agents from age 20 to age 100, so 81 periods 37 | 38 | Params.agejshifter=19; % Age 20 minus one. Makes keeping track of actual age easy in terms of model age 39 | Params.J=100-Params.agejshifter; % =81, Number of period in life-cycle 40 | 41 | % Grid sizes to use 42 | n_d=51; % Endogenous labour choice (fraction of time worked) 43 | n_a=301; % Endogenous asset holdings 44 | % Exogenous labor productivity units shocks (next two lines) 45 | n_z=15; % AR(1) with age-dependent params 46 | vfoptions.n_e=3; % iid 47 | N_j=Params.J; % Number of periods in finite horizon 48 | 49 | %% Parameters 50 | 51 | % Discount rate 52 | % Params.beta = 0.96; % Set above as part of quasi-hyperbolic discounting 53 | % Preferences 54 | Params.sigma = 2; % Coeff of relative risk aversion (curvature of consumption) 55 | Params.eta = 1.5; % Curvature of leisure (This will end up being 1/Frisch elasty) 56 | Params.psi = 10; % Weight on leisure 57 | 58 | Params.A=1; % Aggregate TFP. Not actually used anywhere. 59 | % Production function 60 | Params.alpha = 0.3; % Share of capital 61 | Params.delta = 0.1; % Depreciation rate of capital 62 | 63 | % Demographics 64 | Params.agej=1:1:Params.J; % Is a vector of all the agej: 1,2,3,...,J 65 | Params.Jr=46; 66 | % Population growth rate 67 | Params.n=0.02; % percentage rate (expressed as fraction) at which population growths 68 | 69 | % Age-dependent labor productivity units 70 | Params.kappa_j=[linspace(0.5,2,Params.Jr-15),linspace(2,1,14),zeros(1,Params.J-Params.Jr+1)]; 71 | % Life-cycle AR(1) process z, on (log) labor productivity units 72 | % Chosen following Karahan & Ozkan (2013) [as used by Fella, Gallipoli & Pan (2019)] 73 | % Originals just cover ages 24 to 60, so I create these, and then repeat first and last periods to fill it out 74 | Params.rho_z=0.7596+0.2039*((1:1:37)/10)-0.0535*((1:1:37)/10).^2+0.0028*((1:1:37)/10).^3; % Chosen following Karahan & Ozkan (2013) [as used by Fella, Gallipoli & Pan (2019)] 75 | Params.sigma_epsilon_z=0.0518-0.0405*((1:1:37)/10)+0.0105*((1:1:37)/10).^2-0.0002*((1:1:37)/10).^3; % Chosen following Karahan & Ozkan (2013) [as used by Fella, Gallipoli & Pan (2019)] 76 | % Note that 37 covers 24 to 60 inclusive 77 | % Now repeat the first and last values to fill in working age, and put zeros for retirement (where it is anyway irrelevant) 78 | Params.rho_z=[Params.rho_z(1)*ones(1,4),Params.rho_z,Params.rho_z(end)*ones(1,4),zeros(1,100-65+1)]; 79 | Params.sigma_epsilon_z=[Params.sigma_epsilon_z(1)*ones(1,4),Params.sigma_epsilon_z,Params.sigma_epsilon_z(end)*ones(1,4),Params.sigma_epsilon_z(end)*ones(1,100-65+1)]; 80 | % Transitory iid shock 81 | Params.sigma_e=0.0410+0.0221*((24:1:60)/10)-0.0069*((24:1:60)/10).^2+0.0008*((24:1:60)/10).^3; 82 | % Now repeat the first and last values to fill in working age, and put zeros for retirement (where it is anyway irrelevant) 83 | Params.sigma_e=[Params.sigma_e(1)*ones(1,4),Params.sigma_e,Params.sigma_e(end)*ones(1,4),Params.sigma_e(end)*ones(1,100-65+1)]; 84 | % Note: These will interact with the endogenous labor so the final labor 85 | % earnings process will not equal that of Karahan & Ozkan (2013) 86 | % Note: Karahan & Ozkan (2013) also have a fixed effect (which they call alpha) and which I ignore here. 87 | 88 | % Conditional survival probabilities: sj is the probability of surviving to be age j+1, given alive at age j 89 | % Most countries have calculations of these (as they are used by the government departments that oversee pensions) 90 | % In fact I will here get data on the conditional death probabilities, and then survival is just 1-death. 91 | % Here I just use them for the US, taken from "National Vital Statistics Report, volume 58, number 10, March 2010." 92 | % I took them from first column (qx) of Table 1 (Total Population) 93 | % Conditional death probabilities 94 | Params.dj=[0.006879, 0.000463, 0.000307, 0.000220, 0.000184, 0.000172, 0.000160, 0.000149, 0.000133, 0.000114, 0.000100, 0.000105, 0.000143, 0.000221, 0.000329, 0.000449, 0.000563, 0.000667, 0.000753, 0.000823,... 95 | 0.000894, 0.000962, 0.001005, 0.001016, 0.001003, 0.000983, 0.000967, 0.000960, 0.000970, 0.000994, 0.001027, 0.001065, 0.001115, 0.001154, 0.001209, 0.001271, 0.001351, 0.001460, 0.001603, 0.001769, 0.001943, 0.002120, 0.002311, 0.002520, 0.002747, 0.002989, 0.003242, 0.003512, 0.003803, 0.004118, 0.004464, 0.004837, 0.005217, 0.005591, 0.005963, 0.006346, 0.006768, 0.007261, 0.007866, 0.008596, 0.009473, 0.010450, 0.011456, 0.012407, 0.013320, 0.014299, 0.015323,... 96 | 0.016558, 0.018029, 0.019723, 0.021607, 0.023723, 0.026143, 0.028892, 0.031988, 0.035476, 0.039238, 0.043382, 0.047941, 0.052953, 0.058457, 0.064494,... 97 | 0.071107, 0.078342, 0.086244, 0.094861, 0.104242, 0.114432, 0.125479, 0.137427, 0.150317, 0.164187, 0.179066, 0.194979, 0.211941, 0.229957, 0.249020, 0.269112, 0.290198, 0.312231, 1.000000]; 98 | % dj covers Ages 0 to 100 99 | Params.sj=1-Params.dj(21:101); % Conditional survival probabilities 100 | Params.sj(end)=0; % In the present model the last period (j=J) value of sj is actually irrelevant 101 | 102 | % Warm glow of bequest 103 | Params.warmglow1=0.3; % (relative) importance of bequests 104 | Params.warmglow2=3; % bliss point of bequests (essentially, the target amount) 105 | Params.warmglow3=Params.sigma; % By using the same curvature as the utility of consumption it makes it much easier to guess appropraite parameter values for the warm glow 106 | 107 | % Taxes 108 | Params.tau = 0.15; % Tax rate on labour income 109 | % In addition to payroll tax rate tau, which funds the pension system we will add a progressive 110 | % income tax which funds government spending. 111 | % The progressive income tax takes the functional form: 112 | % IncomeTax=eta1+eta2*log(Income)*Income; % This functional form is empirically a decent fit for the US tax system 113 | % And is determined by the two parameters 114 | Params.eta1=0.09; % eta1 will be determined in equilibrium to balance gov budget constraint 115 | Params.eta2=0.053; 116 | 117 | % Government spending 118 | Params.GdivYtarget = 0.15; % Government spending as a fraction of GDP (this is essentially just used as a target to define a general equilibrium condition) 119 | 120 | %% Some initial values/guesses for variables that will be determined in general eqm 121 | Params.pension=0.4; % Initial guess (this will be determined in general eqm) 122 | Params.r=0.1; 123 | Params.AccidentBeq=0.03; % Accidental bequests (this is the lump sum transfer) 124 | Params.G=0.2; % Government expenditure 125 | % Params.eta1=0.09; % already set above 126 | 127 | %% Grids 128 | a_grid=10*(linspace(0,1,n_a).^3)'; % The ^3 means most points are near zero, which is where the derivative of the value fn changes most. 129 | 130 | % First, z, the AR(1) with age-dependent parameters 131 | [z_grid_J, pi_z_J] = discretizeLifeCycleAR1_FellaGallipoliPan(Params.rho_z,Params.sigma_epsilon_z,n_z,Params.J); 132 | % z_grid_J is n_z-by-J, so z_grid_J(:,j) is the grid for age j 133 | % pi_z_J is n_z-by-n_z-by-J, so pi_z_J(:,:,j) is the transition matrix for age j 134 | 135 | % Second, e, the iid normal with age-dependent parameters 136 | [e_grid_J, pi_e_J] = discretizeLifeCycleAR1_FellaGallipoliPan(zeros(1,Params.J),Params.sigma_e,vfoptions.n_e,Params.J); % Note: AR(1) with rho=0 is iid normal 137 | % Because e is iid we actually just use 138 | pi_e_J=shiftdim(pi_e_J(1,:,:),1); 139 | 140 | % Any (iid) e variable always has to go into vfoptions and simoptions 141 | vfoptions.e_grid=e_grid_J; 142 | vfoptions.pi_e=pi_e_J; 143 | simoptions.n_e=vfoptions.n_e; 144 | simoptions.e_grid=e_grid_J; 145 | simoptions.pi_e=pi_e_J; 146 | 147 | 148 | % Grid for labour choice 149 | h_grid=linspace(0,1,n_d)'; % Notice that it is imposing the 0<=h<=1 condition implicitly 150 | % Switch into toolkit notation 151 | d_grid=h_grid; 152 | 153 | %% Now, create the return function 154 | % DiscountFactorParamNames={'beta','sj'}; % Set above as part of quasi-hyperbolic discounting 155 | 156 | % Notice we use 'OLGModel6_ReturnFn' 157 | ReturnFn=@(h,aprime,a,z,e,sigma,psi,eta,agej,Jr,J,pension,r,A,delta,alpha,kappa_j,warmglow1,warmglow2,AccidentBeq, eta1,eta2,tau)... 158 | OLGModel6_ReturnFn(h,aprime,a,z,e,sigma,psi,eta,agej,Jr,J,pension,r,A,delta,alpha,kappa_j,warmglow1,warmglow2,AccidentBeq, eta1,eta2,tau); 159 | 160 | %% Now solve the value function iteration problem, just to check that things are working before we go to General Equilbrium 161 | disp('Test ValueFnIter') 162 | tic; 163 | [V, Policy]=ValueFnIter_Case1_FHorz(n_d,n_a,n_z,N_j, d_grid, a_grid, z_grid_J, pi_z_J, ReturnFn, Params, DiscountFactorParamNames, [], vfoptions); 164 | toc 165 | 166 | %% Initial distribution of agents at birth (j=1) 167 | % Before we plot the life-cycle profiles we have to define how agents are 168 | % at age j=1. We will give them all zero assets. 169 | jequaloneDist=zeros([n_a,n_z,vfoptions.n_e],'gpuArray'); % Put no households anywhere on grid 170 | jequaloneDist(1,floor((n_z+1)/2),floor((simoptions.n_e+1)/2))=1; % All agents start with zero assets, and the median shock 171 | 172 | %% Agents age distribution 173 | % Many OLG models include some kind of population growth, and perhaps 174 | % some other things that create a weighting of different ages that needs to 175 | % be used to calculate the stationary distribution and aggregate variable. 176 | % Many OLG models include some kind of population growth, and perhaps 177 | % some other things that create a weighting of different ages that needs to 178 | % be used to calculate the stationary distribution and aggregate variable. 179 | Params.mewj=ones(1,Params.J); % Marginal distribution of households over age 180 | for jj=2:length(Params.mewj) 181 | Params.mewj(jj)=Params.sj(jj-1)*Params.mewj(jj-1)/(1+Params.n); 182 | end 183 | Params.mewj=Params.mewj./sum(Params.mewj); % Normalize to one 184 | 185 | AgeWeightsParamNames={'mewj'}; % So VFI Toolkit knows which parameter is the mass of agents of each age 186 | 187 | %% Test 188 | disp('Test StationaryDist') 189 | StationaryDist=StationaryDist_FHorz_Case1(jequaloneDist,AgeWeightsParamNames,Policy,n_d,n_a,n_z,N_j,pi_z_J,Params,simoptions); 190 | 191 | %% General eqm variables 192 | GEPriceParamNames={'r','pension','AccidentBeq','G','eta1'}; 193 | 194 | %% Set up the General Equilibrium conditions (on assets/interest rate, assuming a representative firm with Cobb-Douglas production function) 195 | % Note: we need to add z & e to FnsToEvaluate inputs. 196 | 197 | % Stationary Distribution Aggregates (important that ordering of Names and Functions is the same) 198 | FnsToEvaluate.H = @(h,aprime,a,z,e) h; % Aggregate labour supply 199 | FnsToEvaluate.L = @(h,aprime,a,z,e,kappa_j) kappa_j*exp(z+e)*h; % Aggregate labour supply in efficiency units 200 | FnsToEvaluate.K = @(h,aprime,a,z,e) a;% Aggregate physical capital 201 | FnsToEvaluate.PensionSpending = @(h,aprime,a,z,e,pension,agej,Jr) (agej>=Jr)*pension; % Total spending on pensions 202 | FnsToEvaluate.AccidentalBeqLeft = @(h,aprime,a,z,e,sj) aprime*(1-sj); % Accidental bequests left by people who die 203 | FnsToEvaluate.IncomeTaxRevenue = @(h,aprime,a,z,e,eta1,eta2,kappa_j,r,delta,alpha,A) OLGModel6_ProgressiveIncomeTaxFn(h,aprime,a,z,e,eta1,eta2,kappa_j,r,delta,alpha,A); % Revenue raised by the progressive income tax (needed own function to avoid log(0) causing problems) 204 | 205 | % General Equilibrium conditions (these should evaluate to zero in general equilbrium) 206 | GeneralEqmEqns.capitalmarket = @(r,K,L,alpha,delta,A) r-alpha*A*(K^(alpha-1))*(L^(1-alpha)); % interest rate equals marginal product of capital net of depreciation 207 | GeneralEqmEqns.pensions = @(PensionSpending,tau,L,r,A,alpha,delta) PensionSpending-tau*(A*(1-alpha)*((r+delta)/(alpha*A))^(alpha/(alpha-1)))*L; % Retirement benefits equal Payroll tax revenue: pension*fractionretired-tau*w*H 208 | GeneralEqmEqns.bequests = @(AccidentalBeqLeft,AccidentBeq,n) AccidentalBeqLeft/(1+n)-AccidentBeq; % Accidental bequests received equal accidental bequests left 209 | GeneralEqmEqns.Gtarget = @(G,GdivYtarget,A,K,L,alpha) G-GdivYtarget*(A*K^(alpha)*(L^(1-alpha))); % G is equal to the target, GdivYtarget*Y 210 | GeneralEqmEqns.govbudget = @(G,IncomeTaxRevenue) G-IncomeTaxRevenue; % Government budget balances (note that pensions are a seperate budget) 211 | % Note: the pensions general eqm condition looks more complicated just because we replaced w with the formula for w in terms of r. It is actually just the same formula as before. 212 | 213 | %% Test 214 | % Note: Because we used simoptions we must include this as an input 215 | disp('Test AggVars') 216 | AggVars=EvalFnOnAgentDist_AggVars_FHorz_Case1(StationaryDist, Policy, FnsToEvaluate, Params, [], n_d, n_a, n_z,N_j, d_grid, a_grid, z_grid_J,[],simoptions); 217 | 218 | %% Solve for the General Equilibrium 219 | heteroagentoptions.verbose=1; 220 | p_eqm=HeteroAgentStationaryEqm_Case1_FHorz(jequaloneDist,AgeWeightsParamNames,n_d, n_a, n_z, N_j, 0, pi_z_J, d_grid, a_grid, z_grid_J, ReturnFn, FnsToEvaluate, GeneralEqmEqns, Params, DiscountFactorParamNames, [], [], [], GEPriceParamNames, heteroagentoptions, simoptions, vfoptions); 221 | % p_eqm contains the general equilibrium parameter values 222 | % Put this into Params so we can calculate things about the initial equilibrium 223 | Params.r=p_eqm.r; 224 | Params.pension=p_eqm.pension; 225 | Params.AccidentBeq=p_eqm.AccidentBeq; 226 | Params.G=p_eqm.G; 227 | Params.eta1=p_eqm.eta1; 228 | 229 | % Calculate a few things related to the general equilibrium. 230 | [V, Policy]=ValueFnIter_Case1_FHorz(n_d,n_a,n_z,N_j, d_grid, a_grid, z_grid_J, pi_z_J, ReturnFn, Params, DiscountFactorParamNames, [], vfoptions); 231 | StationaryDist=StationaryDist_FHorz_Case1(jequaloneDist,AgeWeightsParamNames,Policy,n_d,n_a,n_z,N_j,pi_z_J,Params,simoptions); 232 | % Can just use the same FnsToEvaluate as before. 233 | AgeConditionalStats=LifeCycleProfiles_FHorz_Case1(StationaryDist,Policy,FnsToEvaluate,Params,[],n_d,n_a,n_z,N_j,d_grid,a_grid,z_grid_J,simoptions); 234 | 235 | %% Plot the life cycle profiles of capital and labour for the inital and final eqm. 236 | 237 | figure(1) 238 | subplot(3,1,1); plot(1:1:Params.J,AgeConditionalStats.H.Mean) 239 | title('Life Cycle Profile: Hours Worked') 240 | subplot(3,1,2); plot(1:1:Params.J,AgeConditionalStats.L.Mean) 241 | title('Life Cycle Profile: Labour Supply') 242 | subplot(3,1,3); plot(1:1:Params.J,AgeConditionalStats.K.Mean) 243 | title('Life Cycle Profile: Assets') 244 | % saveas(figure_c,'./SavedOutput/Graphs/OLGModel6_LifeCycleProfiles','pdf') 245 | 246 | %% Calculate some aggregates and print findings about them 247 | 248 | % Add consumption to the FnsToEvaluate 249 | FnsToEvaluate.Consumption=@(h,aprime,a,z,e,agej,Jr,r,pension,tau,kappa_j,alpha,delta,A,eta1,eta2,AccidentBeq) OLGModel6_ConsumptionFn(h,aprime,a,z,e,agej,Jr,r,pension,tau,kappa_j,alpha,delta,A,eta1,eta2,AccidentBeq); 250 | 251 | AggVars=EvalFnOnAgentDist_AggVars_FHorz_Case1(StationaryDist, Policy, FnsToEvaluate, Params, [], n_d, n_a, n_z,N_j, d_grid, a_grid, z_grid_J,[],simoptions); 252 | 253 | % GDP 254 | Y=Params.A*(AggVars.K.Mean^Params.alpha)*(AggVars.L.Mean^(1-Params.alpha)); 255 | 256 | % wage (note that this is calculation is only valid because we have Cobb-Douglas production function and are looking at a stationary general equilibrium) 257 | KdivL=((Params.r+Params.delta)/(Params.alpha*Params.A))^(1/(Params.alpha-1)); 258 | w=Params.A*(1-Params.alpha)*(KdivL^Params.alpha); % wage rate (per effective labour unit) 259 | 260 | fprintf('Following are some aggregates of the model economy: \n') 261 | fprintf('Output: Y=%8.2f \n',Y) 262 | fprintf('Capital-Output ratio: K/Y=%8.2f \n',AggVars.K.Mean/Y) 263 | fprintf('Consumption-Output ratio: C/Y=%8.2f \n',AggVars.Consumption.Mean/Y) 264 | fprintf('Average labor productivity: Y/H=%8.2f \n', Y/AggVars.H.Mean) 265 | fprintf('Government-to-Output ratio: G/Y=%8.2f \n', Params.G/Y) 266 | fprintf('Accidental Bequests as fraction of GDP: %8.2f \n',Params.AccidentBeq/Y) 267 | fprintf('Wage: w=%8.2f \n',w) 268 | 269 | 270 | 271 | -------------------------------------------------------------------------------- /OLGModel9B.m: -------------------------------------------------------------------------------- 1 | %% OLG Model 9B: Epstein-Zin preferences 2 | % Modify OLGModel6 to use Epstein-Zin preferences. 3 | % Epstein-Zin preferences seperate the 'intertemporal elasticity of substitution' from the 'risk aversion' 4 | % (a single parameter determines both in standard vonNeumann-Morgenstern preferences). 5 | % This example uses Epstein-Zin preferences in utility-units (rather than the more traditional 6 | % consumption-units formulation of EZ prefs) 7 | 8 | % There are essentially three parts to using Epstein-Zin preferences. 9 | % 1. Use vfoptions to state that you are using Epstein-Zin preferences. 10 | % 2. Set the appropriate preference parameters 11 | % 3. Be careful about warm-glow of bequests (remove from return function) 12 | 13 | % 1. Use vfoptions to state that you are using Epstein-Zin preferences. 14 | vfoptions.exoticpreferences='EpsteinZin'; % Use Epstein-Zin preferences 15 | vfoptions.EZpositiveutility=0; % utility function is negative 16 | 17 | % 2. Set the appropriate preference parameters 18 | vfoptions.EZriskaversion='phi'; 19 | Params.phi=2; % Risk aversion 20 | % This parameter controls the 'additional risk aversion' relative to vNM risk preferences. 21 | 22 | % 3. Be careful about warm-glow of bequests (remove from return function) 23 | % To be able to use a warm-glow-of-bequests with Epstein-Zin preferences we have to distingush 24 | % conditional survival probabilities from the regular discount factor. 25 | % So below the discount factor is now just beta, and we add 26 | vfoptions.survivalprobability='sj'; 27 | % We no longer include warm-glow of bequests in the return fn. 28 | 29 | % 4. Warm-glow of bequests 30 | % Using warm-glow of bequests together with EZ preferences is subtle, so dealing with them has been mostly automated. 31 | % Need to define two things (if you don't want bequests you simply do not define these) 32 | vfoptions.WarmGlowBequestsFn=@(aprime,sigma,wg,agej,J) (agej==J)*wg*(aprime^(1-sigma))/(1-sigma); % First input arguement must be aprime, after than can be any parameters 33 | Params.wg=1; % controls strength of bequest motive 34 | % Comment: Loosely speaking you want the WarmGlowBequestsFn to output the 'same' 35 | % thing as the return fn. Our utility function has (c^(1-sigma))/(1-sigma) 36 | % and hence we set the warmglow to (aprime^(1-sigma))/(1-sigma). We can 37 | % then control the importance of the warm-glow of bequests by multiplying 38 | % it by a constant, here called wg. Note that to keep this in line with previous models we 39 | % also include a term so that the warm-glow of bequests in only non-zero 40 | % in the final period, hence the (agej==J) 41 | % Comment: If a parameter in the WarmGlowBequestsFn depends on age, then it is the last period of life 42 | % from which the parameter value is taken. So be careful. This may mean you want to create 43 | % an offset version of a parameter to put into the WarmGlowBequestsFn. (E.g., if 44 | % you die at the end of period 20, then it is the period 20 parameter 45 | % values that will be used to evaluate WarmGlowBequestsFn; people often 46 | % think of the warm-glow as being received in the following period.) 47 | 48 | % Have also changed the ReturnFn below (just deleting the warm-glow of bequests from it) 49 | 50 | % Done! Everything else below is unchanged :) 51 | 52 | %% Begin setting up to use VFI Toolkit to solve 53 | % Lets model agents from age 20 to age 100, so 81 periods 54 | 55 | Params.agejshifter=19; % Age 20 minus one. Makes keeping track of actual age easy in terms of model age 56 | Params.J=100-Params.agejshifter; % =81, Number of period in life-cycle 57 | 58 | % Grid sizes to use 59 | n_d=51; % Endogenous labour choice (fraction of time worked) 60 | n_a=301; % Endogenous asset holdings 61 | % Exogenous labor productivity units shocks (next two lines) 62 | n_z=15; % AR(1) with age-dependent params 63 | vfoptions.n_e=3; % iid 64 | N_j=Params.J; % Number of periods in finite horizon 65 | 66 | %% Parameters 67 | 68 | % Discount rate 69 | Params.beta = 0.96; 70 | % Preferences 71 | Params.sigma = 2; % Coeff of relative risk aversion (curvature of consumption) 72 | Params.eta = 1.5; % Curvature of leisure (This will end up being 1/Frisch elasty) 73 | Params.psi = 10; % Weight on leisure 74 | 75 | Params.A=1; % Aggregate TFP. Not actually used anywhere. 76 | % Production function 77 | Params.alpha = 0.3; % Share of capital 78 | Params.delta = 0.1; % Depreciation rate of capital 79 | 80 | % Demographics 81 | Params.agej=1:1:Params.J; % Is a vector of all the agej: 1,2,3,...,J 82 | Params.Jr=46; 83 | % Population growth rate 84 | Params.n=0.02; % percentage rate (expressed as fraction) at which population growths 85 | 86 | % Age-dependent labor productivity units 87 | Params.kappa_j=[linspace(0.5,2,Params.Jr-15),linspace(2,1,14),zeros(1,Params.J-Params.Jr+1)]; 88 | % Life-cycle AR(1) process z, on (log) labor productivity units 89 | % Chosen following Karahan & Ozkan (2013) [as used by Fella, Gallipoli & Pan (2019)] 90 | % Originals just cover ages 24 to 60, so I create these, and then repeat first and last periods to fill it out 91 | Params.rho_z=0.7596+0.2039*((1:1:37)/10)-0.0535*((1:1:37)/10).^2+0.0028*((1:1:37)/10).^3; % Chosen following Karahan & Ozkan (2013) [as used by Fella, Gallipoli & Pan (2019)] 92 | Params.sigma_epsilon_z=0.0518-0.0405*((1:1:37)/10)+0.0105*((1:1:37)/10).^2-0.0002*((1:1:37)/10).^3; % Chosen following Karahan & Ozkan (2013) [as used by Fella, Gallipoli & Pan (2019)] 93 | % Note that 37 covers 24 to 60 inclusive 94 | % Now repeat the first and last values to fill in working age, and put zeros for retirement (where it is anyway irrelevant) 95 | Params.rho_z=[Params.rho_z(1)*ones(1,4),Params.rho_z,Params.rho_z(end)*ones(1,4),zeros(1,100-65+1)]; 96 | Params.sigma_epsilon_z=[Params.sigma_epsilon_z(1)*ones(1,4),Params.sigma_epsilon_z,Params.sigma_epsilon_z(end)*ones(1,4),Params.sigma_epsilon_z(end)*ones(1,100-65+1)]; 97 | % Transitory iid shock 98 | Params.sigma_e=0.0410+0.0221*((24:1:60)/10)-0.0069*((24:1:60)/10).^2+0.0008*((24:1:60)/10).^3; 99 | % Now repeat the first and last values to fill in working age, and put zeros for retirement (where it is anyway irrelevant) 100 | Params.sigma_e=[Params.sigma_e(1)*ones(1,4),Params.sigma_e,Params.sigma_e(end)*ones(1,4),Params.sigma_e(end)*ones(1,100-65+1)]; 101 | % Note: These will interact with the endogenous labor so the final labor 102 | % earnings process will not equal that of Karahan & Ozkan (2013) 103 | % Note: Karahan & Ozkan (2013) also have a fixed effect (which they call alpha) and which I ignore here. 104 | 105 | % Conditional survival probabilities: sj is the probability of surviving to be age j+1, given alive at age j 106 | % Most countries have calculations of these (as they are used by the government departments that oversee pensions) 107 | % In fact I will here get data on the conditional death probabilities, and then survival is just 1-death. 108 | % Here I just use them for the US, taken from "National Vital Statistics Report, volume 58, number 10, March 2010." 109 | % I took them from first column (qx) of Table 1 (Total Population) 110 | % Conditional death probabilities 111 | Params.dj=[0.006879, 0.000463, 0.000307, 0.000220, 0.000184, 0.000172, 0.000160, 0.000149, 0.000133, 0.000114, 0.000100, 0.000105, 0.000143, 0.000221, 0.000329, 0.000449, 0.000563, 0.000667, 0.000753, 0.000823,... 112 | 0.000894, 0.000962, 0.001005, 0.001016, 0.001003, 0.000983, 0.000967, 0.000960, 0.000970, 0.000994, 0.001027, 0.001065, 0.001115, 0.001154, 0.001209, 0.001271, 0.001351, 0.001460, 0.001603, 0.001769, 0.001943, 0.002120, 0.002311, 0.002520, 0.002747, 0.002989, 0.003242, 0.003512, 0.003803, 0.004118, 0.004464, 0.004837, 0.005217, 0.005591, 0.005963, 0.006346, 0.006768, 0.007261, 0.007866, 0.008596, 0.009473, 0.010450, 0.011456, 0.012407, 0.013320, 0.014299, 0.015323,... 113 | 0.016558, 0.018029, 0.019723, 0.021607, 0.023723, 0.026143, 0.028892, 0.031988, 0.035476, 0.039238, 0.043382, 0.047941, 0.052953, 0.058457, 0.064494,... 114 | 0.071107, 0.078342, 0.086244, 0.094861, 0.104242, 0.114432, 0.125479, 0.137427, 0.150317, 0.164187, 0.179066, 0.194979, 0.211941, 0.229957, 0.249020, 0.269112, 0.290198, 0.312231, 1.000000]; 115 | % dj covers Ages 0 to 100 116 | Params.sj=1-Params.dj(21:101); % Conditional survival probabilities 117 | Params.sj(end)=0; % In the present model the last period (j=J) value of sj is actually irrelevant 118 | 119 | % Taxes 120 | Params.tau = 0.15; % Tax rate on labour income 121 | % In addition to payroll tax rate tau, which funds the pension system we will add a progressive 122 | % income tax which funds government spending. 123 | % The progressive income tax takes the functional form: 124 | % IncomeTax=eta1+eta2*log(Income)*Income; % This functional form is empirically a decent fit for the US tax system 125 | % And is determined by the two parameters 126 | Params.eta1=0.09; % eta1 will be determined in equilibrium to balance gov budget constraint 127 | Params.eta2=0.053; 128 | 129 | % Government spending 130 | Params.GdivYtarget = 0.15; % Government spending as a fraction of GDP (this is essentially just used as a target to define a general equilibrium condition) 131 | 132 | %% Some initial values/guesses for variables that will be determined in general eqm 133 | Params.pension=0.4; % Initial guess (this will be determined in general eqm) 134 | Params.r=0.1; 135 | Params.AccidentBeq=0.03; % Accidental bequests (this is the lump sum transfer) 136 | Params.G=0.2; % Government expenditure 137 | % Params.eta1=0.09; % already set above 138 | 139 | %% Grids 140 | a_grid=10*(linspace(0,1,n_a).^3)'; % The ^3 means most points are near zero, which is where the derivative of the value fn changes most. 141 | 142 | % First, z, the AR(1) with age-dependent parameters 143 | [z_grid_J, pi_z_J] = discretizeLifeCycleAR1_FellaGallipoliPan(Params.rho_z,Params.sigma_epsilon_z,n_z,Params.J); 144 | % z_grid_J is n_z-by-J, so z_grid_J(:,j) is the grid for age j 145 | % pi_z_J is n_z-by-n_z-by-J, so pi_z_J(:,:,j) is the transition matrix for age j 146 | 147 | % Second, e, the iid normal with age-dependent parameters 148 | [e_grid_J, pi_e_J] = discretizeLifeCycleAR1_FellaGallipoliPan(zeros(1,Params.J),Params.sigma_e,vfoptions.n_e,Params.J); % Note: AR(1) with rho=0 is iid normal 149 | % Because e is iid we actually just use 150 | pi_e_J=shiftdim(pi_e_J(1,:,:),1); 151 | 152 | % Any (iid) e variable always has to go into vfoptions and simoptions 153 | vfoptions.e_grid=e_grid_J; 154 | vfoptions.pi_e=pi_e_J; 155 | simoptions.n_e=vfoptions.n_e; 156 | simoptions.e_grid=e_grid_J; 157 | simoptions.pi_e=pi_e_J; 158 | 159 | 160 | % Grid for labour choice 161 | h_grid=linspace(0,1,n_d)'; % Notice that it is imposing the 0<=h<=1 condition implicitly 162 | % Switch into toolkit notation 163 | d_grid=h_grid; 164 | 165 | %% Now, create the return function 166 | DiscountFactorParamNames={'beta'}; % Just beta, we are using EZ prefs with a warm-glow of bequests, so we had to treat the conditional survival probabilities specially 167 | 168 | % Note, 'OLGModel9B_ReturnFn' is just a copy of 'OLGModel6_ReturnFn', except that we have to delete the part about warm-glow of bequests as this has to be treated specially when using EZ. 169 | % EZ preferences add more risk aversion to this. 170 | ReturnFn=@(h,aprime,a,z,e,sigma,psi,eta,agej,Jr,pension,r,A,delta,alpha,kappa_j,AccidentBeq, eta1,eta2,tau)... 171 | OLGModel9B_ReturnFn(h,aprime,a,z,e,sigma,psi,eta,agej,Jr,pension,r,A,delta,alpha,kappa_j,AccidentBeq, eta1,eta2,tau); 172 | 173 | %% Now solve the value function iteration problem, just to check that things are working before we go to General Equilbrium 174 | disp('Test ValueFnIter') 175 | tic; 176 | [V, Policy]=ValueFnIter_Case1_FHorz(n_d,n_a,n_z,N_j, d_grid, a_grid, z_grid_J, pi_z_J, ReturnFn, Params, DiscountFactorParamNames, [], vfoptions); 177 | toc 178 | 179 | %% Initial distribution of agents at birth (j=1) 180 | % Before we plot the life-cycle profiles we have to define how agents are 181 | % at age j=1. We will give them all zero assets. 182 | jequaloneDist=zeros([n_a,n_z,vfoptions.n_e],'gpuArray'); % Put no households anywhere on grid 183 | jequaloneDist(1,floor((n_z+1)/2),floor((simoptions.n_e+1)/2))=1; % All agents start with zero assets, and the median shock 184 | 185 | %% Agents age distribution 186 | % Many OLG models include some kind of population growth, and perhaps 187 | % some other things that create a weighting of different ages that needs to 188 | % be used to calculate the stationary distribution and aggregate variable. 189 | % Many OLG models include some kind of population growth, and perhaps 190 | % some other things that create a weighting of different ages that needs to 191 | % be used to calculate the stationary distribution and aggregate variable. 192 | Params.mewj=ones(1,Params.J); % Marginal distribution of households over age 193 | for jj=2:length(Params.mewj) 194 | Params.mewj(jj)=Params.sj(jj-1)*Params.mewj(jj-1)/(1+Params.n); 195 | end 196 | Params.mewj=Params.mewj./sum(Params.mewj); % Normalize to one 197 | 198 | AgeWeightsParamNames={'mewj'}; % So VFI Toolkit knows which parameter is the mass of agents of each age 199 | 200 | %% Test 201 | disp('Test StationaryDist') 202 | StationaryDist=StationaryDist_FHorz_Case1(jequaloneDist,AgeWeightsParamNames,Policy,n_d,n_a,n_z,N_j,pi_z_J,Params,simoptions); 203 | 204 | %% General eqm variables 205 | GEPriceParamNames={'r','pension','AccidentBeq','G','eta1'}; 206 | 207 | %% Set up the General Equilibrium conditions (on assets/interest rate, assuming a representative firm with Cobb-Douglas production function) 208 | % Note: we need to add z & e to FnsToEvaluate inputs. 209 | 210 | % Stationary Distribution Aggregates (important that ordering of Names and Functions is the same) 211 | FnsToEvaluate.H = @(h,aprime,a,z,e) h; % Aggregate labour supply 212 | FnsToEvaluate.L = @(h,aprime,a,z,e,kappa_j) kappa_j*exp(z+e)*h; % Aggregate labour supply in efficiency units 213 | FnsToEvaluate.K = @(h,aprime,a,z,e) a;% Aggregate physical capital 214 | FnsToEvaluate.PensionSpending = @(h,aprime,a,z,e,pension,agej,Jr) (agej>=Jr)*pension; % Total spending on pensions 215 | FnsToEvaluate.AccidentalBeqLeft = @(h,aprime,a,z,e,sj) aprime*(1-sj); % Accidental bequests left by people who die 216 | FnsToEvaluate.IncomeTaxRevenue = @(h,aprime,a,z,e,eta1,eta2,kappa_j,r,delta,alpha,A) OLGModel6_ProgressiveIncomeTaxFn(h,aprime,a,z,e,eta1,eta2,kappa_j,r,delta,alpha,A); % Revenue raised by the progressive income tax (needed own function to avoid log(0) causing problems) 217 | 218 | % General Equilibrium conditions (these should evaluate to zero in general equilbrium) 219 | GeneralEqmEqns.capitalmarket = @(r,K,L,alpha,delta,A) r-alpha*A*(K^(alpha-1))*(L^(1-alpha)); % interest rate equals marginal product of capital net of depreciation 220 | GeneralEqmEqns.pensions = @(PensionSpending,tau,L,r,A,alpha,delta) PensionSpending-tau*(A*(1-alpha)*((r+delta)/(alpha*A))^(alpha/(alpha-1)))*L; % Retirement benefits equal Payroll tax revenue: pension*fractionretired-tau*w*H 221 | GeneralEqmEqns.bequests = @(AccidentalBeqLeft,AccidentBeq,n) AccidentalBeqLeft/(1+n)-AccidentBeq; % Accidental bequests received equal accidental bequests left 222 | GeneralEqmEqns.Gtarget = @(G,GdivYtarget,A,K,L,alpha) G-GdivYtarget*(A*K^(alpha)*(L^(1-alpha))); % G is equal to the target, GdivYtarget*Y 223 | GeneralEqmEqns.govbudget = @(G,IncomeTaxRevenue) G-IncomeTaxRevenue; % Government budget balances (note that pensions are a seperate budget) 224 | % Note: the pensions general eqm condition looks more complicated just because we replaced w with the formula for w in terms of r. It is actually just the same formula as before. 225 | 226 | %% Test 227 | % Note: Because we used simoptions we must include this as an input 228 | disp('Test AggVars') 229 | AggVars=EvalFnOnAgentDist_AggVars_FHorz_Case1(StationaryDist, Policy, FnsToEvaluate, Params, [], n_d, n_a, n_z,N_j, d_grid, a_grid, z_grid_J,[],simoptions); 230 | 231 | %% Solve for the General Equilibrium 232 | heteroagentoptions.verbose=1; 233 | p_eqm=HeteroAgentStationaryEqm_Case1_FHorz(jequaloneDist,AgeWeightsParamNames,n_d, n_a, n_z, N_j, 0, pi_z_J, d_grid, a_grid, z_grid_J, ReturnFn, FnsToEvaluate, GeneralEqmEqns, Params, DiscountFactorParamNames, [], [], [], GEPriceParamNames, heteroagentoptions, simoptions, vfoptions); 234 | % p_eqm contains the general equilibrium parameter values 235 | % Put this into Params so we can calculate things about the initial equilibrium 236 | Params.r=p_eqm.r; 237 | Params.pension=p_eqm.pension; 238 | Params.AccidentBeq=p_eqm.AccidentBeq; 239 | Params.G=p_eqm.G; 240 | Params.eta1=p_eqm.eta1; 241 | 242 | % Calculate a few things related to the general equilibrium. 243 | [V, Policy]=ValueFnIter_Case1_FHorz(n_d,n_a,n_z,N_j, d_grid, a_grid, z_grid_J, pi_z_J, ReturnFn, Params, DiscountFactorParamNames, [], vfoptions); 244 | StationaryDist=StationaryDist_FHorz_Case1(jequaloneDist,AgeWeightsParamNames,Policy,n_d,n_a,n_z,N_j,pi_z_J,Params,simoptions); 245 | % Can just use the same FnsToEvaluate as before. 246 | AgeConditionalStats=LifeCycleProfiles_FHorz_Case1(StationaryDist,Policy,FnsToEvaluate,Params,[],n_d,n_a,n_z,N_j,d_grid,a_grid,z_grid_J,simoptions); 247 | 248 | %% Plot the life cycle profiles of capital and labour for the inital and final eqm. 249 | 250 | figure(1) 251 | subplot(3,1,1); plot(1:1:Params.J,AgeConditionalStats.H.Mean) 252 | title('Life Cycle Profile: Hours Worked') 253 | subplot(3,1,2); plot(1:1:Params.J,AgeConditionalStats.L.Mean) 254 | title('Life Cycle Profile: Labour Supply') 255 | subplot(3,1,3); plot(1:1:Params.J,AgeConditionalStats.K.Mean) 256 | title('Life Cycle Profile: Assets') 257 | % saveas(figure_c,'./SavedOutput/Graphs/OLGModel6_LifeCycleProfiles','pdf') 258 | 259 | %% Calculate some aggregates and print findings about them 260 | 261 | % Add consumption to the FnsToEvaluate 262 | FnsToEvaluate.Consumption=@(h,aprime,a,z,e,agej,Jr,r,pension,tau,kappa_j,alpha,delta,A,eta1,eta2,AccidentBeq) OLGModel6_ConsumptionFn(h,aprime,a,z,e,agej,Jr,r,pension,tau,kappa_j,alpha,delta,A,eta1,eta2,AccidentBeq); 263 | 264 | AggVars=EvalFnOnAgentDist_AggVars_FHorz_Case1(StationaryDist, Policy, FnsToEvaluate, Params, [], n_d, n_a, n_z,N_j, d_grid, a_grid, z_grid_J,[],simoptions); 265 | 266 | % GDP 267 | Y=Params.A*(AggVars.K.Mean^Params.alpha)*(AggVars.L.Mean^(1-Params.alpha)); 268 | 269 | % wage (note that this is calculation is only valid because we have Cobb-Douglas production function and are looking at a stationary general equilibrium) 270 | KdivL=((Params.r+Params.delta)/(Params.alpha*Params.A))^(1/(Params.alpha-1)); 271 | w=Params.A*(1-Params.alpha)*(KdivL^Params.alpha); % wage rate (per effective labour unit) 272 | 273 | fprintf('Following are some aggregates of the model economy: \n') 274 | fprintf('Output: Y=%8.2f \n',Y) 275 | fprintf('Capital-Output ratio: K/Y=%8.2f \n',AggVars.K.Mean/Y) 276 | fprintf('Consumption-Output ratio: C/Y=%8.2f \n',AggVars.Consumption.Mean/Y) 277 | fprintf('Average labor productivity: Y/H=%8.2f \n', Y/AggVars.H.Mean) 278 | fprintf('Government-to-Output ratio: G/Y=%8.2f \n', Params.G/Y) 279 | fprintf('Accidental Bequests as fraction of GDP: %8.2f \n',Params.AccidentBeq/Y) 280 | fprintf('Wage: w=%8.2f \n',w) 281 | 282 | 283 | 284 | -------------------------------------------------------------------------------- /OLGModel9B_ReturnFn.m: -------------------------------------------------------------------------------- 1 | function F=OLGModel9B_ReturnFn(h,aprime,a,z,e,sigma,psi,eta,agej,Jr,pension,r,A,delta,alpha,kappa_j,AccidentBeq, eta1,eta2,tau) 2 | % Just deletes the warm-glow of bequests (compared to OLGModel6_ReturnFn), 3 | % as this has to be handled specially for EZ preferences. 4 | 5 | KdivL=((r+delta)/(alpha*A))^(1/(alpha-1)); 6 | w=A*(1-alpha)*(KdivL^alpha); % wage rate (per effective labour unit) 7 | 8 | % Progressive income tax 9 | if agej0 16 | IncomeTax=eta1+eta2*log(Income)*Income; 17 | end 18 | % Note: Have made pensions exempt from income tax. 19 | 20 | 21 | F=-Inf; 22 | if agej0 29 | F=(c^(1-sigma))/(1-sigma) -psi*(h^(1+eta))/(1+eta); % The utility function 30 | end 31 | 32 | 33 | end 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IntroToOLGModels 2 | Building up from a simple OLG 3 | 4 | -------------------------------------------------------------------------------- /TestTheOLGModels.m: -------------------------------------------------------------------------------- 1 | % Run to test all the OLG Models are running without error 2 | 3 | clear all 4 | fprintf('Running OLGModel1 \n') 5 | OLGModel1 6 | 7 | clear all 8 | fprintf('Running OLGModel2 \n') 9 | OLGModel2 10 | 11 | clear all 12 | fprintf('Running OLGModel3 \n') 13 | OLGModel3 14 | 15 | clear all 16 | fprintf('Running OLGModel4 \n') 17 | OLGModel4 18 | 19 | clear all 20 | fprintf('Running OLGModel5 \n') 21 | OLGModel5 22 | 23 | clear all 24 | fprintf('Running OLGModel6 \n') 25 | OLGModel6 26 | 27 | clear all 28 | fprintf('Running OLGModel7 \n') 29 | OLGModel7 30 | 31 | clear all 32 | fprintf('Running OLGModel8 \n') 33 | OLGModel8 34 | 35 | clear all 36 | fprintf('Running OLGModel9A \n') 37 | OLGModel9A 38 | 39 | clear all 40 | fprintf('Running OLGModel9B \n') 41 | OLGModel9B 42 | 43 | clear all 44 | fprintf('Running OLGModel10 \n') 45 | OLGModel10 46 | 47 | clear all 48 | fprintf('Running OLGModel11 \n') 49 | OLGModel11 50 | 51 | clear all 52 | fprintf('Running OLGModel12 \n') 53 | OLGModel12 54 | 55 | clear all 56 | fprintf('Running OLGModel13 \n') 57 | OLGModel13 58 | 59 | clear all 60 | fprintf('Running OLGModel14 \n') 61 | OLGModel14 62 | 63 | % Now the appendix models 64 | addpath('./Appendix/') 65 | 66 | clear all 67 | fprintf('Running Appendix OLGModelB \n') 68 | OLGModelB 69 | 70 | % Now the assignment models 71 | addpath('./Assignments/') 72 | 73 | clear all 74 | fprintf('Running Assignment1_OLGModel \n') 75 | Assignment1_OLGModel 76 | 77 | 78 | --------------------------------------------------------------------------------