├── Slides.pdf ├── Codes ├── raw_data.mat ├── SVAR_demo.mlx ├── SVAR_demo.pdf └── SVAR_demo.m ├── .gitmodules └── README.md /Slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LRondina/SVARs-Intro/HEAD/Slides.pdf -------------------------------------------------------------------------------- /Codes/raw_data.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LRondina/SVARs-Intro/HEAD/Codes/raw_data.mat -------------------------------------------------------------------------------- /Codes/SVAR_demo.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LRondina/SVARs-Intro/HEAD/Codes/SVAR_demo.mlx -------------------------------------------------------------------------------- /Codes/SVAR_demo.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LRondina/SVARs-Intro/HEAD/Codes/SVAR_demo.pdf -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Codes/VAR_toolbox"] 2 | path = Codes/VAR_toolbox 3 | url = https://github.com/LRondina/VAR_toolbox 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction to Structural VAR models 2 | 3 | This short class is designed for M.Sc. Economics students as a part of the Research Methods module. 4 | 5 | The aim of the class is to introduce the students to Vector Autoregression (VAR) and Structural Vector Autoregression (SVAR) models. 6 | 7 | The focus is on the basic concepts and practical implementation of SVARs. As such, important aspects like the estimation of these models or more advanced identification techniques are not covered. 8 | 9 | ### Contents 10 | 11 | `Slides.pdf`: Trends and cycles, Introduction to VAR and SVAR models, Recursive (short-run) restriction, Example. 12 | 13 | `SVAR_demo.mlx`: MATLAB implementation of the example in the slides. This is an interactive Live Script with extensive comments and explanations. Open this file inside MATLAB or see the HTML or PDF version for a quick preview. 14 | 15 | `SVAR_demo.html`: HTML version of `SVAR_demo.mlx`. For a rendered version see [here](https://lrondina.github.io/matlab_html_scripts/SVAR_demo.html) or [here](http://htmlpreview.github.io/?https://github.com/LRondina/SVARs-Intro/blob/master/Codes/SVAR_demo.html). 16 | 17 | `SVAR_demo.pdf`: PDF version of `SVAR_demo.mlx`. 18 | 19 | `SVAR_demo.m`: Less exciting version of `SVAR_demo.mlx`. 20 | 21 | ### Download 22 | 23 | This repository contains a **git submodule** with the VAR toolbox. If you try to simply clone the repository or download it as a zip file, GitHub will download the files of this repository **without** the files in `Codes/VAR_toolbox`. 24 | 25 | To obtain this repository with the toolbox included, you have two options: 26 | 27 | 1. Direct download ([zip version](https://lrondina.github.io/downloads/SVARs-Intro.zip)) 28 | 29 | 2. Clone with submodule: `git clone --recurse-submodules https://github.com/LRondina/SVARs-Intro` 30 | 31 | ### Software and dependencies 32 | 33 | - A recent version of MATLAB (R2018b or never) is required for the Live Script `SVAR_demo.mlx`. 34 | 35 | - [VAR Toolbox 2.0](https://sites.google.com/site/ambropo/MatlabCodes) (a version of this toolbox is provided with this repository with minor modifications to handle plots and figures) 36 | 37 | - [Datafeed toolbox](https://uk.mathworks.com/products/datafeed.html) 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Codes/SVAR_demo.m: -------------------------------------------------------------------------------- 1 | %% Structural Vector Autoregression demo 2 | % This script illustrates how to work with Structural Vector Autoregression 3 | % (SVAR) models with a simple example. 4 | % 5 | % Results are produced using the VAR toolbox designed by Ambrogio Cesa-Bianchi, 6 | % available at https://sites.google.com/site/ambropo/MatlabCodes. 7 | 8 | %% Contents 9 | % 1. Model 10 | % 2. Data 11 | % 3. Estimation 12 | % 4. Impulse Responses 13 | % 5. Historical decomposition 14 | % 6. Forecast Error Variance decomposition 15 | 16 | %% --------- 1. Model 17 | % The model is a structural VAR with three variables (Inflation, Output and 18 | % Federal Funds Rate) and four lags. 19 | % 20 | % A*Y_t = B_1*Y_t-1 + B_2*Y_t-2 + B_3*Y_t-3 + B_4*Y_t-4 + C*e_t 21 | % 22 | % where variables are ranked in the following order 23 | % 24 | % | Pi_t | 25 | % Y_t = | GDP_t | 26 | % | FFR_t | 27 | % 28 | % and with the following imposed restriction on the structural matrix $A$ 29 | % 30 | % | a_11 0 0 | 31 | % A_t = | a_21 a_22 0 | 32 | % | a_31 a_32 a_33 | 33 | 34 | %% --------- 2. Data 35 | % In this example, we estimate the model parameters on US data. 36 | % 37 | % To construct the relevant variables, we use the following series from 38 | % FRED (https://research.stlouisfed.org/fred2): 39 | % 40 | % - Consumer Price Index for All Urban Consumers: All Items (CPIAUCSL) 41 | % - Federal Funds Rate (FEDFUNDS) 42 | % - Civilian Noninstitutional Population (CNP16OV) 43 | % - Gross Domestic Product (GDP) 44 | % - Gross Domestic Product: Implicit Price Deflator (GDPDEF) 45 | % 46 | % Here we use the Datafeed toolbox to fetch data from the FRED data server. 47 | 48 | if contains(matlabpath,['toolbox' filesep 'datafeed']) 49 | % Fetches data from FRED and saves it in raw_data.mat 50 | try 51 | % Create connection with FRED server 52 | c = fred('https://research.stlouisfed.org/fred2/'); 53 | 54 | % Sample period 55 | start_date = '01/01/1960'; 56 | end_date = '01/01/2019'; 57 | 58 | % Fetch data 59 | rawdata.cpi = fetch(c, 'CPIAUCSL' ,start_date,end_date); 60 | rawdata.ffr = fetch(c, 'FEDFUNDS' ,start_date,end_date); 61 | rawdata.pop = fetch(c, 'CNP16OV' ,start_date,end_date); 62 | rawdata.gdp = fetch(c, 'GDP' ,start_date,end_date); 63 | rawdata.gdp_defl = fetch(c, 'GDPDEF' ,start_date,end_date); 64 | 65 | % Save data 66 | save raw_data rawdata start_date end_date 67 | 68 | % Close connection with server 69 | close(c); clearvars c 70 | 71 | disp('Successfully fetched data!') 72 | fetched = true; 73 | catch 74 | disp('Unable to download data from FRED!') 75 | fetched = false; 76 | end 77 | else 78 | disp('Could not find the datafeed toolbox.') 79 | fetched = false; 80 | end 81 | 82 | % If the toolbox is not available in your MATLAB license or fetching data 83 | % fails, it loads previously dowloaded data (raw_data.mat) 84 | 85 | if ~fetched 86 | % Load raw data from .mat file 87 | load raw_data.mat 88 | disp('Loading previously downloaded data ...') 89 | end 90 | 91 | %% Data preparation 92 | % Downloaded data has to be further manipulated before it can be used in our 93 | % model. 94 | % 95 | % In particular, we have to: 96 | % 97 | % - Convert monthly data (CPI, FEDFUNDS and CNP16OV) into quarterly data 98 | % - Create a series for Inflation from the CPI index 99 | % - Construct Real GDP per capita 100 | % - Remove the trend component to get cyclical fluctuations of GDP 101 | 102 | %% Monthly data to quarterly data 103 | % 104 | % Sample period 105 | quarters = rawdata.gdp.Data(:,1); 106 | 107 | % Quarters to months legend: 108 | % Q1 --> 01-Jan 109 | % Q2 --> 01-Apr 110 | % Q3 --> 01-Jul 111 | % Q4 --> 01-Oct 112 | % To see dates, datestr(quarters) 113 | 114 | % Monthly to quarterly data 115 | rawdata.cpi.Data = rawdata.cpi.Data(ismember(rawdata.cpi.Data(:,1),quarters),:); 116 | rawdata.ffr.Data = rawdata.ffr.Data(ismember(rawdata.ffr.Data(:,1),quarters),:); 117 | rawdata.pop.Data = rawdata.pop.Data(ismember(rawdata.pop.Data(:,1),quarters),:); 118 | 119 | %% Year-on-year inflation rate 120 | 121 | T = length(quarters); 122 | Pi = zeros(T-4,1); 123 | for t = 5:T 124 | Pi(t-4) = 100*(rawdata.cpi.Data(t,2) - rawdata.cpi.Data(t-4,2))/rawdata.cpi.Data(t-4,2); 125 | end 126 | 127 | % NOTE: The first four observations are lost when constructing Pi. 128 | % Update sample period and data 129 | quarters = quarters(5:end); 130 | rawdata.gdp.Data = rawdata.gdp.Data(ismember(rawdata.gdp.Data(:,1),quarters),:); 131 | rawdata.gdp_defl.Data = rawdata.gdp_defl.Data(ismember(rawdata.gdp_defl.Data(:,1),quarters),:); 132 | rawdata.ffr.Data = rawdata.ffr.Data(ismember(rawdata.ffr.Data(:,1),quarters),:); 133 | rawdata.pop.Data = rawdata.pop.Data(ismember(rawdata.pop.Data(:,1),quarters),:); 134 | 135 | %% Real GDP per capita 136 | 137 | % Create population index 138 | index_date = '01-Jan-1990'; 139 | pop_index = rawdata.pop.Data(:,2) ./ rawdata.pop.Data(rawdata.pop.Data(:,1)==datenum(index_date),2); 140 | 141 | % Deflate nominal GDP 142 | gdp_real = rawdata.gdp.Data(:,2) ./ rawdata.gdp_defl.Data(:,2); 143 | 144 | % Divide by population index 145 | gdp_real_cap = gdp_real ./ pop_index; 146 | 147 | %% Remove trend in output 148 | 149 | % Choose detrending option: 'log-linear' or 'HP filtering' 150 | detrend_opt = 'HP filtering'; 151 | 152 | switch detrend_opt 153 | case 'log-linear' 154 | Y = detrend(100.*log(gdp_real_cap)); 155 | case 'HP filtering' 156 | [~,Y] = hpfilter(100.*log(gdp_real_cap),1600); 157 | end 158 | 159 | %% Cleaned data 160 | 161 | dates = datetime(datestr(rawdata.ffr.Data(:,1))); 162 | R = rawdata.ffr.Data(:,2); 163 | 164 | % Final data ready to be used in estimation 165 | data = timetable(dates,Pi,Y,R,'VariableNames',{'Inflation','Output','FedFunds'}); 166 | X = [Pi Y R]; 167 | 168 | %% Plot data (optional) 169 | 170 | % Select 'true' or 'false' if you want to plot data 171 | plot_data = true; 172 | if plot_data 173 | plot(dates,data.Variables) 174 | legend(data.Properties.VariableNames) 175 | end 176 | 177 | %% --------- 3. Estimation 178 | % Now that data is ready, we can estimate the VAR using the VAR Toolbox. 179 | % First, we need to tell MATLAB where the toolbox is located: 180 | 181 | % Add VAR toolbox to the MATLAB path (including all subfolders) 182 | addpath(genpath('VAR_toolbox')) 183 | 184 | 185 | % Next, we need to specify some variables that determine the shape of our 186 | % VAR, that is the number of lags and whether the VAR should have a constant, 187 | % a trend or both. 188 | 189 | %% Mean and trends 190 | % Before estimating the VAR, you need to choose between the following options: 191 | % 192 | % - const_trend = 0 --> No constant and no trend 193 | % - const_trend = 1 --> Only constant and no trend 194 | % - const_trend = 2 --> Constant and trend 195 | % 196 | % This choice depends on whether your endogenous variables (Inflation, Output 197 | % and Interest rate) display a non-zero mean and a trend. Therefore, you should 198 | % inspect your variables and make a choice accordingly. 199 | % 200 | % In practice, it is recommended to include both constant and trend in 201 | % your estimation. If it turns out that your time series does not have a non-zero 202 | % mean nor a trend, the respective estimated parameters will be equal (or very 203 | % close) to zero. 204 | 205 | % Choose constant and trend 206 | const_trend = 2; 207 | 208 | % Choose number of lags 209 | nbr_lags = 4; 210 | 211 | % Finally, call the appropriate function to estimate the model and show 212 | % parameters estimates: 213 | 214 | % Estimate the VAR 215 | [VAR, VAR_options] = VARmodel(X,nbr_lags,const_trend); 216 | 217 | % Show estimated model parameters 218 | VAR_options.vnames = data.Properties.VariableNames; 219 | VARprint(VAR,VAR_options); 220 | 221 | %% --------- 4. Impulse responses 222 | % In this section, we compute and plot the dynamic responses of endogenous variables 223 | % to a structural shock. 224 | 225 | %% Identification 226 | % But wait, what is a structural shock!? Remember in the slides we made an 227 | % important distinction between innovations and structural shocks. Loosely 228 | % speaking, a structural shock is a sudden movement in the error terms that we 229 | % can clearly identify coming from a specific source. Conversely, innovations 230 | % are sudden movements in the error terms which might be caused by several factors. 231 | % 232 | % How do we tell a structural shock from an innovation? One way is to use 233 | % economic theory to impose some restrictions on the parameters of the model. 234 | % Given the restriction, we can now say that a sudden movement in the error term 235 | % is due to a movement in a particular variable. 236 | % 237 | % Remember when we introduced the model, we said that the structural matrix 238 | % A was lower triangular. This is an example of one of such restrictions. This 239 | % restriction implies that only some variables are able to contemporaneously 240 | % influence the other variables. This identification scheme is called recursive 241 | % or short-run restriction. 242 | % 243 | % In particular, given the ordering of the variables and the restriction 244 | % on A, 245 | % 246 | % | Pi_t | | a_11 0 0 | 247 | % Y_t = | GDP_t | A_t = | a_21 a_22 0 | 248 | % | FFR_t | | a_31 a_32 a_33 | 249 | % 250 | % we deduce that: 251 | % 252 | % - The policy rate FFR_t responds to contemporaneous changes to other variables 253 | % - Output GDP_t responds current inflation but not interest rate 254 | % - Inflation Pi_t is not contemporaneously affected by GDP_t or FFR_t 255 | % and only responds to these variables with a lag 256 | % 257 | % This ordering of the variables is reasonable since we expect the central 258 | % bank to immediately respond to movements in inflation and output with changes 259 | % in the policy rate. 260 | % 261 | % On the other hand, since both inflation and output are assumed to not contemporaneously 262 | % react to movements in the policy rate, we can say that any sudden change in 263 | % the error term of FFR_t is due to movements in FFR_t only. That is, it is 264 | % a shock to the policy rate that does not come from a reaction to movements in 265 | % other variables. This is a monetary policy shock. 266 | 267 | %% Implementation 268 | % In practice, the restriction on the structural matrix A is imposed by doing 269 | % a Cholesky decomposition of the estimated variance-covariance matrix of 270 | % the residuals. 271 | 272 | % Choose the identification scheme 273 | VAR_options.ident = 'oir'; % 'oir' selects a recursive scheme 274 | 275 | % Choose the horizon for the impulse responses 276 | VAR_options.nsteps = 40; 277 | 278 | % Apply the identification scheme and compute impulse responses 279 | [IRF,VAR] = VARir(VAR,VAR_options); 280 | 281 | % It is usually good practice to report impulse responses along with confidence 282 | % intervals. 283 | % 284 | % The VAR toolbox computes a lower and an upper bound for the impulse responses 285 | % via bootstrap: 286 | % 287 | % - The residuals are resampled and the model parameters are re-estimated a 288 | % large number of times. 289 | % - For each new estimate, impulse responses are computed. 290 | % - All impulse responses are compared to identify the lower, upper and median 291 | % impulse response. 292 | 293 | %% Compute confidence intervals using bootstrap methods 294 | [IRF_lower,IRF_upper,IRF_median] = VARirband(VAR,VAR_options); 295 | 296 | % Finally, we can plot the impulse responses: 297 | 298 | % Figures related options 299 | VAR_options.savefigs = false; 300 | VAR_options.quality = 0; 301 | 302 | %% Plot impulse response functions 303 | VARirplot(IRF_median,VAR_options,IRF_lower,IRF_upper); 304 | 305 | %% --------- 5. Historical decomposition 306 | % The historical decomposition summarises the history of each endogenous variable 307 | % in the light of the VAR. 308 | % 309 | % It asks the following question: given the estimated model, what is the 310 | % sequence of shocks that is able to replicate the time series of Inflation, Output 311 | % and Federal Funds Rate? 312 | % 313 | % In other words, the historical decomposition tells us what portion of the 314 | % deviation of the endogenous variables from their unconditional mean is due to 315 | % the each shock. 316 | 317 | % Compute historical decomposition 318 | HistDecomp = VARhd(VAR); 319 | 320 | % Plot historical decomposition 321 | VARhdplot(HistDecomp,VAR_options); 322 | 323 | %% --------- 6. Forecast Error Variance decomposition 324 | % The variance decomposition of the forecast errors tells us the contribution 325 | % of each shock to the total variability of each endogenous variable. 326 | % 327 | % It is used to understand how much of the variability of each variable is 328 | % explained by a given shock. The dynamic nature of the VAR model also implies 329 | % that the contribution of each shock may change over time, for instance one shock 330 | % may be important in the first few periods but less important in the long-run. 331 | 332 | % Compute forecast error variance decomposition 333 | [FEVD,VAR] = VARfevd(VAR,VAR_options); 334 | 335 | % Compute confidence interval via bootstrap 336 | [FEVDINF,FEVDSUP,FEVDMED] = VARfevdband(VAR,VAR_options); 337 | 338 | % Plot 339 | VARfevdplot(FEVDMED,VAR_options,FEVDINF,FEVDSUP); 340 | --------------------------------------------------------------------------------