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