---
title: "Uncertainty Bands via Block Bootstrap"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Uncertainty Bands via Block Bootstrap}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment  = "#>",
  fig.width  = 7,
  fig.height = 4.5,
  out.width  = "100%"
)
```

```{r setup, message=FALSE}
library(MacroFilters)
library(ggplot2)
data("fr_gdp", package = "MacroFilters")

# France real GDP (log level) as a quarterly ts; includes the 2020 Q2 COVID shock
d0 <- fr_gdp$date[1]
fr <- ts(
  fr_gdp$gdp_log,
  start     = c(as.integer(format(d0, "%Y")),
                (as.integer(format(d0, "%m")) - 1L) %/% 3L + 1L),
  frequency = 4
)
```

---

## 1. Why quantify trend uncertainty?

A point estimate of the trend is only half the story. In real time the trend is
most uncertain exactly where it matters most — at the **end of the sample**,
where the smoother has no future observations to lean on. Every filter in
**MacroFilters** can attach a 95% confidence band to its trend through a single
argument, `boot_iter`.

```{r basic-band}
fit <- mbh_filter(fr, boot_iter = 50L)   # mstop defaults to 500
str(fit[c("trend_lower", "trend_upper")], max.level = 1)
```

When `boot_iter > 0` the returned object gains `$trend_lower` and
`$trend_upper`; otherwise they are absent. Plotting is automatic — `autoplot()`
draws the ribbon whenever the bands are present:

```{r basic-plot}
autoplot(fit)
```

The trend cuts almost straight through the 2020 COVID collapse: the Huber loss
treats the shock as an outlier rather than bending the trend toward it.

---

## 2. The mechanics

The engine is a **Circular Block Bootstrap** (Politis & Romano, 1992) of the
filter's pseudo-residuals (the cycle):

1. Resample the cycle in contiguous **blocks** that wrap around the series end,
   preserving short-run autocorrelation while giving every observation equal
   weight (no end-point under-representation).
2. Rebuild a synthetic series `trend + resampled cycle` and **refit the same
   filter** to it. Each refit uses the *same estimator* as the base fit (same
   `mstop` for MBH, same iteration count for bHP), so the band width is not
   biased.
3. The band is the **normal approximation** `trend ± 1.96 * sd(bootstrap trends)`,
   centred on the point estimate. The standard deviation is used instead of raw
   2.5%/97.5% percentiles because it is smooth and stable at a practical
   `boot_iter` (percentiles need hundreds of replicates to avoid jitter).

Two knobs control it:

- **`boot_iter`** — number of bootstrap replicates (cost grows linearly).
- **`block_size`** — block length; `"auto"` (default) uses `2 * frequency`
  (two cycles), capped at `length(x) / 3` to keep at least three blocks.

```{r block-size}
# Quarterly data -> auto block size = 2 * 4 = 8
fit_b <- mbh_filter(fr, boot_iter = 50L, block_size = 8L)
```

---

## 3. Bands for every filter

The same machinery is available on all four filters. Note that MBH keeps the
default `mstop = 500`: for long log-level series, reducing `mstop` collapses the
trend (the Huber gradient is capped from the first iteration, so the trend never
climbs its full range).

```{r all-filters, fig.height=3.6}
autoplot(hp_filter(fr,       boot_iter = 50L))
autoplot(bhp_filter(fr,      boot_iter = 50L))
autoplot(hamilton_filter(fr, boot_iter = 50L))
autoplot(mbh_filter(fr,      boot_iter = 50L))
```

### Reading the end-point fan

For all filters the band **widens toward the edges** — typically two to three
times the mid-sample width. This is honest, not a bug: estimating the trend at
`t = n` with no future data is genuinely far more uncertain than in the
interior. It is precisely the *end-point problem* these filters are designed to
expose.

### A note on the Hamilton band

The Hamilton filter is a regression on lags of the series, so its first
`h + p - 1` observations have no fitted trend (they appear as `NA`, leaving a
gap at the start of the plot). Its bootstrap is **conditional on those initial
observations**: the lead-in is held fixed across replicates. As a result the
band is narrow at the start of the valid window — where the predictors are the
frozen lead-in and only the regression coefficients vary — and widens forward as
the predictors themselves become resampled quantities.

---

## 4. References

- Politis, D.N. and Romano, J.P. (1992). A circular block-resampling procedure
  for stationary data. In *Exploring the Limits of the Bootstrap*, 263–270.
- Künsch, H.R. (1989). The jackknife and the bootstrap for general stationary
  observations. *Annals of Statistics*, 17(3), 1217–1241.
