Mountford Uhlig JAE 2009 |
This is a set of replication files for Mountford & Uhlig(2009). This extends the work done in Uhlig(2005). This extracts a set of four shocks ("business cycle", "monetary policy", "revenue" and "spending") from a 10 variable VAR. The two shocks of particular interest are revenue and spending, which are assumed to be orthogonal to the first two. They are actually analyzed in parallel rather than sequentially (they are each orthogonal to the cycle and money shocks, but not to each other).
Note well that this is a very technically demanding piece of analysis. This type of model is covered in considerable detail as part of the Vector Autoregressions e-course.
This has four separate programs and a "setup" file which does the data transformations and model setup common to all four of the programs:
MU2009B1.RPF
This does the analysis with 4 period sign-constrained shocks, including the combination shocks to do the various forms of fiscal policy experiments.
MU2009B2.RPF
This does the analysis with "delayed" (forced zero) responses.
MU2009X1.RPF
This does the same analysis as MU2009B1.RPF but uses the rejection method rather than penalty functions (not done in the paper).
MU2009X2.RPF
This does the same analysis as MU2009B2.RPF but uses the rejection method rather than penalty functions (not done in the paper).
MUJAESETUP.SRC
This is the set up file, which reads and transforms the data, sets up and estimates the model and prepares matrices for use in the Monte Carlo integration.
The first two programs use a different method for handling the minimization of the penalty function than was done by the authors. Instead of doing each optimization twice, then rejecting draws where the modes don't match up, it does a slower broad scan with the genetic algorithm as the preliminary method, which seems in practice to find the global optimum with very high reliability. With this (fairly large) model, it's able to do 250 draws in about five minutes, which is much faster than the Gauss code provided by the authors.
The "X1" and "X2" programs do the same analysis, but use the "rejection" method that was used heavily in Uhlig's earlier work.
Adapting to a Different Model
Because it's a rather large model, the "setup" that is specific to the authors' work is in the separate "source" file MUJAESETUP.SRC which each of the four working programs pulls in right at the start. The following sets up the VAR and creates descriptive labels for use in the graphs.
system(model=varmodel)
variables rgdp rbpexp rbprev ffrt ares ppic gdpdef rcon rnresinv wage
lags 1 to 6
end(system)
estimate(noprint)
*
dec vect[strings] vl(10)
compute vl=||"GDP","Expenditure","Revenue","Federal Rate","Reserves","PPI",$
"GDP deflator","Consumption","Investment","Wages"||
This is the number of variables in the model and the number of impulse response steps to compute. This is not the number that are constrained—typically it will be quite a bit higher, but should be reasonable given the frequency of the data. (Anything more than five years is probably too many.)
compute nvar =10
compute nstep =25
The remainder of the "setup" file is standard.
For the MU2009B1.RPF program, the following set up most of the information for the shocks (except for the specific "shapes"). KMIN and KMAX are range of steps to be sign-constrained—note that these are 1-based positions, so the impact is at 1.
compute KMIN =1
compute KMAX =4
These define descriptive labels for the four shocks.
compute nshocks=4
dec vect[strings] sl(nshocks)
compute sl=||"Business Cycle","Monetary Policy","Revenue","Spending"||
The following set up the parameter vectors for the nested optimization problems. They should have a size equal to the number of variables, less 1 + the number of constraints imposed prior to their estimation. Those prior constraints can be orthogonality to previous shocks, or can be zero restrictions. Note that in this case, the revenue and spending shocks are done in parallel—both are orthgonal to the business cycle and monetary policy shocks (hence the nvar-3, as they are orthogonal to the two prior shocks), but not to each other.
compute [vect] g1 =%fill(nvar-1,1,1.0) ;* Parameters for the first identified shock
compute [vect] g2 =%fill(nvar-2,1,1.0) ;* Parameters for the second identified shock
compute [vect] g3r=%fill(nvar-3,1,1.0) ;* Parameters for the third identified shock (revenue)
compute [vect] g3e=%fill(nvar-3,1,1.0) ;* Parameters for the third identified shock (spending)
The following computes the penalty function minimizer over a stereographic parameterization of the unit circle. The final parameter on the UhligPenalty function call describes the shape of the shock: +1 means positive (actually non-negative) on the first variable in the VAR (RGDP), +3 means positive on the third (revenue), etc.
nonlin g1
find(noprint,pmethod=genetic,piters=50,method=simplex) min func
compute v1=%stereo(g1)
compute func=UhligPenalty(v1,KMIN,KMAX,||+1,+3,+8,+9||)
end find
compute i1=sigmap*v1
The V1 is computed in "factor" space, while the I1 transforms back to the natural response in the actual variables.
To move onto the next orthogonal shock, we need to isolate the subspace of the factor space that's orthogonal to the first chosen impulse vector. That's done by using @FORCEDFACTOR with I1 as the forced column. Because UhligPenalty works off shocks orthogonalized using the Cholesky factor of the current sigma draw, the final columns of FFACTOR are transformed by pre-multiplying by the inverse of that factor. (FFACTOR is itself a factor, but a different one).
@forcedfactor(force=column) sigmad i1 ffactor
compute r2=inv(sigmap)*%xsubmat(ffactor,1,nvar,2,nvar)
A similar optimization is now done over the smaller parameter space, with a different set of shape constraints.
nonlin g2
find(noprint,pmethod=genetic,piters=50,method=simplex) min func
compute v2=r2*%stereo(g2)
compute func=UhligPenalty(v2,KMIN,KMAX,||+4,-5,-6,-7||)
end find
compute i2=sigmap*v2
To move on to the third shock, the factor space orthogonal to the first two impulse vectors needs to be computed, so this forces the first two columns of the factor to be spanned by i1~i2 (column i1 next to column i2):
@forcedfactor(force=column) sigmad i1~i2 ffactor
compute r3=inv(sigmap)*%xsubmat(ffactor,1,nvar,3,nvar)
A similar optimization is done on the (now) 7 parameter space.
In this example, the final (spending) shock is done using the same space as the revenue shock. If you needed a fourth shock to be orthogonal to the first three, you would do a new @FORCEDFACTOR with a three column input.
The following collects the desired sets of linear combinations of the Cholesky responses which is why it uses the "V"'s rather than the "I"'s.
dim %%responses(draw)(nshocks*nvar,nstep)
*
* Save the desired sets of linear combinations of the Cholesky
* responses
*
compute vweights=v1~v2~v3r~v3e
ewise %%responses(draw)(i,j)=(ik=%vec(%xt(impulses,j)*vweights)),ik(i)
Outside the loop, the following does a standard set of impulse response graphs with @MCGRAPHIRF, using the labels created earlier for the shocks and variables, with some rearrangement of the position by using the INCLUDE option.
@MCGraphIRF(model=varmodel,varlabels=vl,shocklabels=sl,$
page=byshock,center=median,columns=2,include=||1,2,10,4,6,8,3,9,5,7||)
The remainder of the program does calculations with linear transformations on the impulse responses.
The MU2009B2.RPF does zero ("delay") constraints for the first four periods for the revenue and spending shocks. It still generates shocks which are orthogonal to the business cycle and monetary policy shocks, but doesn't bother saving those, concentrating only of the fiscal policy shocks.
The following sets up the ranges of constrained shocks. KZERO is the range of the delay, while KMIN to KMAX is the range that is sign-constrained. Note that the KMIN=5 is actually due to an error in the authors' program (the business cycle and money shocks weren't sign-constrained for periods 1 to 4). In practice, you would want KMIN to be 1.
compute KZERO =4
compute KMIN =5 ;* For replication of paper. Should be 1 in practice.
compute KMAX =8
As in the earlier program, the following sets up the parameter vectors for the optimization. Note that the G3R and G3E vectors are much smaller since they have the extra 4 constraints for the delay.
compute [vect] g1x=%fill(nvar-1,1,1.0) ;* Parameters for the first identified shock (business cycle, extended)
compute [vect] g2x=%fill(nvar-2,1,1.0) ;* Parameters for the second identified shock (monetary policy, extended)
compute [vect] g3r=%fill(nvar-7,1,1.0) ;* Parameters for the third identified shock (revenue, delayed)
compute [vect] g3e=%fill(nvar-7,1,1.0) ;* Parameters for the third identified shock (spending, delayed)
The first two shocks are computed as before. The set up for the revenue shock, however, requires the addition of extra columns to the @FORCEDFACTOR to enforce the 4-period delay (in the response of revenue, which is variable 3 in the VAR, hence the 3 subscript in the EWISE):
dec rect rirf(KZERO,nvar)
ewise rirf(i,j)=ix=%xt(impulses,i),ix(3,j)
*
compute forcedcols=i1x~i2x~sigmap*tr(rirf)
@forcedfactor(force=column) sigmad forcedcols ffactor
The mapping back is a bit fancier here so it can adapt automatically to changes in KZERO.
compute r3r=inv(sigmap)*%xsubmat(ffactor,1,nvar,%cols(forcedcols)+1,nvar)
The spending shock is done similarly. The factor has to be recomputed as it has different zero constraints (here on variable 2 in the VAR):
dec rect rirf(KZERO,nvar)
ewise rirf(i,j)=ix=%xt(impulses,i),ix(2,j)
*
compute forcedcols=i1x~i2x~sigmap*tr(rirf)
@forcedfactor(force=column) sigmad forcedcols ffactor
MU2009X1.RPF and MU2009X2.RPF are similar to their counterparts, but use the "rejection" method. The penalty function method picks the impulse vector which comes "closest" to satisfying all the constraints, but doesn't require that the constraints be met. The rejection method only accepts impulse vectors which do satisfy all the constraints. The difficulty is that none may exist—though in this case, the constraints are reasonable enough that this is doable. The generation of shocks is inside a "subdraw" loop which takes the following "pseudo-code" form:
do subdraw=1,n2
try to draw shocks. If fail, goto reject
:reject
end do subdraw
The draws for the shocks is fairly similar but uses %RANSPHERE to generate random points on the unit sphere (in whatever is the required dimension) rather than optimizing over the unit sphere using the %STEREO mapping, and rather than UhligPenalty to compute the penalty function it uses UhligAccept to check whether the constraints are met. If they aren't (UhligAccept returns 0), the subdraw is rejected.
compute [vector] v1=%ransphere(nvar)
if UhligAccept(v1,KMIN,KMAX,||+1,+3,+8,+9||)==0
goto reject
compute i1=sigmap*v1
Assuming an acceptable first shock was found, you move on to the second shock in exactly the same way as in the penalty function and then again sample from the (lower dimensional) unit sphere.
compute forcedcols=i1
@forcedfactor(force=column) sigmad forcedcols ffactor
compute r2=inv(sigmap)*%xsubmat(ffactor,1,nvar,%cols(forcedcols)+1,nvar)
compute [vector] v2=r2*%ransphere(%cols(r2))
The following are the control parameters for the draw process (These are at the top of each of the programs). NKEEP is the number of good draws that you want, N1 is the number of outer draws (for the VAR as a whole) and N2 is the number of subdraws (for shocks). With these parameters, it will do up to 50000 sets of draws to try to get 250 valid ones.
compute nkeep=250
compute n1 =500
compute n2 =1000
Common Errors
The single most common error in attempting to apply these method is overdoing the "zero" restrictions. In a M variable VAR, there are only M-1 "degrees of freedom" for selecting an "impulse vector". Each prior shock which is considered to be orthogonal takes away one of those, as does each specific zero restriction. In this paper, M is 10, the revenue and spending shocks are each assumed to be orthogonal to the business cycle and monetary policy shocks, so there can be at most seven other restrictions. Even just a four period delay as is done in MU2009B2.RPF and MU2009X2.RPF leaves only three remaining degrees of freedom. Each variable and each step that is constrained to zero counts as one against the limit, so (for instance) constraining two variables for four steps each is 8 restrictions.
Another common error is trying to generate too many shocks relative to the size of the model. The paper identifies three shocks (since the revenue and spending are done separately) from a ten variable VAR. For a four variable VAR, you really can't sign-restrict four shocks, because the last one is determined (other than sign) by orthogonality to the first three. Even three is difficult for a model that size. Another error is making shocks whose specifications are too similar (or similar except with opposite signs). If the first shock is (for instance) +4,-3 and the second is -4,+3,-2, most of the space which satisfies the first two of the criteria on shock two will be the same space (except for sign) as the first shock. Since the second shock needs to be orthogonal to the first, the probability of finding a shock which satisfies that will be rather small. And a draw is rejected unless a sequence of all shocks can be found.
Copyright © 2025 Thomas A. Doan