From ceb5c9554b1cbfeb3bf7be4046071307d3c459af Mon Sep 17 00:00:00 2001 From: Michael Tiemann Date: Thu, 19 Feb 2026 16:39:08 +1300 Subject: [PATCH 1/7] OLGModel14: tighten GE constraints Discussion here: http://discourse.vfitoolkit.com/t/general-equilibria-and-pricing-tensions/593 --- OLGModel14.m | 44 ++++++++++++++++------------- OLGModel14_FirmReturnFn.m | 4 ++- OLGModel14_HouseholdConsumptionFn.m | 2 +- OLGModel14_HouseholdIncomeFn.m | 2 +- OLGModel14_HouseholdReturnFn.m | 2 +- 5 files changed, 31 insertions(+), 23 deletions(-) diff --git a/OLGModel14.m b/OLGModel14.m index ff4c192..bb9a70a 100644 --- a/OLGModel14.m +++ b/OLGModel14.m @@ -29,18 +29,22 @@ Params.agejshifter=19; % Age 20 minus one. Makes keeping track of actual age easy in terms of model age Params.J=100-Params.agejshifter; % =81, Number of period in life-cycle n_d.household=51; % Endogenous labour choice (fraction of time worked) -n_a.household=501; % Endogenous share holdings +n_a.household=51; % Endogenous share holdings % Exogenous labor productivity units shocks (next two lines) n_z.household=15; % AR(1) with age-dependent params vfoptions.n_e.household=3; % iid N_j.household=Params.J; % Number of periods in finite horizon % Grids to use for firm -n_d.firm=101; % Dividend payment -n_a.firm=501; % Capital holdings +n_d.firm=51; % Dividend payment +n_a.firm=51; % Capital holdings n_z.firm=11; % Productivity shock N_j.firm=Inf; % Infinite horizon +%% Global parameters (applies to household and firm) +% Risk-free rate of return +Params.r=0.05; + %% Parameters for household % Discount rate @@ -124,14 +128,13 @@ % Some initial values/guesses for variables that will be determined in general eqm Params.pension=0.4; % Initial guess (this will be determined in general eqm) -Params.r=0.05; -Params.w=1; -Params.AccidentBeq=0.03; % Accidental bequests (this is the lump sum transfer) +Params.w=1; % Wages, determines (household) labor supply and (firm) demand +Params.AccidentBeq=0.01; % Accidental bequests (this is the lump sum transfer) Params.G=0.1; % Government expenditure Params.firmbeta=1/(1+Params.r/(1-Params.tau_cg)); % 1/(1+r) but returns net of capital gains tax -Params.D=0.2; % Dividends +Params.D=0.2; % Dividends rate expected/received by households Params.P0=1; -Params.Lhscale=0.3; % Scaling the household labor supply +Params.Lhscale=0.26; % Scaling the household labor supply %% Grids for household @@ -139,7 +142,10 @@ d_grid.household=linspace(0,1,n_d.household)'; % Notice that it is imposing the 0<=h<=1 condition implicitly % Grid for share holdings -a_grid.household=10*(linspace(0,1,n_a.household).^3)'; % The ^3 means most points are near zero, which is where the derivative of the value fn changes most. +a_grid_cubed=linspace(0,1,ceil(n_a.household/2)).^3; % The ^3 means most points are near zero, which is where the derivative of the value fn changes most. +a_grid_linear=linspace(1,10,floor(n_a.household/2)+1); +a_grid.household=[a_grid_cubed, a_grid_linear(2:end)]'; +% a_grid.household=linspace(0,6,n_a.household)'; % First, z, the AR(1) with age-dependent parameters [z_grid_J, pi_z_J] = discretizeLifeCycleAR1_FellaGallipoliPan(Params.rho_z,Params.sigma_epsilon_z,n_z.household,Params.J); @@ -165,7 +171,9 @@ %% Grids for firm d_grid.firm=linspace(0,1,n_d.firm)'; % Notice that it is imposing the d>=0 condition implicitly -a_grid.firm=10*(linspace(0,1,n_a.firm).^3)'; % The ^3 means most points are near zero, which is where the derivative of the value fn changes most. +a_grid_cubed=linspace(0,1,ceil(n_a.firm/2)).^3; % The ^3 means most points are near zero, which is where the derivative of the value fn changes most. +a_grid_linear=linspace(1,10,floor(n_a.firm/2)+1); +a_grid.firm=[a_grid_cubed, a_grid_linear(2:end)]'; [z_grid.firm,pi_z.firm] = discretizeAR1_FarmerToda(0,Params.rho_z_firm,Params.sigma_z_e_firm,n_z.firm); z_grid.firm=exp(z_grid.firm); @@ -176,14 +184,14 @@ % For households DiscountFactorParamNames.household={'beta','sj'}; % Notice we use 'OLGModel14_HouseholdReturnFn' -ReturnFn.household=@(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)... - 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); +ReturnFn.household=@(h,sprime,s,z,e,sigma,psi,eta,agej,Jr,J,pension,w,P0,D,kappa_j,warmglow1,warmglow2,AccidentBeq,r,tau_l,tau_d,tau_cg,Lhscale)... + OLGModel14_HouseholdReturnFn(h,sprime,s,z,e,sigma,psi,eta,agej,Jr,J,pension,w,P0,D,kappa_j,warmglow1,warmglow2,AccidentBeq,r,tau_l,tau_d,tau_cg,Lhscale); % For firms DiscountFactorParamNames.firm={'firmbeta'}; % Notice we use 'OLGModel14_FirmReturnFn' -ReturnFn.firm=@(d,kprime,k,z,w,delta,alpha_k,alpha_l,capadjconstant,tau_corp,phi,tau_d,tau_cg)... - OLGModel14_FirmReturnFn(d,kprime,k,z,w,delta,alpha_k,alpha_l,capadjconstant,tau_corp,phi,tau_d,tau_cg); +ReturnFn.firm=@(d,kprime,k,z,w,D,delta,alpha_k,alpha_l,capadjconstant,tau_corp,phi,tau_d,tau_cg)... + OLGModel14_FirmReturnFn(d,kprime,k,z,w,D,delta,alpha_k,alpha_l,capadjconstant,tau_corp,phi,tau_d,tau_cg); %% Now solve the value function iteration problem, just to check that things are working before we go to General Equilbrium disp('Test ValueFnIter') @@ -216,7 +224,7 @@ StationaryDist=StationaryDist_Case1_FHorz_PType(jequaloneDist,AgeWeightsParamNames,PTypeDistParamNames,Policy,n_d,n_a,n_z,N_j,Names_i,pi_z,Params,simoptions); %% General eqm variables -GEPriceParamNames={'r','pension','AccidentBeq','G','w','firmbeta','D','P0','Lhscale'}; +GEPriceParamNames={'pension','AccidentBeq','G','w','firmbeta','D','P0'}; % We don't need P % We can get P from the equation that defines r as the return to the mutual fund % 1+r = (P0 +(1-tau_d)D - tau_cg(P0-P))/Plag @@ -280,7 +288,6 @@ p_eqm=HeteroAgentStationaryEqm_Case1_FHorz_PType(n_d, n_a, n_z, N_j, Names_i, [], pi_z, d_grid, a_grid, z_grid,jequaloneDist, ReturnFn, FnsToEvaluate, GeneralEqmEqns, Params, DiscountFactorParamNames, AgeWeightsParamNames, PTypeDistParamNames, GEPriceParamNames,heteroagentoptions, simoptions, vfoptions); % p_eqm contains the general equilibrium parameter values % Put this into Params so we can calculate things about the initial equilibrium -Params.r=p_eqm.r; Params.pension=p_eqm.pension; Params.AccidentBeq=p_eqm.AccidentBeq; Params.G=p_eqm.G; @@ -288,7 +295,6 @@ Params.firmbeta=p_eqm.firmbeta; Params.D=p_eqm.D; Params.P0=p_eqm.P0; -Params.Lhscale=p_eqm.Lhscale; % Calculate a few things related to the general equilibrium. [V, Policy]=ValueFnIter_Case1_FHorz_PType(n_d,n_a,n_z,N_j, Names_i, d_grid, a_grid, z_grid, pi_z, ReturnFn, Params, DiscountFactorParamNames, vfoptions); @@ -308,8 +314,8 @@ %% Calculate some aggregates and print findings about them % Add consumption to the FnsToEvaluate -FnsToEvaluate.Consumption.household=@(h,sprime,s,z,e,agej,Jr,pension,r,w,P0,D,kappa_j,AccidentBeq,tau_l,tau_d,tau_cg,Lhscale) OLGModel14_HouseholdConsumptionFn(h,sprime,s,z,e,agej,Jr,pension,r,w,P0,D,kappa_j,AccidentBeq,tau_l,tau_d,tau_cg,Lhscale); -FnsToEvaluate.Income.household=@(h,sprime,s,z,e,agej,Jr,pension,r,w,P0,D,kappa_j,AccidentBeq,tau_l,tau_d,tau_cg,Lhscale) OLGModel14_HouseholdIncomeFn(h,sprime,s,z,e,agej,Jr,pension,r,w,P0,D,kappa_j,AccidentBeq,tau_l,tau_d,tau_cg,Lhscale); +FnsToEvaluate.Consumption.household=@(h,sprime,s,z,e,agej,Jr,pension,w,P0,D,kappa_j,AccidentBeq,r,tau_l,tau_d,tau_cg,Lhscale) OLGModel14_HouseholdConsumptionFn(h,sprime,s,z,e,agej,Jr,pension,w,P0,D,kappa_j,AccidentBeq,r,tau_l,tau_d,tau_cg,Lhscale); +FnsToEvaluate.Income.household=@(h,sprime,s,z,e,agej,Jr,pension,w,P0,D,kappa_j,AccidentBeq,r,tau_l,tau_d,tau_cg,Lhscale) OLGModel14_HouseholdIncomeFn(h,sprime,s,z,e,agej,Jr,pension,w,P0,D,kappa_j,AccidentBeq,r,tau_l,tau_d,tau_cg,Lhscale); 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,simoptions); diff --git a/OLGModel14_FirmReturnFn.m b/OLGModel14_FirmReturnFn.m index 9a05e58..c433773 100644 --- a/OLGModel14_FirmReturnFn.m +++ b/OLGModel14_FirmReturnFn.m @@ -1,4 +1,4 @@ -function F=OLGModel14_FirmReturnFn(dividend,kprime,k,z,w,delta,alpha_k,alpha_l,capadjconstant,tau_corp,phi,tau_d,tau_cg) +function F=OLGModel14_FirmReturnFn(dividend,kprime,k,z,w,D,delta,alpha_k,alpha_l,capadjconstant,tau_corp,phi,tau_d,tau_cg) % Whether we set it up so that dividends or equity issuance is the decision % variable is unimportant, here I use dividends as the decision variable. @@ -32,6 +32,8 @@ % Firms per-period objective if s>=0 % enforce that 'no share repurchases allowed' F=((1-tau_d)/(1-tau_cg))*dividend-s; + % Disfavor discrepencies between dividends paid and expected (D) + F=F-(D-dividend)^2; end % Note: dividend payments cannot be negative is enforced by the grid on diff --git a/OLGModel14_HouseholdConsumptionFn.m b/OLGModel14_HouseholdConsumptionFn.m index f5e18d8..b084ebc 100644 --- a/OLGModel14_HouseholdConsumptionFn.m +++ b/OLGModel14_HouseholdConsumptionFn.m @@ -1,4 +1,4 @@ -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) +function c=OLGModel14_HouseholdConsumptionFn(h,sprime,s,z,e,agej,Jr,pension,w,P0,D,kappa_j,AccidentBeq,r,tau_l,tau_d,tau_cg,Lhscale) % Replace assets with 'share holdings' % Get rid of progressive taxes % Add Lhnormalize diff --git a/OLGModel14_HouseholdIncomeFn.m b/OLGModel14_HouseholdIncomeFn.m index 8c2f709..8d8896d 100644 --- a/OLGModel14_HouseholdIncomeFn.m +++ b/OLGModel14_HouseholdIncomeFn.m @@ -1,4 +1,4 @@ -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) +function income=OLGModel14_HouseholdIncomeFn(h,sprime,s,z,e,agej,Jr,pension,w,P0,D,kappa_j,AccidentBeq,r,tau_l,tau_d,tau_cg,Lhscale) % Replace assets with 'share holdings' % Get rid of progressive taxes % Add Lhnormalize diff --git a/OLGModel14_HouseholdReturnFn.m b/OLGModel14_HouseholdReturnFn.m index 35a33a9..02a9ec9 100644 --- a/OLGModel14_HouseholdReturnFn.m +++ b/OLGModel14_HouseholdReturnFn.m @@ -1,4 +1,4 @@ -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) +function F=OLGModel14_HouseholdReturnFn(h,sprime,s,z,e,sigma,psi,eta,agej,Jr,J,pension,w,P0,D,kappa_j,warmglow1,warmglow2,AccidentBeq,r,tau_l,tau_d,tau_cg,Lhscale) % Replace assets with 'share holdings' % Get rid of progressive taxes % Add Lhnormalize From bf8e1092dd07ec3960cc9eaf083b5f8dc527609d Mon Sep 17 00:00:00 2001 From: Michael Tiemann Date: Thu, 19 Feb 2026 23:11:16 +1300 Subject: [PATCH 2/7] Steer wages for better GE Create a GE condition that helps the solver nudge wages to help `L_h` and `L_f` find balance. This also allows us to set `Lhscale` to a more accurate GE balance point without that very setting upsetting the wage equilibrium number so much that our labor constraints never do find a good balance. Also fix sizes of grids, that were too aggressively sized down (and might yet still be, but more testing is needed to tell). --- OLGModel14.m | 11 ++++++----- OLGModel14_GE_wages.m | 27 +++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 OLGModel14_GE_wages.m diff --git a/OLGModel14.m b/OLGModel14.m index bb9a70a..3648c87 100644 --- a/OLGModel14.m +++ b/OLGModel14.m @@ -28,16 +28,16 @@ % Lets model agents from age 20 to age 100, so 81 periods Params.agejshifter=19; % Age 20 minus one. Makes keeping track of actual age easy in terms of model age Params.J=100-Params.agejshifter; % =81, Number of period in life-cycle -n_d.household=51; % Endogenous labour choice (fraction of time worked) -n_a.household=51; % Endogenous share holdings +n_d.household=101; % Endogenous labour choice (fraction of time worked) +n_a.household=101; % Endogenous share holdings % Exogenous labor productivity units shocks (next two lines) n_z.household=15; % AR(1) with age-dependent params vfoptions.n_e.household=3; % iid N_j.household=Params.J; % Number of periods in finite horizon % Grids to use for firm -n_d.firm=51; % Dividend payment -n_a.firm=51; % Capital holdings +n_d.firm=101; % Dividend payment +n_a.firm=101; % Capital holdings n_z.firm=11; % Productivity shock N_j.firm=Inf; % Infinite horizon @@ -134,7 +134,7 @@ Params.firmbeta=1/(1+Params.r/(1-Params.tau_cg)); % 1/(1+r) but returns net of capital gains tax Params.D=0.2; % Dividends rate expected/received by households Params.P0=1; -Params.Lhscale=0.26; % Scaling the household labor supply +Params.Lhscale=0.22; % Scaling the household labor supply %% Grids for household @@ -256,6 +256,7 @@ % General Equilibrium conditions (these should evaluate to zero in general equilbrium) GeneralEqmEqns.sharemarket = @(S) S-1; % mass of all shares equals one GeneralEqmEqns.labormarket = @(L_h,L_f) L_h-L_f; % labor supply of households equals labor demand of firms +GeneralEqmEqns.wages = @(L_h,L_f,w) OLGModel14_GE_wages(L_h,L_f,w); % Push GE toward wage-balanced agreement GeneralEqmEqns.pensions = @(PensionSpending,PayrollTaxRevenue) PensionSpending-PayrollTaxRevenue; % Retirement benefits equal Payroll tax revenue: pension*fractionretired-tau*w*H GeneralEqmEqns.bequests = @(AccidentalBeqLeft,AccidentBeq,n) AccidentalBeqLeft/(1+n)-AccidentBeq; % Accidental bequests received equal accidental bequests left GeneralEqmEqns.govbudget = @(G,tau_d,D,CapitalGainsTaxRevenue,CorpTaxRevenue) G-tau_d*D-CapitalGainsTaxRevenue-CorpTaxRevenue; % G is equal to the target, GdivYtarget*Y diff --git a/OLGModel14_GE_wages.m b/OLGModel14_GE_wages.m new file mode 100644 index 0000000..5bf71c4 --- /dev/null +++ b/OLGModel14_GE_wages.m @@ -0,0 +1,27 @@ +function F=OLGModel14_GE_wages(L_h,L_f,w) +% A continuous function that returns zero when L_h is balanced with L_f +% and otherwise attempts to steer wages (w) toward balancing L_h and L_f + +F=0; + +if (L_h-L_f)^2 <= 10^(-6) + return +elseif L_f>L_h + if w>=1 + % Small increase + F=(L_f/L_h)*(w-1); + else + % Larger increase + F=(L_f/L_h)^2*(1-w); + end +else + if w>1 + % Large decrease (negative) + F=(L_h/L_f)^2*(1-w); + else + % Smaller decrease (negative) + F=(L_h/L_f)*(w-1); + end +end + +end \ No newline at end of file From d72163644d418002ce826a4d0d0e6eaf835d5ea3 Mon Sep 17 00:00:00 2001 From: Michael Tiemann Date: Thu, 19 Feb 2026 23:33:02 +1300 Subject: [PATCH 3/7] Update grid sizes for more accurate HH/Firm value Increasing the household and firm shares and capital holdings grids from 101 to 201 points yielded an increase in agreement in the final value of each others values. With 101 grid points, we saw 0.65 vs. 0.85, a 30% discrepancy. With 201 grid points, we see 113 vs. 117, a 3.5% discrepancy. --- OLGModel14.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OLGModel14.m b/OLGModel14.m index 3648c87..3d1feec 100644 --- a/OLGModel14.m +++ b/OLGModel14.m @@ -29,7 +29,7 @@ Params.agejshifter=19; % Age 20 minus one. Makes keeping track of actual age easy in terms of model age Params.J=100-Params.agejshifter; % =81, Number of period in life-cycle n_d.household=101; % Endogenous labour choice (fraction of time worked) -n_a.household=101; % Endogenous share holdings +n_a.household=201; % Endogenous share holdings % Exogenous labor productivity units shocks (next two lines) n_z.household=15; % AR(1) with age-dependent params vfoptions.n_e.household=3; % iid @@ -37,7 +37,7 @@ % Grids to use for firm n_d.firm=101; % Dividend payment -n_a.firm=101; % Capital holdings +n_a.firm=201; % Capital holdings n_z.firm=11; % Productivity shock N_j.firm=Inf; % Infinite horizon From eb931ba79ddfe48ca61d5ce87258c9cf8d85d4d1 Mon Sep 17 00:00:00 2001 From: Michael Tiemann Date: Fri, 20 Feb 2026 10:46:37 +1300 Subject: [PATCH 4/7] Fix `phi` parameter typo Surely this was meant to be 50%, not 52%. --- OLGModel14.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OLGModel14.m b/OLGModel14.m index 3d1feec..6571e6e 100644 --- a/OLGModel14.m +++ b/OLGModel14.m @@ -110,7 +110,7 @@ Params.capadjconstant=1.21; % term in the capital adjustment cost % Tax Params.tau_corp=0.34; % Tax rate on corporate earnings -Params.phi=0.52; % Fraction of capital adjustment costs that can be deducted from corporate earnings +Params.phi=0.5; % Fraction of capital adjustment costs that can be deducted from corporate earnings Params.tau_d=0.2; % Tax rate on dividends Params.tau_cg=0.2; % Tax rate on capital gains % Idiosyncatic productivity shocks From 43af22d7d961e7664efefcd7e97bb5eafbba3888 Mon Sep 17 00:00:00 2001 From: Michael Tiemann Date: Fri, 20 Feb 2026 17:53:40 +1300 Subject: [PATCH 5/7] Don't let GE_wages stall near w==1 The previous version of this function had the defect that as `w` approached 1, it would return zero, regardless of the relationship of `L_h` and `L_f``. This new version fixes that defect while maintaining its continuous nature. --- OLGModel14_GE_wages.m | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/OLGModel14_GE_wages.m b/OLGModel14_GE_wages.m index 5bf71c4..bd56c42 100644 --- a/OLGModel14_GE_wages.m +++ b/OLGModel14_GE_wages.m @@ -9,18 +9,18 @@ elseif L_f>L_h if w>=1 % Small increase - F=(L_f/L_h)*(w-1); + F=(L_f/L_h)*w; else % Larger increase - F=(L_f/L_h)^2*(1-w); + F=(L_f/L_h)^2/w; end else - if w>1 + if w>=1 % Large decrease (negative) - F=(L_h/L_f)^2*(1-w); + F=-(L_h/L_f)^2*w; else % Smaller decrease (negative) - F=(L_h/L_f)*(w-1); + F=-(L_h/L_f)/w; end end From ee32324669d40c1808c504fe3626028d25278c5f Mon Sep 17 00:00:00 2001 From: Michael Tiemann Date: Fri, 20 Feb 2026 22:30:19 +1300 Subject: [PATCH 6/7] Existing `labormarket` function does wage-steering Deleting `OLGModel14_GE_wages.m` and related function because it's actually redundant with existing `GeneralEqmEqns.labormarket` function. The existing function may do better with a larger weight associated (since it influences the `w` parameter, which in turn influence both labor supply and demand). But we will leave that for others to decide. --- OLGModel14.m | 1 - OLGModel14_GE_wages.m | 27 --------------------------- 2 files changed, 28 deletions(-) delete mode 100644 OLGModel14_GE_wages.m diff --git a/OLGModel14.m b/OLGModel14.m index 6571e6e..561de40 100644 --- a/OLGModel14.m +++ b/OLGModel14.m @@ -256,7 +256,6 @@ % General Equilibrium conditions (these should evaluate to zero in general equilbrium) GeneralEqmEqns.sharemarket = @(S) S-1; % mass of all shares equals one GeneralEqmEqns.labormarket = @(L_h,L_f) L_h-L_f; % labor supply of households equals labor demand of firms -GeneralEqmEqns.wages = @(L_h,L_f,w) OLGModel14_GE_wages(L_h,L_f,w); % Push GE toward wage-balanced agreement GeneralEqmEqns.pensions = @(PensionSpending,PayrollTaxRevenue) PensionSpending-PayrollTaxRevenue; % Retirement benefits equal Payroll tax revenue: pension*fractionretired-tau*w*H GeneralEqmEqns.bequests = @(AccidentalBeqLeft,AccidentBeq,n) AccidentalBeqLeft/(1+n)-AccidentBeq; % Accidental bequests received equal accidental bequests left GeneralEqmEqns.govbudget = @(G,tau_d,D,CapitalGainsTaxRevenue,CorpTaxRevenue) G-tau_d*D-CapitalGainsTaxRevenue-CorpTaxRevenue; % G is equal to the target, GdivYtarget*Y diff --git a/OLGModel14_GE_wages.m b/OLGModel14_GE_wages.m deleted file mode 100644 index bd56c42..0000000 --- a/OLGModel14_GE_wages.m +++ /dev/null @@ -1,27 +0,0 @@ -function F=OLGModel14_GE_wages(L_h,L_f,w) -% A continuous function that returns zero when L_h is balanced with L_f -% and otherwise attempts to steer wages (w) toward balancing L_h and L_f - -F=0; - -if (L_h-L_f)^2 <= 10^(-6) - return -elseif L_f>L_h - if w>=1 - % Small increase - F=(L_f/L_h)*w; - else - % Larger increase - F=(L_f/L_h)^2/w; - end -else - if w>=1 - % Large decrease (negative) - F=-(L_h/L_f)^2*w; - else - % Smaller decrease (negative) - F=-(L_h/L_f)/w; - end -end - -end \ No newline at end of file From aad0be30fb41d27715ff98c7942aecf746f50c25 Mon Sep 17 00:00:00 2001 From: Michael Tiemann Date: Mon, 23 Feb 2026 20:50:10 +1300 Subject: [PATCH 7/7] Remove Lhscale from many functions After studying why my agents were so impoverished, I realized that Lhscale was doing them no favors at all. The one place where Lhscale is needed is when relating L_h to L_f (and perhaps in government taxation functions). But the households don't need it and it only confuses things, especially when we are trying to budget for w=1 and we need to fit things like 0.3 for rent. An Lhscale value of 0.21 inside the consumption function destroys that, pure and simple. This also has the happy(?) effect of restoring `beta` to a value less than 1 (which the comment seemed to expect would be more correct). Here's what the GEq finally looked like: ``` Current GE prices: pension: 0.3999 AccidentBeq: 0.0201 G: 0.0447 w: 1.0228 firmbeta: 0.9516 D: 0.2050 P0: 1.1897 Current aggregate variables: L_h: 0.1808 S: 1.0013 PensionSpending: 0.0614 PayrollTaxRevenue: 0.0370 AccidentalBeqLeft: 0.0140 CapitalGainsTaxRevenue: -0.0246 Output: 0.2792 L_f: 0.1774 K: 0.3599 DividendPaid: 0.2027 Sissued: 0.1513 CorpTaxRevenue: 0.0266 Current GeneralEqmEqns: sharemarket: 0.001347 labormarket: 0.003368 pensions: 0.024378 bequests: -0.006375 govbudget: 0.001803 firmdiscounting: 0.010416 dividends: 0.002340 ShareIssuance: 0.028331 CapitalOutputRatio: -0.001393 Warning: The permanent type mass weights must sum to one (PTypeDistParamNames points to weights that do not sum to one) > In StationaryDist_Case1_FHorz_PType (line 56) In OLGModel14 (line 301) LifeCycleProfiles_FHorz_Case1_PType: Ignoring the 2-th PType, firm because it is infinite horizon Following are some aggregates of the model economy: Output: Y= 0.28 Aggregate TFP: Y= 1.18 Capital-Output ratio (firm side): K/Y= 1.29 Total asset value (HH side): P*S= 1.31 Total firm value (firm side): Value of firm= 1.03 Consumption-Output ratio: C/Y= 2.92 Government-to-Output ratio: G/Y= 0.16 Wage: w= 1.02 Elapsed time is 1042.895036 seconds. ``` --- OLGModel14.m | 16 ++++++++-------- OLGModel14_HouseholdConsumptionFn.m | 4 ++-- OLGModel14_HouseholdIncomeFn.m | 4 ++-- OLGModel14_HouseholdReturnFn.m | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/OLGModel14.m b/OLGModel14.m index 561de40..e446a1f 100644 --- a/OLGModel14.m +++ b/OLGModel14.m @@ -48,11 +48,11 @@ %% Parameters for household % Discount rate -Params.beta = 1.01; % Changed to get S to increase nearer to 1 given r=0.05 (ran it with beta=0.99, got S=0.3, so increased this; note that it interacts with sj to give the actual discount factor) +Params.beta = 0.95; % Changed to get S to increase nearer to 1 given r=0.05 (ran it with beta=0.99, got S=0.3, so increased this; note that it interacts with sj to give the actual discount factor) % Preferences Params.sigma = 2; % Coeff of relative risk aversion (curvature of consumption) Params.eta = 1.5; % Curvature of leisure (This will end up being 1/Frisch elasty) -Params.psi = 10; % Weight on leisure +Params.psi = 2; % Weight on leisure % Demographics Params.agej=1:1:Params.J; % Is a vector of all the agej: 1,2,3,...,J @@ -129,12 +129,12 @@ % Some initial values/guesses for variables that will be determined in general eqm Params.pension=0.4; % Initial guess (this will be determined in general eqm) Params.w=1; % Wages, determines (household) labor supply and (firm) demand -Params.AccidentBeq=0.01; % Accidental bequests (this is the lump sum transfer) +Params.AccidentBeq=0.02; % Accidental bequests (this is the lump sum transfer) Params.G=0.1; % Government expenditure Params.firmbeta=1/(1+Params.r/(1-Params.tau_cg)); % 1/(1+r) but returns net of capital gains tax Params.D=0.2; % Dividends rate expected/received by households Params.P0=1; -Params.Lhscale=0.22; % Scaling the household labor supply +Params.Lhscale=0.21; % Scaling the household labor supply %% Grids for household @@ -184,8 +184,8 @@ % For households DiscountFactorParamNames.household={'beta','sj'}; % Notice we use 'OLGModel14_HouseholdReturnFn' -ReturnFn.household=@(h,sprime,s,z,e,sigma,psi,eta,agej,Jr,J,pension,w,P0,D,kappa_j,warmglow1,warmglow2,AccidentBeq,r,tau_l,tau_d,tau_cg,Lhscale)... - OLGModel14_HouseholdReturnFn(h,sprime,s,z,e,sigma,psi,eta,agej,Jr,J,pension,w,P0,D,kappa_j,warmglow1,warmglow2,AccidentBeq,r,tau_l,tau_d,tau_cg,Lhscale); +ReturnFn.household=@(h,sprime,s,z,e,sigma,psi,eta,agej,Jr,J,pension,w,P0,D,kappa_j,warmglow1,warmglow2,AccidentBeq,r,tau_l,tau_d,tau_cg)... + OLGModel14_HouseholdReturnFn(h,sprime,s,z,e,sigma,psi,eta,agej,Jr,J,pension,w,P0,D,kappa_j,warmglow1,warmglow2,AccidentBeq,r,tau_l,tau_d,tau_cg); % For firms DiscountFactorParamNames.firm={'firmbeta'}; @@ -314,8 +314,8 @@ %% Calculate some aggregates and print findings about them % Add consumption to the FnsToEvaluate -FnsToEvaluate.Consumption.household=@(h,sprime,s,z,e,agej,Jr,pension,w,P0,D,kappa_j,AccidentBeq,r,tau_l,tau_d,tau_cg,Lhscale) OLGModel14_HouseholdConsumptionFn(h,sprime,s,z,e,agej,Jr,pension,w,P0,D,kappa_j,AccidentBeq,r,tau_l,tau_d,tau_cg,Lhscale); -FnsToEvaluate.Income.household=@(h,sprime,s,z,e,agej,Jr,pension,w,P0,D,kappa_j,AccidentBeq,r,tau_l,tau_d,tau_cg,Lhscale) OLGModel14_HouseholdIncomeFn(h,sprime,s,z,e,agej,Jr,pension,w,P0,D,kappa_j,AccidentBeq,r,tau_l,tau_d,tau_cg,Lhscale); +FnsToEvaluate.Consumption.household=@(h,sprime,s,z,e,agej,Jr,pension,w,P0,D,kappa_j,AccidentBeq,r,tau_l,tau_d,tau_cg) OLGModel14_HouseholdConsumptionFn(h,sprime,s,z,e,agej,Jr,pension,w,P0,D,kappa_j,AccidentBeq,r,tau_l,tau_d,tau_cg); +FnsToEvaluate.Income.household=@(h,sprime,s,z,e,agej,Jr,pension,w,P0,D,kappa_j,AccidentBeq,r,tau_l,tau_d,tau_cg) OLGModel14_HouseholdIncomeFn(h,sprime,s,z,e,agej,Jr,pension,w,P0,D,kappa_j,AccidentBeq,r,tau_l,tau_d,tau_cg); 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,simoptions); diff --git a/OLGModel14_HouseholdConsumptionFn.m b/OLGModel14_HouseholdConsumptionFn.m index b084ebc..2dfbfd6 100644 --- a/OLGModel14_HouseholdConsumptionFn.m +++ b/OLGModel14_HouseholdConsumptionFn.m @@ -1,4 +1,4 @@ -function c=OLGModel14_HouseholdConsumptionFn(h,sprime,s,z,e,agej,Jr,pension,w,P0,D,kappa_j,AccidentBeq,r,tau_l,tau_d,tau_cg,Lhscale) +function c=OLGModel14_HouseholdConsumptionFn(h,sprime,s,z,e,agej,Jr,pension,w,P0,D,kappa_j,AccidentBeq,r,tau_l,tau_d,tau_cg) % Replace assets with 'share holdings' % Get rid of progressive taxes % Add Lhnormalize @@ -14,7 +14,7 @@ if agej