Modeling Uncertain Retirement Income

Thanks Robert. But do we still talk about the same problem. Initially I modelling:

a) a tail event resulting in a temporary drop in retirement income (e.g., temporary illness expenses);
b) a tail event resulting in a permanent drop in retirement income (e.g., permanent illness expenses or/and death of a spouse or/and entry into a retirement home);

while I already have two iid shocks in portfolio model like 31: persistent z1 and temporarily z2.

Problem a) is solved. I add iid shock e to existing shocks z1 and z2 (similar to model 11B where are only one z and one e). I additionally require that ‘variability’ of the process e can drop by 50% with probability 10% in each period. More specifically:

[e_grid,pi_e]=discretizeAR1_FarmerToda(0,0,Params.sigma_epsilon_e,n_e-1);
e_grid=exp(e_grid);
pi_e=pi_e(1,:)';
e_grid=[0.5; e_grid];
pi_e=[0.1; (1-0.1)*pi_e];
mean_e=pi_e'*e_grid;
e_grid=e_grid./mean_e;

% + I connect e with pension in return function and modify code also in other required places (vfoptions, simoptions, return function, plots …).

I still struggling with problem b). I trying solve it with implementing your first suggestion:

But recently you suggest:

Does your recent comment still address problem b)? Sorry for continuing to ask questions, but I really want to know how to model b). Is it possible to provide an example of how I can implement your first suggestion? Thank you very much!

I see. For problem (b) you want a markov shock, not an i.i.d. shock (a z not an e in my examples). Because it is markov but you tried to include it as an e (which is for i.i.d.) there are errors.

My impression is you want two z shocks.

For two markov (z) shocks you need to

When you use multiple markov z shocks you need to set up n_z=[n_z1, n_z2]; z_grid=[z1_grid; z2_grid]; and pi_z=kron(pi_z2, pi_z1); (note reverse order in the kron, also the pi_z is here assuming the two shocks are uncorrelated).

and then include (…,z1,z2,…) in your ReturnFn and FnsToEvaluate.


Just looked at your code, and actually it will be three markov z shocks, so set up n_z=[n_z1, n_z2, n_z3]; z_grid=[z1_grid; z2_grid; z3_grid];, and then pi_z12=kron(pi_z2, pi_z1); and pi_z=kron(pi_z3, pi_12); (the pi_z is here assuming the three shocks are uncorrelated).
[pi_z12 is not actually needed for anything, figured it is easier to read as two steps, rather than just pi_z=kron(pi_z3, kron(pi_z2, pi_z1))]

and then include (…,z1,z2,z3,…) in your ReturnFn and FnsToEvaluate.

Note, you probably want to have the markov be age-dependent (I have glossed over this).

2 Likes

Yes, I already have two labour shocks: z1 is persistent, modelled as AR(1), and z2 transitory, modelled as iid. I actually model z1 and z2 as you suggested in model 11A. z1 therefore should be markov and z2 iid.

Yes, now I want third shock that is markov and address problem b) as you suggestion (z3_grid=[1;0.5]; and pi_z3=[0.9, 0.1; 0, 1]; ) but do not know how to introduce this into code.

So finally, there will be two makrov (z1 and z3) and one iid (z2) shocks. Is this correct?

However, I introduced your suggestions as follows:

n_z=[21,5,2];
  
% z1_grid … as already defined
% z2_grid … as already defined
  
% I think here missing something
z3_grid=[1;0.5];
pi_z3=[0.9, 0.1; 0, 1];
  
z_grid=[z1_grid; z2_grid; z3_grid];
pi_z=kron(pi_z3, kron(pi_z2, pi_z1));

% + other changes

Value and policy functions and also calculations of life-cycle profile are going through now without errors but plots are empty although in change some plotting and other settings. I think something still missing in the code which I saved here (code).

[Yes, I want that z3 shock depend on ages. I was thinking to use somehow probability of dead (1-survival probability) since I trying to capture effect of death of spouse on household pension. However, firstly I would like to solve issue with z3 without age dependency.]

1 Like

As far as I understand, now you have 3 z shocks and no e shocks, is that correct?

The shock z2 is iid so its transition matrix pi_z2 should have identical rows

1 Like

Yes, I have 3 z shocks and no e shock.

The model with just z1 and z2 works fine. The problem is that I am not able to introduce z3, which will account for, e.g., a 10% possibility that retirement income at each age drops by 50% and stays at that level forever (z3_grid=[1;0.5]; and pi_z3=[0.9, 0.1; 0, 1];).

1 Like

If they are two markov and one i.i.d., then you can just set up as:
(…,z1,z2,e,…)

Use n_z=[n_z1, n_z2]; z_grid=[z1_grid; z2_grid]; and pi_z=kron(pi_z2, pi_z1) for your two markov shocks;. And set up n_e, e_grid, and pi_e appropriately (for your one i.i.d. shock).

But you must use the ordering of markov shocks and then i.i.d. shocks.


What do you mean by “plots are empty”? If you mean the plots of V and Policy, this is because the shape of them has changed (look at size(V), it will include the dimensions of all your shocks). The life-cycle plots should still show okay do they?

PS. You should set up i.i.d as in LifeCycleModel11B, not 11A. Cleaning up the Appendix on shocks is on my to-do list and I plan to eliminate 11A as part of this (I will still give it as an example in the appendix, but it is never how you want to do things, it exists because in the early days of the toolkit there was no specific i.i.d. e shock feature so you just had to pretend they were markov).

2 Likes

OK, I will make as you suggested (11B): persistent labour (markov) shock and permanent retirement (markov) shock as z1 and z2 and then transitory labour (iid) shock as e1. Consequently, computation will be faster, but the results/problems will be the same?

I mean that graphs for V and policies are blank, without expected curves. Yes, size(V) has increased for the new shock, but I included this change into plotting settings. However, my modifications are maybe wrong. Actually, I made the following modifications:

%% For V and policy plots

zind_3=floor(n_z(3)+1)/2;
% + add zind_3 in required places

% After I run plots, I receive:    
% Subscript indices must either be real positive integers or logicals.


%% For life-cycle plots
jequaloneDist(1,floor((n_z(1)+1)/2),floor((n_z(2)+1)/2),floor((n_z(3)+1)/2))=1; % I extend jequaloneDist for floor((n_z(3)+1)/2)
% + add z3 to FnsToEvaluate

% After I run:
AgeConditionalStats=LifeCycleProfiles_FHorz_Case1(StationaryDist,Policy,FnsToEvaluate,Params,[],n_d,n_a,n_z,N_j,d_grid,a_grid,z_grid,simoptions);

% I receive:
% Error using CreateCellFromParams (line 56)
% Failed to find parameter: z3
% Error in LifeCycleProfiles_FHorz_Case1 (line 458)

[Yes, this with markov and iid shock can be confusing in appendix, although iid is a special kind of Markov shock. It would be great to have some more examples of how to model more shocks, e.g., two markov and two iid.]

Hi Robert, life cycle plots work just fine, as you say. :slight_smile: The case was that I have z3 in the wrong place in FnsToEvaluate.earnings. (FnsToEvaluate.earnings = @(savings, riskyshare, a, z1, z2, w, kappa_j, z3) instead of FnsToEvaluate.earnings = @(savings, riskyshare, a, z1, z2, z3, w, kappa_j)).

Problem with V and policy plots, of course, persists. Probably due to some misspecification on my side, but I have no idea what is wrong. :frowning:

1 Like

I reformulate model in the way that persistent labour z1 and permanent retirement z2 shocks are markov while transitory labour shock e is now iid (consistent with model 11B). However, problem with plotting V and policy remain the same.

Fortunately, I found the reason for roblem with plotting V and policy. The case is in zind_2 = floor(n_z(2)+1)/2 which give value 1.5 and consequently reshaping V(:,zind_1,zind_2,eind_1,: ) give error (subscript indices must either be real positive integers or logicals). I change zind_2 = floor(n_z(2))/2 which give value 1 and consequently V(:,zind_1,zind_2,eind_1,: ) go through and V and policy function can be plotted. However, floor for z2 is now defined differently than for z1 and e. Thanks for tip Robert.

2 Likes

Fantastic :smiley:

When I get around to the overhaul of the Appendix of exogenous shocks I will keep in mind what you said about an example with two markov (z) and two i.i.d (e) shocks.

All codes should work with up to four of each shock type.

2 Likes

Hi Robert, I am extending uncertain retirement income with the addition of age-dependency. Currently, I have the following model, which works fine:

2 Markov shocks:

  • persistent labor shock z1;
  • permanent retirement shock (e.g., death of spouse) z2.

2 iid shocks:

  • transitory labor shock e1;
  • transitory retirement shock (e.g., health expenses) e2.

Based on discussion in the topic “Age-dependent health shocks” I introduce age-dependency to z2 as follows:

% Permanent retirement shock (death of spouse) z2 (age-dependent)
z2_grid=[1;0.5]; % 50% probability of a pension drop
Params.dj_1=Params.dj(21:101);
p_B_j = zeros(1,N_j); % hance that the drop remains forever 
pi_z2_J = zeros(n_z(2),n_z(2),N_j);

for j=1:N_j
    prob_j = [Params.dj_1(j),1-Params.dj_1(j);
              p_B_j(j),1-p_B_j(j)];
    pi_z2_J(:,:,j) = prob_j;
end

% Combine z1, z2 together
z_grid=[z1_grid; z2_grid];
pi_z  = zeros(n_z(1)*n_z(2),n_z(1)*n_z(2),N_j); 
for j=1:N_j
    pi_z(:,:,j)  = kron(pi_z2_J(:,:,j),pi_z1);  
end

I think the code should be fine to some extent. However, I receive the following error when I try to solve the value function iteration:

tic;
[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);
toc
Test ValueFnIter
Warning: When using vfoptions.riskyasset you should also set vfoptions.refine_d (you do not have refine_d, and this is making codes way slower
than they should be) 
> In ValueFnIter_Case1_FHorz_RiskyAsset (line 74)
In ValueFnIter_Case1_FHorz (line 535) 
Error using CreateReturnFnMatrix_Case2_Disc_Par2e (line 358)
gpuArray/arrayfun encountered an issue while compiling 'PortfolioCoiceModel5_ReturnFn (line 7)'.

Error in ValueFnIter_Case1_FHorz_RiskyAsset_noa1_e_raw (line 34)
        ReturnMatrix=CreateReturnFnMatrix_Case2_Disc_Par2e(ReturnFn, n_d, n_a, n_z, n_e, d_grid, a_grid, z_gridvals_J(:,:,N_j), e_gridvals_J(:,:,N_j), ReturnFnParamsVec);

Error in ValueFnIter_Case1_FHorz_RiskyAsset (line 80)
                [VKron, PolicyKron]=ValueFnIter_Case1_FHorz_RiskyAsset_noa1_e_raw(n_d,n_a2,n_z,vfoptions.n_e,n_u, N_j, d_grid, a2_grid, z_gridvals_J, vfoptions.e_gridvals_J, u_grid, pi_z_J, vfoptions.pi_e_J, pi_u, ReturnFn, aprimeFn, Parameters, DiscountFactorParamNames, ReturnFnParamNames, aprimeFnParamNames, vfoptions);

Error in ValueFnIter_Case1_FHorz (line 535)
    [V,Policy]=ValueFnIter_Case1_FHorz_RiskyAsset(n_d,n_a1,n_a2,n_z,vfoptions.n_u, N_j, d_grid, a1_grid, a2_grid, z_gridvals_J, vfoptions.u_grid, pi_z_J, vfoptions.pi_u, ReturnFn, vfoptions.aprimeFn, Parameters, DiscountFactorParamNames, ReturnFnParamNames, vfoptions);

Caused by:
    Unable to find function, variable, or class 'e' on the MATLAB Path. Make sure your search path includes the correct folders.

Related documentation

As you see, I did not yet introduce vfoptions.refine_d because I get another error (I will report it in topic ‘Riskyasset (portfolio-choice) now much faster with refine’).

Many thanks.

1 Like

My impression:

  • You get pi_z_J correct (you call it pi_z, but that does not matter in any way, just using my own notation to make clear in notation what does and does not depend on age). The size of it is prod(n_z)-by-prod(n_z)-by-N_j, and the matrix pi_z_J(:,:,jj) represents the transition matrix from period jj to period jj+1 for the markov. [looks like you put the two markovs together correctly]
  • But you just have z_grid being sum(n_z)-by-1 which is not age-dependent.
  • VFI Toolkit assumes either (i) z_grid and pi_z both do not depend on age, or (ii) z_grid_J and pi_z_J do both depend on age. Because you mix the two there is the error (I am guessing this is what the cause of that error is).
  • Solution, just do z_grid_J=z_grid.*ones(1,N_j), so z_grid_J end up being of size sum(n_z)-by-N_j (every column will be the same as you want the same grid at all ages, but that is fine). Now you will be case (ii).

PS. I assume that you have n_z and n_e set correct (e.g., n_z=[5,2] and n_e=[7,3] or somesuch), and that you put n_e in vfoptions and simoptions (same for e_grid and pi_e). The inputs to the ReturnFn should be (…,z1,z2,e1,e2,…)

2 Likes

Now it works. :slight_smile: Thanks

1 Like

I think there is a typo in your first bullet point, Robert:

The size of it is prod(n_z)-by-prod(n_j)-by-N_j, and the matrix pi_z_J(:,:,jj)

The size should be prod(n_z)-by-prod(n_z)-by-N_j

2 Likes

Quite right. Fixed. Thanks!

2 Likes