Residual adjustments (add-factors) add a value to the residual of selected stochastic equations in the forecast period, e.g. to include information the model does not capture. The model then computes the forecast of all variables with the adjusted equations.
We use the small macro model for Switzerland from the small macro model vignette, estimated up to 2023 Q4 and forecast for 2024.
library(koma)
equations <- "consumption ~ gdp + consumption.L(1),
investment ~ investment.L(1),
exports ~ world_gdp + exports.L(1),
imports ~ domestic_demand + imports.L(1),
prices ~ exchange_rate + oil_price + prices.L(1),
interest_rate ~ prices + interest_rate_germany + prices.L(1),
gdp == 0.9*domestic_demand + 0.5*exports - 0.4*imports,
domestic_demand == 0.6*consumption + 0.4*investment"
exogenous_variables <- c("world_gdp", "interest_rate_germany", "exchange_rate", "oil_price")
sys_eq <- system_of_equations(equations, exogenous_variables)
dates <- list(
estimation = list(start = c(1996, 1), end = c(2023, 4)),
forecast = list(start = c(2024, 1), end = c(2024, 4))
)
series <- names(small_open_economy)
series <- series[!series %in% c("interest_rate", "interest_rate_germany")]
ts_data <- lapply(series, function(x) {
as_ets(small_open_economy[[x]], series_type = "level", method = "diff_log")
})
names(ts_data) <- series
ts_data$interest_rate <- as_ets(small_open_economy$interest_rate,
series_type = "rate", method = "none"
)
ts_data$interest_rate_germany <- as_ets(small_open_economy$interest_rate_germany,
series_type = "rate", method = "none"
)
# endogenous data up to the quarter before the forecast
ts_data[sys_eq$endogenous_variables] <- lapply(
sys_eq$endogenous_variables,
function(x) stats::window(ts_data[[x]], end = c(2023, 4))
)Before adjusting, look at the recent residuals of the equations. They show where the model was off. Like the data, they are in rates.
Adjustments are given by equation, in the same forms as restrictions for conditional forecasts: by forecast horizon, by date or as a time series. Here exports are raised by 0.5 in the first quarter and 0.3 in the second.
adjustments <- list(
exports = ts(c(0.5, 0.3), start = c(2024, 1), frequency = 4)
)
adjusted <- forecast(estimates, dates = dates, adjustments = adjustments)The result keeps the forecast without adjustments in
unadjusted, computed with the same shocks. The difference
between the two is the effect of the adjustments.
compare <- function(forecasts, variable) {
stats::ts(
cbind(
unadjusted = as.numeric(forecasts$unadjusted$mean[[variable]]),
adjusted = as.numeric(forecasts$mean[[variable]])
),
start = c(2024, 1), frequency = 4
)
}
compare(adjusted, "exports")
#> unadjusted adjusted
#> 2024 Q1 0.9890750 1.4890750
#> 2024 Q2 0.9469996 1.2128093
#> 2024 Q3 1.2120213 1.1979068
#> 2024 Q4 0.9726232 0.9754732
compare(adjusted, "gdp")
#> unadjusted adjusted
#> 2024 Q1 0.3881933 0.6516926
#> 2024 Q2 0.4567337 0.5838692
#> 2024 Q3 0.6107484 0.5982094
#> 2024 Q4 0.4488500 0.4510171The applied adjustments are stored by variable and forecast quarter:
An adjustment can also start at a value and decay by a factor per
quarter until the end of the forecast. decay = 0 adjusts
one quarter only, decay = 1 all quarters by the same value.
The adjustment starts in the first forecast quarter, or at the quarter
given by horizon or date.
To carry the recent error of an equation into the forecast, start the
adjustment at its last residual with init = "last". It
takes the residual of the quarter before the forecast and lets it
decay.
adjustments <- list(imports = list(init = "last", decay = 0.6))
adjusted <- forecast(estimates, dates = dates, adjustments = adjustments)adjusted$adjustments$imports
#> Qtr1 Qtr2 Qtr3 Qtr4
#> 2024 1.7545845 1.0527507 0.6316504 0.3789902
compare(adjusted, "imports")
#> unadjusted adjusted
#> 2024 Q1 0.9815705 2.118459
#> 2024 Q2 1.0612965 1.947452
#> 2024 Q3 0.8784005 1.408013
#> 2024 Q4 0.9963298 1.321075The adjustment starts at the last residual of imports shown above.
All variables of the equation must be observed in the quarter before the
forecast. If one of them is filled because its series ends earlier,
forecast() fails; set the start value with
value instead, e.g. from residuals().
adjusted$adjustments_spec keeps the adjustments as
given to forecast().