|
6 | 6 |
|
7 | 7 | import BeforeIT as Bit
|
8 | 8 |
|
9 |
| -using Plots, StatsPlots |
| 9 | +using Plots, StatsBase |
10 | 10 |
|
11 | 11 | parameters = Bit.AUSTRIA2010Q1.parameters
|
12 | 12 | initial_conditions = Bit.AUSTRIA2010Q1.initial_conditions
|
13 | 13 |
|
14 | 14 | # Initialise the model and the data collector
|
15 |
| -T = 20 |
| 15 | +T = 16 |
16 | 16 | model = Bit.init_model(parameters, initial_conditions, T);
|
17 | 17 |
|
18 |
| -# Simulate the model for T quarters |
19 |
| -data_vec_baseline = Bit.ensemblerun(model, 4) |
| 18 | +# Simulate the baseline model for T quarters, N_reps times, and collect the data |
| 19 | +N_reps = 64 |
| 20 | +data_vec_baseline = Bit.ensemblerun(model, N_reps) |
20 | 21 |
|
21 | 22 | # Now, apply a shock to the model and simulate it again.
|
22 | 23 | # A shock is simply a function that takes the model and changes some of
|
23 | 24 | # its parameters for a specific time period.
|
24 | 25 |
|
25 |
| -# In this case, let's define an interest rate shock that sets the interest |
26 |
| -# rate for a number of epochs. |
| 26 | +# We do this by first defining a "struct" with useful attributes. |
| 27 | +# For example, we can define an productivity and a consumption shock with the following structs |
| 28 | +struct ProductivityShock |
| 29 | + productivity_multiplier::Float64 # productivity multiplier |
| 30 | +end |
| 31 | +struct ConsumptionShock |
| 32 | + consumption_multiplier::Float64 # productivity multiplier |
| 33 | + final_time::Int |
| 34 | +end |
27 | 35 |
|
28 |
| -# We do this by first defining a "struct" with some useful attributes |
29 |
| -struct CustomShock |
30 |
| - rate::Float64 # target rate for the first 10 epochs |
31 |
| - final_time::Int # number of epochs for the shock |
| 36 | +# and then by making the structs callable functions that change the parameters of the model, |
| 37 | +# this is done in Julia using the syntax below |
| 38 | + |
| 39 | +# A permanent change in the labour productivities by the factor s.productivity_multiplier |
| 40 | +function (s::ProductivityShock)(model::Bit.Model) |
| 41 | + model.firms.alpha_bar_i .= model.firms.alpha_bar_i .* s.productivity_multiplier |
32 | 42 | end
|
33 | 43 |
|
34 |
| -# and then by making the struct a callable function that changes the interest |
35 |
| -# rate in the model, this is done in Julia using the syntax below |
36 |
| -function (s::CustomShock)(model::Bit.Model) |
37 |
| - if model.agg.t <= s.final_time |
38 |
| - model.cb.r_bar = s.rate |
| 44 | +# A temporary change in the propensity to consume model.prop.psi by the factor s.consumption_multiplier |
| 45 | +function (s::ConsumptionShock)(model::Bit.Model) |
| 46 | + if model.agg.t == 1 |
| 47 | + model.prop.psi = model.prop.psi * s.consumption_multiplier |
| 48 | + elseif model.agg.t == s.final_time |
| 49 | + model.prop.psi = model.prop.psi / s.consumption_multiplier |
39 | 50 | end
|
40 | 51 | end
|
41 | 52 |
|
42 |
| -# Now we define a specific shock with a rate of 0.01 for the first 10 epochs, |
43 |
| -# and run a shocked simulation |
| 53 | +# Define specific shocks, for example a 2% increase in productivity |
| 54 | +productivity_shock = ProductivityShock(1.02) |
| 55 | +# or a 4 quarters long 2% increase in consumption |
| 56 | +consumption_shock = ConsumptionShock(1.02, 4) |
44 | 57 |
|
45 |
| -custom_shock = CustomShock(0.0, 10) |
46 |
| -data_vec_shocked = Bit.ensemblerun(model, 4; shock = custom_shock) |
| 58 | +# Simulate the model with the shock |
| 59 | +data_vec_shocked = Bit.ensemblerun(model, N_reps; shock = consumption_shock) |
47 | 60 |
|
48 |
| -# Finally, we can plot baseline and shocked simulations |
| 61 | +# Compute mean and standard error of GDP for the baseline and shocked simulations |
| 62 | +mean_gdp_baseline = mean(data_vec_baseline.real_gdp, dims = 2) |
| 63 | +mean_gdp_shocked = mean(data_vec_shocked.real_gdp, dims = 2) |
49 | 64 |
|
50 |
| -Te = T + 1 |
51 |
| -StatsPlots.errorline( |
52 |
| - 1:Te, |
53 |
| - data_vec_baseline.real_gdp, |
54 |
| - errortype = :sem, |
55 |
| - label = "baseline", |
56 |
| - titlefont = 10, |
57 |
| - xlabel = "quarters", |
58 |
| - ylabel = "GDP", |
59 |
| -) |
60 |
| -StatsPlots.errorline!( |
61 |
| - 1:Te, |
62 |
| - data_vec_shocked.real_gdp, |
63 |
| - errortype = :sem, |
64 |
| - label = "shock", |
65 |
| - titlefont = 10, |
| 65 | +sem_gdp_baseline = std(data_vec_baseline.real_gdp, dims = 2) / sqrt(N_reps) |
| 66 | +sem_gdp_shocked = std(data_vec_shocked.real_gdp, dims = 2) / sqrt(N_reps) |
| 67 | + |
| 68 | +# Compute the ratio of shocked to baseline GDP |
| 69 | +gdp_ratio = mean_gdp_shocked ./ mean_gdp_baseline |
| 70 | +# the standard error on a ratio of two variables is computed with the error propagation formula |
| 71 | +sem_gdp_ratio = gdp_ratio .* ((sem_gdp_baseline ./ mean_gdp_baseline).^2 .+ (sem_gdp_shocked ./ mean_gdp_shocked).^2).^0.5 |
| 72 | + |
| 73 | +# Finally, we can plot the impulse response curve |
| 74 | +plot( |
| 75 | + 1:T+1, |
| 76 | + gdp_ratio, |
| 77 | + ribbon = sem_gdp_ratio, |
| 78 | + fillalpha = 0.2, |
| 79 | + label = "", |
66 | 80 | xlabel = "quarters",
|
67 |
| - ylabel = "GDP", |
| 81 | + ylabel = "GDP change", |
| 82 | + size = (350, 220), |
| 83 | + dpi = 300, |
68 | 84 | )
|
69 | 85 |
|
70 |
| -# Note that, importantly, once the function `central_bank_rate` has been changed, |
71 |
| -# the model will use the new interest rate in all the simulations, unless the function |
72 |
| -# is changed again. To restore the original interest rate, we can simply re-import the |
73 |
| -# function `central_bank_rate`. |
| 86 | +# We can save the figure using: savefig("gdp_shock.png") |
0 commit comments