Residual Adjustments

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.

Model and Data

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))
)
set.seed(1)
estimates <- estimate(sys_eq, ts_data = ts_data, dates = dates)

Residuals

Before adjusting, look at the recent residuals of the equations. They show where the model was off. Like the data, they are in rates.

res <- residuals(estimates)
utils::tail(res$imports, 4)
#>            Qtr1       Qtr2       Qtr3       Qtr4
#> 2023  2.1089655 -2.7666108  0.8997722  1.7545845

Adjusting an Equation

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.4510171

The applied adjustments are stored by variable and forecast quarter:

adjusted$adjustments
#> $exports
#>      Qtr1 Qtr2 Qtr3 Qtr4
#> 2024  0.5  0.3  0.0  0.0

Decaying Adjustments

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.

adjustments <- list(
  investment = list(value = 0.8, decay = 0.5, date = c(2024, 2))
)
adjusted <- forecast(estimates, dates = dates, adjustments = adjustments)
adjusted$adjustments$investment
#>      Qtr1 Qtr2 Qtr3 Qtr4
#> 2024  0.0  0.8  0.4  0.2

Starting at the Last Residual

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.321075

The 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().

Notes

  • Adjustments are in rates, like the data the model is estimated on.
  • Only stochastic equations can be adjusted, identities cannot.
  • Adjustments cannot be combined with restrictions for conditional forecasts.
  • adjusted$adjustments_spec keeps the adjustments as given to forecast().