Monitoring and testing
radf(), datestamp() and the
dating_*() family (see
vignette("dating-methods")) all work on a finished sample.
They answer the question of whether there was a bubble, and when, after
every observation is already in hand. The monitor_*()
family answers a real-time question instead. We fix a training window
[1, T*] that we believe is free of exuberance and calibrate
a boundary on it. We then watch each new observation
T*+1, T*+2, ... and raise an alarm the first time the
boundary is crossed. All four functions share this r_star,
alarm and alarm_date structure. They differ in the
statistic they monitor and in how they calibrate the boundary.
| Function | Statistic monitored | Boundary | Static, full-sample counterpart |
|---|---|---|---|
monitor() |
radf()’s own badf/bsadf
recursion |
"bootstrap" (Phillips & Shi 2020 wild-bootstrap
quantile), "kurozumi" (closed-form, Kurozumi 2020), or
"fluc" (closed-form, Homm & Breitung 2012) |
radf() and datestamp(). It is not a
_test() function, but it uses the same recursive ADF
core |
monitor_cusum() |
A CUSUM of the training-window-standardized series | Homm & Breitung (2012)’s asymptotic (or finite-sample) constant | None. The CUSUM boundary of Homm & Breitung is a training and monitoring construction by design and has no full-sample form |
monitor_lbi() |
Breitung & Diegel (2025)’s locally-best-invariant CUSUM
(mCUSUM/wCUSUM, via c_bar) |
Their Table 1 constant |
lbi_test(), the static version of the same
statistic |
monitor_quantile() |
A recursive quantile regression at tau
|
A simulated first-crossing boundary (Wu, Shi & Wu 2025) |
quantile_test(), the static version of the same
statistic |
monitor() reuses badf and
bsadf directly, which is the same recursive ADF core as in
the radf_*() family. It is named after what it does and not
after that internal detail (see
vignette("naming-and-analysis") for the reasoning). Two of
its three siblings, monitor_lbi() and
monitor_quantile(), are the sequential extension of an
existing static test with the same name minus the monitor_
prefix. monitor_cusum() has no such counterpart, because
its source paper (Homm & Breitung 2012) proposed the CUSUM only as a
monitoring detector.
One bubble, five monitors
The series starts with a training window of pure random walk
(T* = 100) and continues as a random walk until
t = 150. From then until the end of the sample it follows
an explosive regime (rho = 1.04). We generate it with
sim_psy1(), placing the bubble after the training window
and leaving out the collapse:
y <- sim_psy1(n = 200, te = 150, tf = 200, c = 0.04, alpha = 0, seed = 7)
monitor_lbi(y, r_star = 100)
#>
#> ── monitor_lbi (T* = 100 / 200, c_bar = 0, b_alpha = 1.95) ─────────────────────
#>
#> series alarm alarm_date
#> series1 156 156
monitor_cusum(y, r_star = 0.5)
#>
#> ── monitor_cusum (T* = 100 / 200, b_alpha = 4.6) ───────────────────────────────
#>
#> series alarm alarm_date
#> series1 161 161
monitor_quantile(y, tau = 0.5, nrep = 200, seed = 1)
#>
#> ── monitor_quantile (QPWY, n = 200, minw = 27, tau = 0.5, sig_lvl = 95%) ───────
#>
#> series delta boundary alarm alarm_date
#> series1 0.64 1.909 161 161
monitor(y, r_star = 0.5, nboot = 200, seed = 1)
#>
#> ── monitor (T* = 100 / 200, minw = 27, sig_lvl = 95%, boundary = bootstrap) ────
#>
#> series boundary alarm alarm_date
#> series1 2.17 156 156
monitor(y, r_star = 0.5, boundary = "kurozumi")
#>
#> ── monitor (T* = 100 / 200, minw = 27, sig_lvl = 95%, boundary = kurozumi) ─────
#>
#> series boundary alarm alarm_date
#> series1 1.038 159 159monitor_lbi() and monitor_quantile() each
have a static, full-sample counterpart that asks the retrospective
version of the same question. It runs on the whole series and does not
wait for a first crossing:
lbi_test(y)
#>
#> ── lbi_test (n = 200, sig_lvl = 95%) ───────────────────────────────────────────
#>
#> series stat crit detected
#> series1 6.502 1.645 TRUE
quantile_test(y, tau = 0.5)
#>
#> ── quantile_test (n = 200, sig_lvl = 95%) ──────────────────────────────────────
#>
#> series tau tstat crit delta detected
#> series1 0.5 20.25 0.5041 0.64 TRUEEvery monitor alarms within about 15 observations of the true bubble
start (150), and none alarms before it. Each function’s own test suite
checks the absence of alarms before T* (or the true start)
under the null. The timing of the alarm differs by design. The
ADF-family statistics in monitor() tend to detect bubbles
in the middle of the sample fastest, as the literature finds (for
example Kurozumi 2020, 2021). The CUSUM-type detectors
(monitor_cusum() and monitor_lbi()) are
typically slower, but they are computationally simpler and need no
bootstrap.
Which to reach for
- If you want the fastest detection and can afford a wild bootstrap on
each call, use
monitor(boundary = "bootstrap"), which is the default. - If you want the same statistic without a bootstrap, using a
published constant instead, use
monitor(boundary = "kurozumi")ormonitor(boundary = "fluc"). - If you want a simpler CUSUM-based alternative with its own
closed-form boundary, use
monitor_cusum(). For the locally best invariant version of Breitung & Diegel, usemonitor_lbi(), wherec_bar > 0gives up a little size in exchange for power against slowly building bubbles. - If you want to monitor a specific quantile of the distribution
instead of the mean, use
monitor_quantile().
