## ----include = FALSE----------------------------------------------------------
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)

## ----setup, message=FALSE, warning=FALSE,include=FALSE------------------------
library(postshock)


## ----load-cop-data------------------------------------------------------------
data("cop_oil_postshock", package = "postshock")

names(cop_oil_postshock)

## ----inspect-cop-data---------------------------------------------------------
cop_structure <- data.frame(
  Position = seq_along(cop_oil_postshock$Y),
  Series = names(cop_oil_postshock$Y),
  Covariates = names(cop_oil_postshock$X),
  Shock_time = cop_oil_postshock$shock_time_vec,
  Shock_length = cop_oil_postshock$shock_length_vec
)

knitr::kable(
  cop_structure,
  caption = "Alignment of the target and donor inputs in `cop_oil_postshock`."
)

## ----fit-cop-dbw, results='hide', message=FALSE, warning=FALSE----------------
cop_dbw <- dbw(
  X = cop_oil_postshock$X,
  dbw_indices = seq_len(ncol(cop_oil_postshock$X[[1]])),
  shock_time_vec = cop_oil_postshock$shock_time_vec,
  center = TRUE,
  scale = TRUE,
  sum_to_1 = TRUE,
  bounded_below_by = 0,
  bounded_above_by = 1,
  normchoice = "l2",
  penalty_normchoice = "l2",
  penalty_lambda = 1e-2
)

## ----inspect-cop-dbw----------------------------------------------------------
names(cop_dbw)

cop_dbw$convergence
cop_dbw$loss
sum(cop_dbw$opt_params)

## ----display-cop-dbw----------------------------------------------------------
cop_weight_table <- data.frame(
  Donor = sub(
    "^Y_",
    "",
    names(cop_oil_postshock$Y)[-1]
  ),
  Weight = as.numeric(cop_dbw$opt_params)
)

knitr::kable(
  cop_weight_table,
  digits = 3,
  caption = "Donor balancing weights for the ConocoPhillips example."
)

## ----fit-cop-synthprediction, results='hide', message=FALSE, warning=FALSE----
cop_fit <- SynthPrediction(
  Y_series_list = cop_oil_postshock$Y,
  covariates_series_list = cop_oil_postshock$X,
  shock_time_vec = cop_oil_postshock$shock_time_vec,
  shock_length_vec = cop_oil_postshock$shock_length_vec,
  k = 1L,
  dbw_indices = seq_len(ncol(cop_oil_postshock$X[[1]])),
  dbw_center = TRUE,
  dbw_scale = TRUE,
  use_dbw = TRUE,
  covariate_indices = NULL,
  seasonal = TRUE,
  penalty_lambda = 1e-2,
  penalty_normchoice = "l2"
)

## ----inspect-cop-fit----------------------------------------------------------
names(cop_fit)
names(cop_fit$predictions)
names(cop_fit$meta)

## ----cop-forecast-comparison--------------------------------------------------
forecast_index <- cop_oil_postshock$shock_time_vec[1] + 1L

observed_value <- as.numeric(
  cop_oil_postshock$Y[[1]][forecast_index]
)

forecast_values <- c(
  as.numeric(cop_fit$predictions$unadjusted[1]),
  as.numeric(cop_fit$predictions$arithmetic_mean[1]),
  as.numeric(cop_fit$predictions$adjusted[1])
)

cop_forecast_table <- data.frame(
  Method = c(
    "Observed value",
    "Unadjusted",
    "Arithmetic mean",
    "DBW adjusted"
  ),
  Value = c(
    observed_value,
    forecast_values
  ),
  Absolute_error = c(
    NA_real_,
    abs(forecast_values - observed_value)
  )
)

knitr::kable(
  cop_forecast_table,
  digits = 3,
  col.names = c("Method", "Value", "Absolute error"),
  caption = paste(
    "One-step forecast comparison for the March 2020",
    "ConocoPhillips shock episode."
  )
)

## ----inspect-cop-donor-results------------------------------------------------
cop_donor_summary <- data.frame(
  Donor = sub(
    "^Y_",
    "",
    names(cop_oil_postshock$Y)[-1]
  ),
  Weight = as.numeric(cop_fit$linear_combinations),
  Estimated_effect = as.numeric(cop_fit$meta$omega_vec)
)

knitr::kable(
  cop_donor_summary,
  digits = 3,
  col.names = c(
    "Donor",
    "DBW weight",
    "Estimated post-shock effect"
  ),
  caption = "Donor weights and estimated effects for the COP example."
)

## ----inspect-cop-adjustment---------------------------------------------------
data.frame(
  Unadjusted_forecast =
    as.numeric(cop_fit$predictions$unadjusted[1]),
  Combined_donor_effect =
    as.numeric(cop_fit$meta$combined_omega),
  Adjusted_forecast =
    as.numeric(cop_fit$predictions$adjusted[1])
) |>
  knitr::kable(
    digits = 3,
    col.names = c(
      "Unadjusted forecast",
      "Combined donor effect",
      "DBW-adjusted forecast"
    ),
    caption = "Construction of the DBW-adjusted COP forecast."
  )

## ----define-cop-pools---------------------------------------------------------
cop_pools <- list(
  supply = "Y_2014_11_28",
  demand = c(
    "Y_2008_03_17",
    "Y_2008_09_09",
    "Y_2008_09_15",
    "Y_2008_09_29"
  )
)

cop_pool_table <- data.frame(
  Pool = names(cop_pools),
  Donors = unname(
    vapply(
      cop_pools,
      function(x) {
        paste(
          gsub("_", "-", sub("^Y_", "", x)),
          collapse = ", "
        )
      },
      character(1)
    )
  )
)

knitr::kable(
  cop_pool_table,
  row.names = FALSE,
  col.names = c("Pool", "Donor episodes"),
  caption = "Structured donor pools for the ConocoPhillips example."
)

## ----fit-cop-multipool, results='hide', message=FALSE, warning=FALSE----------
cop_multipool <- SynthPrediction(
  Y_series_list = cop_oil_postshock$Y,
  covariates_series_list = cop_oil_postshock$X,
  shock_time_vec = cop_oil_postshock$shock_time_vec,
  shock_length_vec = cop_oil_postshock$shock_length_vec,
  k = 1L,
  covariate_indices = NULL,
  seasonal = TRUE,
  dbw_indices = seq_len(
    ncol(cop_oil_postshock$X[[1]])
  ),
  dbw_center = TRUE,
  dbw_scale = TRUE,
  penalty_lambda = 1e-2,
  penalty_normchoice = "l2",
  pools = cop_pools,
  pool_agg = "sum",
  base_use_dbw = FALSE,
  pool_use_dbw = TRUE
)

## ----inspect-cop-pool-effects-------------------------------------------------
cop_pool_effects <- data.frame(
  Pool = names(
    cop_multipool$meta$multi_pool$pool_effects
  ),
  Estimated_adjustment = as.numeric(
    cop_multipool$meta$multi_pool$pool_effects
  )
)

knitr::kable(
  cop_pool_effects,
  row.names = FALSE,
  digits = 3,
  col.names = c(
    "Pool",
    "Estimated pool adjustment"
  ),
  caption = "Pool-specific adjustments for the ConocoPhillips example."
)

## ----compare-cop-multipool----------------------------------------------------
cop_multipool_values <- c(
  as.numeric(
    cop_multipool$predictions$unadjusted[1]
  ),
  as.numeric(
    cop_fit$predictions$adjusted[1]
  ),
  as.numeric(
    cop_multipool$predictions$adjusted_multipool[1]
  )
)

cop_multipool_table <- data.frame(
  Method = c(
    "Observed value",
    "Unadjusted",
    "Single-pool DBW",
    "MultiPool (sum)"
  ),
  Value = c(
    observed_value,
    cop_multipool_values
  ),
  Absolute_error = c(
    NA_real_,
    abs(cop_multipool_values - observed_value)
  )
)

knitr::kable(
  cop_multipool_table,
  digits = 3,
  col.names = c("Method", "Value", "Absolute error"),
  caption = paste(
    "Comparison of single-pool and MultiPool forecasts",
    "for the ConocoPhillips example."
  )
)

## ----load-iyg-data------------------------------------------------------------
data("iyg_onestep_input", package = "postshock")

names(iyg_onestep_input)
names(iyg_onestep_input$inputs)

## ----inspect-iyg-input--------------------------------------------------------
iyg_restricted <- iyg_onestep_input$inputs$restricted

names(iyg_restricted)

## ----summarize-iyg-input------------------------------------------------------
iyg_restricted$target_event
iyg_restricted$donor_events

c(
  number_of_series =
    length(iyg_restricted$Y_series_list),
  number_of_donors =
    length(iyg_restricted$donor_events),
  donor_covariate_sets =
    length(iyg_restricted$covariates_series_list),
  shock_time_entries =
    length(iyg_restricted$shock_time_vec),
  shock_length_entries =
    length(iyg_restricted$shock_length_vec)
)

## ----fit-iyg-volatility, results='hide', message=FALSE, warning=FALSE---------
iyg_fit <- SynthVolForecast(
  Y_series_list =
    iyg_restricted$Y_series_list,
  covariates_series_list =
    iyg_restricted$covariates_series_list,
  target_covariates =
    iyg_restricted$target_covariates,
  shock_time_vec =
    iyg_restricted$shock_time_vec,
  shock_length_vec =
    iyg_restricted$shock_length_vec,
  k = 1L,
  dbw_indices = seq_len(
    ncol(iyg_restricted$target_covariates)
  ),
  dbw_center = TRUE,
  dbw_scale = TRUE,
  penalty_lambda = 1e-2,
  penalty_normchoice = "l2",
  covariate_indices = NULL,
  garch_order = NULL,
  max.p = 3L,
  max.q = 3L,
  vcov.type = "robust",
  return_fits = FALSE
)

## ----inspect-iyg-orders-------------------------------------------------------
iyg_selected_orders <- do.call(
  rbind,
  c(
    iyg_fit$meta$donor_orders,
    list(iyg_fit$meta$target_order)
  )
)

iyg_order_table <- data.frame(
  Model = c(
    paste("Donor:", iyg_restricted$donor_events),
    paste("Target:", iyg_restricted$target_event)
  ),
  ARCH_q = iyg_selected_orders[, 1],
  GARCH_p = iyg_selected_orders[, 2],
  Asymmetry_o = iyg_selected_orders[, 3]
)

knitr::kable(
  iyg_order_table,
  row.names = FALSE,
  col.names = c(
    "Model",
    "ARCH order (q)",
    "GARCH order (p)",
    "Asymmetry indicator (o)"
  ),
  caption = paste(
    "Orders selected automatically by BIC for the",
    "donor and target variance models."
  )
)

## ----inspect-iyg-donor-adjustments--------------------------------------------
iyg_donor_summary <- data.frame(
  Donor = as.character(iyg_restricted$donor_events),
  Weight = as.numeric(
    iyg_fit$linear_combinations
  ),
  Estimated_adjustment = as.numeric(
    iyg_fit$meta$omega_vec
  )
)

knitr::kable(
  iyg_donor_summary,
  row.names = FALSE,
  digits = 6,
  col.names = c(
    "Donor episode",
    "DBW weight",
    "Estimated variance adjustment"
  ),
  caption = paste(
    "Donor weights and estimated variance adjustments",
    "for the restricted IYG specification."
  )
)

## ----inspect-iyg-combined-adjustment------------------------------------------
iyg_adjustment_table <- data.frame(
  Unadjusted_forecast = as.numeric(
    iyg_fit$predictions$unadjusted[1]
  ),
  Combined_adjustment = as.numeric(
    iyg_fit$meta$combined_omega
  ),
  Adjusted_forecast = as.numeric(
    iyg_fit$predictions$adjusted[1]
  )
)

knitr::kable(
  iyg_adjustment_table,
  row.names = FALSE,
  digits = 6,
  col.names = c(
    "Unadjusted variance forecast",
    "Combined donor adjustment",
    "DBW-adjusted variance forecast"
  ),
  caption = "Construction of the DBW-adjusted IYG variance forecast."
)

## ----compare-iyg-variance-forecasts-------------------------------------------
iyg_proxy_index <-
  iyg_restricted$shock_time_vec[1] + 1L

iyg_observed_proxy <- as.numeric(
  iyg_restricted$Y_series_list[[1]][iyg_proxy_index]
)^2

iyg_forecast_values <- c(
  as.numeric(
    iyg_fit$predictions$unadjusted[1]
  ),
  as.numeric(
    iyg_fit$predictions$arithmetic_mean[1]
  ),
  as.numeric(
    iyg_fit$predictions$adjusted[1]
  )
)

iyg_forecast_table <- data.frame(
  Method = c(
    "Observed squared-return proxy",
    "Unadjusted",
    "Arithmetic mean",
    "DBW adjusted"
  ),
  Variance = c(
    iyg_observed_proxy,
    iyg_forecast_values
  ),
  Absolute_error = c(
    NA_real_,
    abs(
      iyg_forecast_values -
        iyg_observed_proxy
    )
  )
)

knitr::kable(
  iyg_forecast_table,
  row.names = FALSE,
  digits = 6,
  col.names = c(
    "Method",
    "Variance",
    "Absolute error"
  ),
  caption = paste(
    "One-step variance forecast comparison for IYG",
    "under the restricted donor-pool specification."
  )
)

