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 = , 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 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 innovations it is 21\% at tau = 0.8 and 44\% at tau = 0.9 (n = 100). With 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()`). # 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()`). # 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.
exuber