*! version 1.0.0 07jul2026 Merwan Roudane

Title

boundeduroot hlt -- Bounded multiple level-shift detection, HLT (CSG 2024)

Syntax

boundeduroot hlt varname [if] [in],
lbound(#) ubound(#)
[options]

lbound(#) lower bound b (required)

ubound(#) upper bound b-bar (required)

window(#) window fraction m; one of 0.10, 0.15 (default), 0.20, 0.25, 0.30

iter(#) Monte Carlo draws per candidate break; default 400

seed(#) RNG seed; default 1

level(#) confidence level; maps to CV percentile 90/95/97.5/99; default c(level)

nograph suppress the diagnostic figure

gname(string) name stub for the produced graph

Description

boundeduroot hlt detects multiple level shifts in a bounded time series, whatever its
order of integration, following Carrion-i-Silvestre & Gadea (2024), Case A (the boundaries do
not change). It first locates candidate break dates from the moving forward-minus-backward mean
M(t), then forms the Harvey-Leybourne-Taylor (2010) statistics

S1 = max|M| / sqrt(T) / sqrt(omega_e) (uses the I(1) long-run variance),

S0 = max|M| * sqrt(T) / sqrt(omega_u) (uses the I(0) long-run variance),

where omega_e and omega_u are autoregressive long-run variances of the differenced
and level residuals. Because the series is bounded, the critical values are not the original
HLT constants; instead the command simulates, for each candidate break, a regulated (reflected)
Brownian motion (for S1, from a bounded I(1) path) and a bounded I(0) process (for S0), with the
bounds shifted by the cumulative mean of the earlier breaks, and reports the bound-specific
critical values together with a union (U) decision. A break is flagged as a genuine level shift
when its statistic exceeds the simulated critical value.

Note. The command is simulation-intensive (each candidate break requires iter bounded
paths, each re-running the detection and two long-run-variance estimators); expect a wait of tens
of seconds. Start with the default iter(400) and raise it for final results.

Options

lbound(#), ubound(#) give the (known, constant) bounds.

window(#) is the HLT window fraction m; it also fixes the maximum number of candidate
breaks (8, 5, 4, 3, 3 for m = 0.10, 0.15, 0.20, 0.25, 0.30).

iter(#), seed(#), level(#) control the simulated critical values and the
reported percentile.

Stored results

Scalars

r(N) number of observations

r(nbreaks) number of candidate breaks examined

r(n_shift_s1) r(n_shift_s0) breaks flagged by S1 / S0

r(omega_u) r(omega_e) level / difference long-run variances

r(x0) r(lbound) r(ubound) first obs and bounds

Matrices

r(result) nb×7: position, S1, S0, CV(S1), CV(S0), reject_S1, reject_S0

Examples

. tsset time

. boundeduroot hlt urate, lbound(2) ubound(20)

. boundeduroot hlt urate, lbound(2) ubound(20) window(0.20) iter(1000)

References

Carrion-i-Silvestre, J. L., and M. D. Gadea. 2024. Detecting multiple level shifts in bounded
time series.

Harvey, D. I., S. J. Leybourne, and A. M. R. Taylor. 2010. Robust methods for detecting multiple
level breaks in autocorrelated time series. Journal of Econometrics 157: 342-358.

Author

Dr Merwan Roudane -- merwanroudane920@gmail.com -- github.com/merwanroudane