Skip to content
exuber

Real-time monitoring

QPWY/QPSY Recursive Quantile Monitoring (Wu, Shi & Wu 2025)

monitor_quantile Replication record →
monitor_quantile(
  data,
  tau = 0.5,
  minw = NULL,
  nrep = 500L,
  sig_lvl = 95,
  seed = NULL,
  type = c("qpwy", "qpsy")
)

monitor_quantile implements the QPWY and QPSY real-time monitoring strategies of Wu, Shi & Wu (2025). They are quantile-regression (QR) analogues of the recursive ADF t-statistics of PWY and PSY, and they test at a chosen conditional quantile tau, in contrast to the single full-sample test in quantile_test. type = "qpwy" uses the expanding window [1, r], which has the shape of badf in radf. type = "qpsy" also takes the supremum over every window start, which has the shape of bsadf.

Arguments

data A univariate or multivariate numeric time series object, a numeric vector or matrix, or a data.frame. A column may have leading or trailing NA values, which describes an unbalanced panel in which series enter or exit the sample at different times. Those periods are filled with NA in badf and bsadf and excluded from the adf, sadf and gsadf of that series. Interior NA values (a gap in the middle of a series) are not supported. When any series is padded in this way, the panel statistics (bsadf_panel and gsadf_panel) are not available, and the function returns NA for them with a warning.
tau Quantile to test at, in (0, 1). It is fixed, in contrast to the "optimal" grid search in quantile_test, because eq. 25 of WSW takes tau as a given parameter of the monitoring statistic and does not reselect it at each recursion point.
minw A positive integer. The minimum window size (default = (0.01+1.8/T)T(0.01 + 1.8/\sqrt{T})T, where T denotes the sample size).
nrep Number of Monte Carlo replications for the boundary.
sig_lvl Significance level, one of 90, 95, 99.
seed Optional seed for the Monte Carlo draws.
type "qpwy" (expanding window) or "qpsy" (also the supremum over window starts).

Value

An object of class monitor_quantile_obj: a list with the statistic path stat, the flat boundary, the estimated delta, and alarm and alarm_date (the first breach, NA if there is none).

Details

The point statistic needs genuine QR fits, because there is no closed-form recursive update as there is for OLS. QPWY needs O(T) fits and QPSY needs O(T^2), so QPSY takes seconds for each series at n = 200 and the time grows quadratically.

The function simulates the critical value in each call from the limiting null distribution delta * Q_{r1,r2} + sqrt(1 - delta^2) * Z_{r1,r2}. Here delta is a correlation coefficient estimated from the data (as in quantile_test), Q is the Dickey-Fuller t functional and Z is its counterpart driven by an independent Brownian motion. Both are simulated for every window, so no QR fits are needed. The boundary is a single flat value and not one value for each r. It is the quantile of the supremum of each simulated path, constructed exactly like the sadf_cv of radf_mc_cv, which controls the first-crossing false-alarm rate.

Caveats

The boundary is the asymptotic one. Near the median it is well sized in finite samples, with a false-alarm rate of 3.5 to 4.0\% at a nominal 5\% (Gaussian and t3t_3 innovations, tau = 0.5). Away from the median the small early windows make both statistics oversized, and QPSY badly so even with Gaussian innovations. The false-alarm rate of QPSY is 35\% at tau = 0.9 (Gaussian). With t3t_3 innovations it is 21\% at tau = 0.8 and 44\% at tau = 0.9 (n = 100). With t3t_3 innovations the rate for QPWY is 7.5 to 8.5\% at tau = 0.2 and 0.8 and 12.5\% at tau = 0.9 (n = 150). Wu, Shi & Wu advise against extreme quantiles in small samples and use bootstrap critical values for monitoring. That bootstrap is not implemented here. For type = "qpsy" with tau away from 0.5, the function emits a short pointer as a message (see suppressMessages) and stores it as attr(x, "caveat"). The numbers are in docs/alternative-paradigms.md.

Status

[Experimental]

Examples

These examples are copied from the package's own documentation and are run by R CMD check on every release. The printed output (after #>) and the plots were produced by running them against the current package source.

# Heavy-tailed (t3) innovations, explosive from t = 150 to the sample end
y <- sim_psy1(n = 200, te = 150, tf = 200, seed = 7,
  e = sim_innov(199, dist = "t", df = 3))
res <- monitor_quantile(y, tau = 0.5, nrep = 100, seed = 1)
print(res)
#> 
#> ── monitor_quantile (QPWY, n = 200, minw = 27, tau = 0.5, sig_lvl = 95%) ───────
#> 
#>    series  delta  boundary  alarm  alarm_date
#>   series1  0.623     1.934    165         165
autoplot(res)
#> Warning: Removed 1 row containing missing values or values outside the scale range
#> (`geom_segment()`).
Plot from the monitor_quantile example
# Monitoring an upper quantile is typically more powerful for right-tailed
# bubbles, but see the Caveats section on extreme quantiles
autoplot(monitor_quantile(y, tau = 0.8, nrep = 100, seed = 1))
#> Warning: Removed 1 row containing missing values or values outside the scale range
#> (`geom_segment()`).
Plot from the monitor_quantile example
# QPSY: supremum over window starts too (O(n^2) QR fits, slower)
monitor_quantile(y[101:200], tau = 0.5, nrep = 100, seed = 1, type = "qpsy")
#> 
#> ── monitor_quantile (QPSY, n = 100, minw = 19, tau = 0.5, sig_lvl = 95%) ───────
#> 
#>    series  delta  boundary  alarm  alarm_date
#>   series1  0.754     2.172     53          53

See also

quantile_test for the static, full-sample version of this test, and monitor for the monitoring alternative based on OLS.

Other monitoring: monitor(), monitor_cusum(), monitor_lbi()

References

Wu, R., Shi, S., & Wu, J. (2025). Quantile analysis for financial bubble detection and surveillance. Journal of Time Series Analysis, 46(5), 908-931.