Nothing
#' @useDynLib TwoStepSDFM, .registration=TRUE
#' @importFrom Rcpp sourceCpp
#' @import zoo
#' @import xts
#' @import lubridate
#' @import ggplot2
#' @import stats
#' @import utils
NULL
# SPDX-License-Identifier: GPL-3.0-or-later
#
# Copyright (C) 2024-2026 Domenic Franjic
#
# This file is part of TwoStepSDFM.
#
# TwoStepSDFM is free software: you can redistribute
# it and/or modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 3 of the License,
# or (at your option) any later version.
#
# TwoStepSDFM is distributed in the hope that it
# will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with TwoStepSDFM. If not, see <https://www.gnu.org/licenses/>.
#' @name forecastWrapper
#' @title Internal forecasting wrapper function
#' @description
#' This function is for internal use only and may change in future releases
#' without notice. Users should use `nowcast()` instead for a stable and
#' supported interface.
#' Helper function to check parameter vectors for positive signed integer values
#' @keywords internal
forecastWrapper <- function(target_variables,
quarterly_predictors,
factors,
target_variable_delay,
quarterly_delay,
lag_estim_criterion,
max_fcast_horizon,
max_ar_lag_order,
max_predictor_lag_order,
jitter
)
{
no_of_factors <- dim(factors)[1]
no_of_target_vars <- dim(target_variables)[1]
qtrly_predictors_missing <- is.null(quarterly_predictors)
if(qtrly_predictors_missing){
no_of_qrtly_vars <- 0
}else{
no_of_qrtly_vars <- dim(quarterly_predictors)[1]
}
no_of_vars <- no_of_qrtly_vars + no_of_target_vars
no_of_qrtly_obs <- (dim(factors)[2] - 2) / 3
min_fcast_horizons <- ifelse(target_variable_delay == 0,
0,
-floor(target_variable_delay / 3) + 1)
return_object <- list()
# Store all monthly predictors and the monthly factors in a single matrix
all_qtrly_data_delay <- c(floor(c(target_variable_delay, quarterly_delay) / 3), rep(0, no_of_factors))
# Start quarterfication loop according to Mariano and Murasawa #
# Note: It is implicitly assumed that the stationary monthly data starts at the
# second month of the first quarter. Further, it is assumed that the data set
# ends with an observation in the last month of the quarter. This is handled
# by the higher level function calling this wrapper.
all_qrtly_data <- matrix(NaN, no_of_vars + no_of_factors, no_of_qrtly_obs)
for(t in seq(5, dim(factors)[2], 3)){
all_qrtly_data[1:no_of_target_vars, (t - 2)/3] <- target_variables[, t]
if(!qtrly_predictors_missing){
all_qrtly_data[(no_of_target_vars + 1):(no_of_target_vars + no_of_qrtly_vars),
(t - 2)/3] <- quarterly_predictors[, t]
}
all_qrtly_data[(no_of_target_vars + no_of_qrtly_vars + 1):(no_of_vars + no_of_factors),
(t - 2)/3] <- rowSums(cbind(1/3 * factors[, t, drop = FALSE],
2/3 * factors[, t - 1, drop = FALSE],
1 * factors[, t - 2, drop = FALSE],
2/3 * factors[, t - 3, drop = FALSE],
1/3 * factors[, t - 4, drop = FALSE]),
na.rm = TRUE)
}
# End quarterfication loop according to Mariano and Murasawa #
# Start ARDL estimation loop over the target variables #
fcasts <- matrix(NaN, no_of_target_vars, max_fcast_horizon - min(min_fcast_horizons) + 1)
for(current_target in 1:no_of_target_vars){
# Start ARDL estimation loop over the predictor #
current_fcasts <- matrix(NaN, no_of_vars + no_of_factors, max_fcast_horizon - min_fcast_horizons[current_target] + 1)
for(current_predictor in 1:(no_of_vars + no_of_factors)){
if(current_target == current_predictor){
next # Skip using the current target_variable as a single predictor as its always included as predictor
}
if(all_qtrly_data_delay[current_target] < all_qtrly_data_delay[current_predictor]){
next # Skip a predictor if it is dalyed further back compared to the target variable (we do not expect forecasting gains from using variables that are further behind then the target)
}
rel_fcast_horizons <- min_fcast_horizons[current_target]:max_fcast_horizon + all_qtrly_data_delay[current_predictor]
for(h in rel_fcast_horizons){
# Fit the model for the specific forecasting horizon
horizon_adjustment <- which(rel_fcast_horizons == h)
horizon_specific_target <- matrix(
all_qrtly_data[current_target,
(horizon_adjustment + 1):(no_of_qrtly_obs - all_qtrly_data_delay[current_target])],
ncol = 1)
horizon_specific_ar_lag <- matrix(
all_qrtly_data[current_target,
1:(no_of_qrtly_obs - all_qtrly_data_delay[current_target] - horizon_adjustment)],
ncol = 1)
horizon_specific_predictor <- matrix(
all_qrtly_data[current_predictor,
(horizon_adjustment + 1 - h):(no_of_qrtly_obs - all_qtrly_data_delay[current_target] - h)],
ncol = 1)
if(max_ar_lag_order != 0){
ardl_fit <- runARDL(horizon_specific_target,
horizon_specific_ar_lag,
horizon_specific_predictor,
max(max_ar_lag_order - max(h, 0), 1),
max(max_predictor_lag_order - max(h, 0), 1),
lag_estim_criterion,
jitter)
# Forecast
forecast_predictors <- matrix(1, sum(ardl_fit$optimL_lag_order) + 3, 1) # Add three for the intercept and the "contemporaenous" observations
forecast_predictors[2:(ardl_fit$optimL_lag_order[1] + 2), ] <-
head(all_qrtly_data[current_target,
(no_of_qrtly_obs - all_qtrly_data_delay[current_target]):1],
ardl_fit$optimL_lag_order[1] + 1)
forecast_predictors[(ardl_fit$optimL_lag_order[1] + 3):(ardl_fit$optimL_lag_order[1] + ardl_fit$optimL_lag_order[2] + 3), ] <-
head(all_qrtly_data[current_predictor,
(no_of_qrtly_obs - all_qtrly_data_delay[current_predictor]):1],
ardl_fit$optimL_lag_order[2] + 1)
current_fcasts[current_predictor, which(rel_fcast_horizons == h)] <-
matrix(ardl_fit$coefficients, nrow = 1) %*% forecast_predictors
}else{
ardl_fit <- runDL(horizon_specific_target,
horizon_specific_predictor,
max(max_predictor_lag_order - max(h, 0), 1),
lag_estim_criterion,
jitter = jitter)
# Forecast
forecast_predictors <- matrix(1, ardl_fit$optimL_lag_order + 2, 1) # Add two for the intercept and the "contemporaenous" observations
forecast_predictors[2:(ardl_fit$optimL_lag_order[1] + 2), ] <-
head(all_qrtly_data[current_predictor,
(no_of_qrtly_obs - all_qtrly_data_delay[current_predictor]):1],
ardl_fit$optimL_lag_order + 1)
current_fcasts[current_predictor, which(rel_fcast_horizons == h)] <-
matrix(ardl_fit$coefficients, nrow = 1) %*% forecast_predictors
}
}
# End loop over the forecasting horizons #
}
# Store the final point forecast using simple forecast averaging for each target
if(qtrly_predictors_missing){
rownames(current_fcasts) <- c(rownames(target_variables), rownames(factors))
}else{
rownames(current_fcasts) <- c(rownames(target_variables), rownames(quarterly_predictors), rownames(factors))
}
return_object[[current_target]] <- current_fcasts
names(return_object)[current_target] <- paste0("Single Predictor Forecasts ", rownames(target_variables)[current_target], collapse = "")
fcasts[current_target, (max_fcast_horizon - min(min_fcast_horizons) - length(rel_fcast_horizons) + 2):(max_fcast_horizon - min(min_fcast_horizons) + 1)] <-
colMeans(current_fcasts, na.rm = TRUE)
# Start ARDL estimation loop over the predictor #
}
# End ARDL estimation loop over the target variables #
rownames(fcasts) <- rownames(target_variables)
return_object[[no_of_target_vars + 1]] <- fcasts
names(return_object)[no_of_target_vars + 1] <- "Avg. Point Forecast"
return(return_object)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.