RATS 10.1
RATS 10.1

Kilian(2009) uses Vector Autoregressive techniques to analyze the effects of the (world) oil market on U.S. macro data.

 

The data file kilian2009.rat is constructed from the data provided by the author to the AER data repository. The raw data are unlabeled text files, with a mix of monthly and quarterly series. Since RATS format can handle the mix of frequencies, it's a more useful way to handle the data. The series for the oil market model are constructed by the author (and are described in detail in the paper) while the macro series are from public sources.

 

oilmodel.rpf

This is a relatively straightforward analysis of oil market data using standard VAR methods.

 

oilmacro.rpf

This is a less standard analysis. It takes the structural residuals from the oil model and runs distributed lag regressions of the two macroeconomic series (real GDP growth and CPI inflation) on those to get impulse response functions with respect to the shocks. Because GDP is only available quarterly, this analysis uses compacted data for the monthly series (CPI and the oil market shocks).

oilmodel.rpf

As described above, this is a relatively straightforward use of standard VAR methods. The only less-than-standard adaptation is that it uses a Cholesky factorization, but with the sign of the first shock (the oil supply shock) flipped to give a negative effect on oil production. This is done using the factor function

 

function SignedFactor sigma model

type rect SignedFactor

type symm sigma

type model model

*

compute SignedFactor=%dmult(%chol(sigma),||-1.0,1.0,1.0||)

end

 

Note that this is specific to this being a 3-variable model. If you want to apply something like this to a model with a different number of variables, you will have to adjust the multiplier matrix ||-1.0,1.0,1.0|| to give the size you need.

 

The error bands for the impulse response functions are generated with @MCVARDoDraws and graphed with @MCGraphIRF. The paper does the error bands using a (somewhat vaguely described) bootstrapping technique and shows 1 and 2 standard deviation error bands rather the the more commonly used percentile bands done here. The results, however, will be quite similar.

 

@MCVARDoDraws(model=varmodel,steps=nsteps,draws=ndraws,ffunction=SignedFactor,accum=||1||)

@MCGraphIRF(model=varmodel,varlabels=vl,shocklabels=sl,$

  page=all,percent=||.025,.16,.84,.975||)

 

The final calculation in the file is of the historical decomposition of the real price of oil (3rd variable in the model). This graphs only the cumulated effects of the shocks. It's important in a case like this to use a common scale for all the graphs so a small effect (in this case, the supply shock) will not be spread across the full vertical range and leave a misleading impression. That is done by using the TABLE instruction across the three series to be graphed and using the %MAXIMUM and %MINIMUM values from that for the MAX and MIN options on the graphs.

 

history(model=varmodel,base=base,effects=effects,factor=SignedFactor(%sigma,varmodel))

 

table / effects(3,1) effects(3,2) effects(3,3)

spgraph(vfields=3,header="Figure 6: Historical Decomposition of Real Price of Oil\\1975.2-2005.9")

 graph(header="Cumulative Effect of Oil Supply Shock on Real Price of Oil",max=%maximum,min=%minimum)

 # effects(3,1) * 2005:9

 graph(header="Cumulative Effect of Aggregate Demand Shock on Real Price of Oil",max=%maximum,min=%minimum)

 # effects(3,2) * 2005:9

 graph(header="Cumulative Effect of Oil-Specific Demand Shock on Real Price of Oil",max=%maximum,min=%minimum)

 # effects(3,3) * 2005:9

spgraph(done)

 

oilmacro.rpf

This looks at the effects of the computed shocks from the oil model on U.S. macro variables. This is done using a distributed lag of the growth rates of each macro variable (thus GDP growth and inflation) on each of the shocks. Because the shocks are (theoretically) serially uncorrelated and the growth rates at most only minimally serially correlated, the coefficients in that will be estimates of the impulse responses from the shocks to the macro variables. The accumulated coefficients will be the responses of GDP and the price index themselves.

 

Because GDP is available only at quarterly frequencies, the distributed lags (for both series) are done on quarterly data, with quarterly averages used to compact the monthly data to quarterly. The simplest way to do this is to copy the monthly data out to a file (in this case an Excel file), and then read it back in once the CALENDAR is switched to quarterly. The first part of the program is identical to oilmodel.rpf for specifying and estimating the oil market model. The first new code is to compute the structural residuals:

 

@StructResids(factor=SignedFactor(%sigma,varmodel)) u / structu

set oilsupply = structu(1)

set aggdemand = structu(2)

set oildemand = structu(3)

 

The CPI data are read in under the monthly CALENDAR since we need monthly level inflation data:

 

data(format=rats) 1974:12 2007:12 cpi

set inflation = 1200.0*log(cpi/cpi{1})

 

The structural shocks and inflation data are copied out to an Excel file so they can be read back with quarterly compaction. The CLOSE COPY is needed to make the file available for reading in the same program.

 

open copy monthlytemp.xls

copy(dates,org=columns,format=xls) / oilsupply aggdemand oildemand inflation

close copy

 

The remainder of the analysis is done using a quarterly CALENDAR:

 

cal(q) 1973:1

 

This reads the GDP data are creates annualized growth rates:

 

data(format=rats) 1974:04 2007:04 beagdp

set gdpgrowth = 400.0*log(beagdp/beagdp{1})

 

This reads monthly data back as quarterly averages:

 

open data monthlytemp.xls

data(format=xls,org=columns,compact=average) * 2007:4 oilsupply aggdemand oildemand inflation

 

The distributed lags themselves are fairly straightforward. However, the paper estimates the error bands on the coefficients (thus the impulse responses for shocks to the macro variables) using a block bootstrap to allow for the fact that the residuals in the regressions have modest levels of serial correlation. This uses bootstrap calculations filling in the standard %%RESPONSES array to allow use of the @MCGraphIRF procedure to do the final graphs.

 

compute dllags=12

compute ndraws=20000

 

compute nshocks=3

compute ntargets=2

 

dec vect[rect] %%responses(ndraws)

ewise %%responses(i)=%zeros(nshocks*ntargets,dllags+1)

 

dofor depvar = gdpgrowth inflation

   compute itarget=%doforpass

   dofor shock = oilsupply aggdemand oildemand

      compute jshock=%doforpass

      linreg depvar

      # constant shock{0 to dllags}

      do draw=1,ndraws

         boot(block=4) shuffle %regstart() %regend()

         linreg(shuffle=shuffle,lastreg,noprint)

         set(first=%beta(2)) accirf 1 dllags+1 = accirf{1}+%beta(t+1)

         do k=1,dllags+1

            compute %%responses(draw)(ntargets*(jshock-1)+itarget,k)=accirf(k)

         end do k

      end do draw

   end dofor shock

end dofor depvar

 

The IRF's will be lags 0 to DLLAGS (in this case 12) which will be copied out of the coefficients of the regressions of the macro variables on the shocks. The IRF's for the integrated variables (GDP and CPI, both in log form) are computed from the %BETA vector by the instruction

 

set(first=%beta(2)) accirf 1 dllags+1 = accirf{1}+%beta(t+1)

 

which starts the ACCIRF series at %BETA(2) (second coefficient, that is, 0 lag of the shock series), then adds the next coefficient to the last value.

 

This does the graph. Note that this does percentiles rather than 1 and 2 s.d. bands:

 

@mcgraphirf(header="Figure 5. Responses of U.S. Real GDP and CPI to Structural Shocks",$

   varlabels=||"log GDP","log CPI"||,$

   shocklabels=||"Oil Supply Shock","Aggregate Demand Shock","Oil-Specific Demand"||,$

   percentiles=||.025,.16,.84,.975||)

 


Copyright © 2025 Thomas A. Doan