I reorganized this to use a function to calculate the penalty function, which shortens the program considerably. (Also makes it much easier to read). This does everything in the paper that uses only the impact shocks. You need the MCGraphIRF procedure from the Procedures forum as well.
The "R" matrix is the same as the one in the paper. The p*tr(r) input in the forcedfactor is to get it in the same form as the orthogonality conditions on the new shocks that forcedfactor is imposing. (forcedfactor is doing basically a "Gram-Schmidt" orthogonalization on a rotated basis).
Code: Select all
*
* Replication file for Mountford and Uhlig (2009), "What are the Effects of Fiscal
* Policy Shocks?", Journal of Applied Econometrics.
*
open data mudata.xls
calendar(q) 1955:1
data(format=xls,org=columns) 1955:1 2000:4 rgdp rbpexp rbprev ffrt ares ppic gdpdef rcon rnresinv wage
*
set rgdp = rgdp*100
set rbpexp = rbpexp*100
set rbprev = rbprev*100
set ffrt = ffrt
set ares = ares*100
set ppic = ppic*100
set gdpdef = gdpdef*100
set rcon = rcon*100
set rnresinv = rnresinv*100
set wage = wage*100
*
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"||
*
* Compute scale factors (standard deviations of first differences) for weighting
* the penalty function
*
dec vect scales(10)
dec real func
compute fill=0
dofor i = rgdp rbpexp rbprev ffrt ares ppic gdpdef rcon rnresinv wage
diff i / diff1
stats(noprint) diff1
compute fill=fill+1,scales(fill)=sqrt(%variance)
end dofor i
*
* ndraws is the desired number of draws from the posterior of the VAR
* nvar is the number of variables
* nstep is the number of IRF steps to compute
* KMAX is the "K" value for the number of steps constrained
*
compute ndraws=250
compute nvar =10
compute nstep =25
compute KMAX =3
dec rect[series] impulses
*
* Parameter vectors for the nested optimization problems. They should have a size
* equal to nvar 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.
*
compute nshocks=6
dec vect[strings] sl(nshocks)
compute sl=||"Business Cycle","Monetary Policy","Revenue","Revenue (delayed)","Spending","Spending (delayed)"||
*
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] g3c=%fill(nvar-3,1,1.0) ;* Parameters for the third identified shock (revenue)
compute [vect] g3d=%fill(nvar-7,1,1.0) ;* Parameters for the third identified shock (revenue, delayed)
compute [vect] g3e=%fill(nvar-3,1,1.0) ;* Parameters for the third identified shock (spending)
compute [vect] g3f=%fill(nvar-7,1,1.0) ;* Parameters for the third identified shock (spending, delayed)
*******************************************************************************
*
* UhligPenalty(q,first,last,constrained) returns the penalty function for the
* weight vector <<q>> (applied to the impulse responses in the global VECT[SERIES]
* impulses). <<first>> and <<last>> are the range of responses constrained (1 =
* impact response). <<constrained>> is a VECT[INTEGER] with the variable positions
* being constrained. Use +slot for a positivity constraint and -slot for a
* negativity constraint. That is, if you want the first 4 responses to be positive
* on the 2nd variable and negative on the third, you would use the function
*
* UhligPenalty(q,1,4,||2,-3||)
*
function UhligPenalty q first last constrained
type real UhligPenalty
type vector q
type integer first last
type vect[int] constrained
*
local integer i k
local real func
local vector ik
*
compute func=0.0
do k=first,last
compute ik=(%xt(impulses,k)*q)./scales
do i=1,%rows(constrained)
if constrained(i)<0
compute value= ik(-constrained(i))
else
compute value=-ik(constrained(i))
compute func=func+%if(value<0.0,value,100*value)
end do i
end do k
compute UhligPenalty=func
end
*******************************************************************************
*
* This is the standard setup for MC integration of an OLS VAR
*
compute sxx =%decomp(%xx)
compute svt =%decomp(inv(%nobs*%sigma))
compute betaols=%modelgetcoeffs(varmodel)
compute ncoef =%rows(sxx)
compute wishdof=%nobs-ncoef
*
dec vect[rect] %%responses
dim %%responses(ndraws)
*
declare vector ik a(nvar) ones(nvar)
declare series[rect] irfsquared
compute ones=%const(1.0)
source forcedfactor.src
*
infobox(action=define,progress,lower=1,upper=ndraws) 'Monte Carlo Integration'
compute accept=0
do draws=1,ndraws*2
*
* Make a draw from the posterior for the VAR and compute its impulse
* responses.
*
compute sigmad =%ranwisharti(svt,wishdof)
compute p =%decomp(sigmad)
compute betadraw=betaols+%ranmvkron(p,sxx)
compute %modelsetcoeffs(varmodel,betadraw)
*
impulse(noprint,model=varmodel,decomp=p,results=impulses,steps=nstep)
gset irfsquared 1 1 = %xt(impulses,t).^2
gset irfsquared 2 nstep = irfsquared{1}+%xt(impulses,t).^2
*
* Minimize the penalty function, starting from the last set of minimizers
*
************************************************
* First in Order - Business Cycle Vector
************************************************
nonlin g1
find(noprint) min func
compute v1=%stereo(g1)
compute func=UhligPenalty(v1,1,KMAX+1,||+1,+3,+8,+9||)
end find
compute testfunc=func,testbeta=%beta
*
* Try the minimization again, starting from a standard set of values
*
compute g=%fill(nvar-1,1,1.0)
find(noprint) min func
compute v1=%stereo(g1)
compute func=UhligPenalty(v1,1,KMAX+1,||+1,+3,+8,+9||)
end find
*
* If the two estimates don't match, reject the draw.
*
if abs(testfunc-func)>.01
branch newdraw
compute i1=p*v1
*
* Compute a factor with i1 forced as the first column.
* Transform the orthogonal complement (remaining columns) back into weights on
* the Choleski factor.
*
@forcedfactor(force=column) sigmad i1 f
compute r2=inv(p)*%xsubmat(f,1,nvar,2,nvar)
*****************************************************
* Second in Order - Monetary Shock
*****************************************************
*
nonlin g2
find(noprint) min func
compute v2=r2*%stereo(g2)
compute func=UhligPenalty(v2,1,KMAX+1,||+4,-5,-6,-7||)
end find
compute testfunc=func,testbeta=%beta
*
* Try the minimization again, starting from a standard set of values
*
compute g2=%fill(nvar-2,1,1.0)
find(noprint) min func
compute v2=r2*%stereo(g2)
compute func=UhligPenalty(v2,1,KMAX+1,||+4,-5,-6,-7||)
end find
*
* If the two estimates don't match, reject the draw.
*
if abs(testfunc-func)>.01
branch newdraw
compute i2=p*v2
*
* Compute a factor with i1~i2 forced as the first two columns.
* Transform the orthogonal complement (remaining columns) back into weights on
* the Choleski factor.
*
@forcedfactor(force=column) sigmad i1~i2 f
compute r3=inv(p)*%xsubmat(f,1,nvar,3,nvar)
*****************************************************
* Third in Order - Govt Revenue Shock (no delay)
*****************************************************
*
* Draw from the orthogonal complement of i1 and i2 (final nvar-2 columns
* in the factor).
*
nonlin g3c
find(noprint) min func
compute v3c=r3*%stereo(g3c)
compute func=UhligPenalty(v3c,1,KMAX+1,||+3||)
end find
compute testfunc=func,testbeta=%beta
*
* Try the minimization again, starting from a standard set of values
*
compute g3c=%fill(nvar-3,1,1.0)
find(noprint) min func
compute v3c=r3*%stereo(g3c)
compute func=UhligPenalty(v3c,1,KMAX+1,||+3||)
end find
*
* If the two estimates don't match, reject the draw.
*
if abs(testfunc-func)>.01
branch newdraw
compute i3c=p*v3c
*****************************************************
* Third in Order - Govt Revenue Shock (one year delay)
*****************************************************
dec rect r(KMAX+1,nvar)
ewise r(i,j)=ix=%xt(impulses,i),ix(3,j)
@forcedfactor(force=column) sigmad i1~i2~p*tr(r) f
compute r3x=inv(p)*%xsubmat(f,1,nvar,7,nvar)
nonlin g3d
find(noprint) min func
compute v3d=r3x*%stereo(g3d)
compute func=UhligPenalty(v3d,KMAX+2,KMAX+5,||+3||)
end find
compute testfunc=func,testbeta=%beta
*
* Try the minimization again, starting from a standard set of values
*
compute g3d=%fill(nvar-7,1,1.0)
find(noprint) min func
compute v3d=r3x*%stereo(g3d)
compute func=UhligPenalty(v3d,KMAX+2,KMAX+5,||+3||)
end find
*
* If the two estimates don't match, reject the draw.
*
if abs(testfunc-func)>.01
branch newdraw
compute i3d=p*v3d
*****************************************************
* Third in Order - Govt Spending Shock (no delay)
*****************************************************
nonlin g3e
find(noprint) min func
compute v3e=r3*%stereo(g3e)
compute func=UhligPenalty(v3e,1,KMAX+1,||+2||)
end find
compute testfunc=func,testbeta=%beta
*
* Try the minimization again, starting from a standard set of values
*
compute g3e=%fill(nvar-3,1,1.0)
find(noprint) min func
compute v3e=r3*%stereo(g3e)
compute func=UhligPenalty(v3e,1,KMAX+1,||+2||)
end find
*
* If the two estimates don't match, reject the draw.
*
if abs(testfunc-func)>.01
branch newdraw
compute i3e=p*v3e
*****************************************************
* Third in Order - Govt Revenue Shock (one year delay)
*****************************************************
dec rect r(KMAX+1,nvar)
ewise r(i,j)=ix=%xt(impulses,i),ix(2,j)
@forcedfactor(force=column) sigmad i1~i2~p*tr(r) f
compute r3x=inv(p)*%xsubmat(f,1,nvar,7,nvar)
nonlin g3f
find(noprint) min func
compute v3f=r3x*%stereo(g3f)
compute func=UhligPenalty(v3f,KMAX+2,KMAX+5,||+2||)
end find
compute testfunc=func,testbeta=%beta
*
* Try the minimization again, starting from a standard set of values
*
compute g3f=%fill(nvar-7,1,1.0)
find(noprint) min func
compute v3f=r3x*%stereo(g3f)
compute func=UhligPenalty(v3f,KMAX+2,KMAX+5,||+2||)
end find
*
* If the two estimates don't match, reject the draw.
*
if abs(testfunc-func)>.01
branch newdraw
compute i3f=p*v3f
*
* Meets all restrictions
*
compute accept=accept+1
*
dim %%responses(accept)(nshocks*nvar,nstep)
compute vweights=v1~v2~v3c~v3d~v3e~v3f
ewise %%responses(accept)(i,j)=(ik=%vec(%xt(impulses,j)*vweights)),ik(i)
* ewise goodfevd(accept)(i,j)=ik=(irfsquared(i)*(v1.^2))./(irfsquared(i)*ones),ik(j)
* ewise goodfevda(accept)(i,j)=ik=(irfsquared(i)*(v2.^2))./(irfsquared(i)*ones),ik(j)
* ewise goodfevdb(accept)(i,j)=ik=(irfsquared(i)*(v3.^2))./(irfsquared(i)*ones),ik(j)
* ewise goodfevdc(accept)(i,j)=ik=(irfsquared(i)*(v4.^2))./(irfsquared(i)*ones),ik(j)
if accept>=ndraws
break
infobox(current=accept)
:newdraw
end do draws
infobox(action=remove)
disp accept
*
@MCGraphIRF(model=varmodel,varlabels=vl,shocklabels=sl,$
page=byshock,columns=2,include=||1,2,10,4,6,8,3,9,5,7||)