*! version 1.9.0 31jul2026

help for qrbreak

Title

qrbreak -- Structural breaks in quantile regression (testing and estimation)

Syntax

qrbreak depvar indepvars [if] [in], tau(numlist) [nsize(#) trim(#) maxbreaks(#) alpha(#) cilevel(#) time(varname) norm(method)]

indepvars may contain factor variables and time-series operators; base
and omitted factor levels are dropped automatically, exactly as
model.matrix() does in R. The dependent variable may carry
time-series operators but may not be a factor variable.

Description

qrbreak tests for structural breaks occurring at unknown dates in regression
quantiles and estimates the break dates, their confidence intervals, and the
regression coefficients in each regime. The analysis is carried out both
quantile by quantile (the SQ test of Qu 2008) and jointly over a range of
quantiles (the DQ test of Oka and Qu 2011). The number of breaks is determined
by a sequential testing procedure, break dates are estimated by dynamic
programming, and confidence intervals for the break dates are constructed under
the shrinking-break asymptotic framework of Oka and Qu (2011).

The command is a faithful port of the R package QR.break version 1.0.3 by
Zhongjun Qu and Tatsushi Oka (with contributions by Samuel Messer), including
verbatim ports of the quantile regression solvers of the R package
quantreg version 6.1 by Roger Koenker (rqbr.f, the modified
Barrodale-Roberts simplex, and rqfnb.f, the Frisch-Newton interior point
method). All deterministic results replicate the R implementation.

The approach extends the multiple-structural-break framework of Bai and
Perron (1998, 2003), developed for conditional mean regressions, to
conditional quantiles: the dynamic-programming estimation of the break dates
and the sequential determination of their number follow the Bai-Perron
methodology, while the SQ and DQ statistics replace the mean-regression
tests with subgradient-based tests suited to quantile regression.

The framework assumes stationary, I(0), regressors and errors; it is not
designed for unit-root or cointegrated series. The nsize() option
accommodates repeated cross sections (a fresh sample of units in every
period); genuine panel models with unit fixed effects are outside its scope.
For classical Bai-Perron break tests in conditional mean models with I(0)
series see the author's command byperron; for structural breaks in
cointegrating relationships see the author's command kperrony.

The data must be ordered as in the R original: for time series data
(nsize(1), the default) simply in time order; for repeated cross sections
the first N observations belong to period 1, the next N to period 2,
and so forth, where N is given in nsize(). A constant is added
automatically and all regression coefficients are allowed to change across
regimes.

Methods: what the command does, step by step

Step 1. Objective values on all admissible subsamples. For every
admissible segment of the sample (every start and end period such that the
segment contains at least round(T*trim) periods) the quantile
regression objective function (the sum of the check function evaluated at the
segment fit) is computed at each requested quantile. These values are the
building blocks of everything that follows.

Step 2. Break date estimation by dynamic programming. For a given number
of breaks m, the break dates are estimated globally: the sample is split
into m+1 regimes so that the sum of the segment objective values is
minimized over all admissible partitions, using the dynamic programming
recursion of the Bai-Perron type adapted to quantile objectives. For the
single-quantile analysis the objective of that quantile is used; for the
multiple-quantile analysis the objectives are summed over the specified
quantiles, so that all quantiles share the same break dates (Oka and Qu 2011).

Step 3. Testing 0 versus 1 break (the SQ statistic, Qu 2008). The model
without breaks is estimated on the full sample and the subgradient process of
the quantile regression is formed: the normalized partial sums of the sign
function of the residuals, weighted by the regressors. Under the null of no
break this process fluctuates around a straight line; the SQ statistic is the
largest standardized deviation of the process from that line, taken over time
and over coefficients. The sign classification of the residuals follows R
exactly: the fitted values are accumulated in extended precision, matching
R's internal matrix product, so the statistics replicate the CRAN
QR.break output digit for digit. Under norm(spectral) the normalization matrix is instead the rescaled symmetric square root of the regressor correlation matrix, following QR.break 1.0.3; the same critical values apply.

Step 4. Sequential testing for the number of breaks. To test l
versus l+1 breaks, the sample is split at the l estimated break
dates and the 0-versus-1 test of Step 3 is applied within each regime; the
statistic is the maximum over regimes. If it exceeds the critical value, the
procedure moves on to l+1 breaks, up to maxbreaks(); the first
non-rejection determines the number of breaks. The decision reported in the
output uses the level in alpha(); the results for all three levels (10,
5, 1 percent) are computed and stored in e().

Step 5. The DQ test (Oka and Qu 2011). The DQ statistic applies the same
construction jointly over the quantile range: the subgradient process is
evaluated on a grid of quantiles spanning [min(tau), max(tau)] with
grid step 1/T, and the maximum is taken over time, coefficients, and
quantiles. This test has power against breaks occurring anywhere in the
specified part of the conditional distribution and is the primary test for the
overall decision when several quantiles are given (Part 2 and the Conclusion
in the output).

Step 6. Critical values. SQ critical values come from the table
distributed with the R package; DQ critical values come from the response
surface when the quantile range is symmetric and from simulation otherwise
(see Critical values below).

Step 7. Confidence intervals for the break dates. Each estimated break
date receives a confidence interval built under the shrinking-break asymptotic
framework of Oka and Qu (2011), using the estimated coefficient changes
between the adjacent regimes and kernel estimates of the conditional densities
in those regimes.

Step 8. Regime coefficients and break sizes. Conditional on the
estimated break dates, the quantile regression with regime-specific
coefficients is estimated; standard errors, t statistics, and p-values use the
nid-type sandwich estimator of quantreg. Break sizes are the
differences between the coefficients of consecutive regimes, with standard
errors from the same covariance matrix.

Options

tau(numlist) is required and specifies the quantiles used for break
detection and estimation, for example tau(0.2(0.15)0.8). With a single
quantile only the SQ analysis is performed; with several quantiles the DQ
analysis over the range [min(tau), max(tau)] is added.

nsize(#) is the number of cross-sectional units per time period; default
nsize(1) (time series). When time() is given and nsize() is
omitted, qrbreak counts the observations in each period of the time
variable and, if every period has the same count, uses that count
automatically (a note is printed). Unequal counts or periods whose
observations are not contiguous stop with an error, and an explicitly given
nsize() that conflicts with the period structure of time() is
likewise rejected.

trim(#) is the trimming proportion; the minimum regime length is
round(T*trim). Default trim(0.15).

maxbreaks(#) is the maximum number of breaks allowed (at most 10).
Default maxbreaks(3).

alpha(#) is the significance level, in percent, used in the sequential
procedure that determines the number of breaks; one of 10, 5, or 1. Default
alpha(5).

cilevel(#) is the coverage level, in percent, of the confidence intervals
for the break dates; one of 90 or 95. Default cilevel(95).

time(varname) gives a (numeric or string) variable holding the date label
of each observation; the value at the first observation of each period is used
to report break dates in date format. If omitted, break dates are reported as
observation indices only.

norm(method) selects how the subgradient process underlying the SQ and
DQ tests is normalized; it is the exact counterpart of the norm.method
argument of QR.break version 1.0.3. norm(cholesky), the default, uses
the Cholesky factor of the regressor cross-product matrix and reproduces
QR.break versions 1.0.2 and earlier exactly; because that factor is built
sequentially, the test statistics depend on the order in which the regressors
are listed. norm(spectral) uses the symmetric square root of the
correlation matrix of the regressors, rescaled by their standard deviations,
and is therefore invariant to the ordering, units, and signs of the
regressors. Both normalizations have the same limiting null distribution, so
the same critical values apply and both tests are valid. Break dates, their
confidence intervals, and regime coefficients do not depend on norm().

Critical values

Critical values of the SQ test are taken from the table distributed with the R
package (for up to 100 coefficients and 10 breaks). Critical values of the DQ
test are computed from the response surface in Qu (2008) and Oka and Qu (2011)
when the quantile range is symmetric (that is, min(tau) = 1 - max(tau)), at
most 20 coefficients change, and at most 5 breaks are allowed; otherwise they
are obtained by simulation (500 grid points, 50,000 replications), exactly as
in the R package. The R original does not set a random seed for these
simulations, so simulated DQ critical values are inherently stochastic in both
implementations; set set seed beforehand if you need reproducibility of
the simulated critical values within Stata.

Performance and the compiled plugin

The computational core of qrbreak (the Barrodale-Roberts quantile
regression solver, the subsample objective-value precomputation, and the SQ
and DQ test statistics) ships as a compiled C plugin. When qrbreak is
called it loads the plugin for the current operating system
(qrbreak_core_windows.plugin, qrbreak_core_unix.plugin, or on
macOS qrbreak_core_macosx_arm64.plugin /
qrbreak_core_macosx_x86_64.plugin, tried in turn) and uses it
automatically. If no plugin is available for the platform, the command
falls back to a pure Mata implementation of the very same algorithms. The
two paths produce identical results; the plugin is only faster. For
orientation, on the author's machine the GDP example of this help file runs
in about 10 seconds with the plugin, while the same analysis in R
(QR.break under R 4.3 on Windows) takes about one minute. The DQ
critical values for asymmetric quantile ranges are obtained by simulation
without a fixed seed, exactly as in the R original, and therefore vary
slightly across runs; all other reported numbers are deterministic.

Examples

Two datasets accompany the command; both are the example datasets shipped
with the R package QR.break and are hosted at the URLs used below.
gdp.dta is the time-series application of Qu (2008) and Oka and Qu
(2011): quarterly US real GDP growth from 1947 Q4 to 2009 Q2 (247 quarters),
with variables gdp (the growth rate), lag1 and lag2 (its
first two lags, the regressors of an AR(2)), and yq (the quarter
label). driver.dta is the repeated cross-section application of Oka
and Qu (2011): the blood alcohol concentration of young drivers over
1983 Q1 to 2007 Q4, with 108 drivers sampled afresh in each of the 100
quarters (10,800 observations) and variables bac (blood alcohol
concentration), age, gender and winter (the latter two 0-1
indicators), and yq (the quarter label).

Example 1, with its replication in R: US real GDP growth (Qu 2008; Oka
and Qu 2011, Section 6.2; 1947Q4-2009Q2). In Stata:

. use https://www.eruygurakademi.com/datasets/qrbreak/gdp.dta, clear

. qrbreak gdp lag1 lag2, tau(0.2(0.15)0.8) trim(0.15) maxbreaks(3) alpha(5) cilevel(95) time(yq)

The identical analysis in R with the package QR.break (version 1.0.3);
v.a = 2 selects the 5 percent decision level of alpha(5) from the
levels (10, 5, 1), and v.b = 2 selects the 95 percent confidence level
of cilevel(95) from the levels (90, 95):

library(QR.break)

data(gdp)

res <- rq.break(y = gdp$gdp, x = gdp[, c("lag1", "lag2")],

vec.tau = seq(0.2, 0.8, by = 0.15), N = 1, trim.e = 0.15,

vec.time = gdp$yq, m.max = 3, v.a = 2, v.b = 2, verbose = TRUE)

The test statistics, critical values, break dates, confidence intervals, and
coefficient tables printed by the two commands coincide (R prints them in its
own layout; the R return value res holds them in res$s.out and
res$m.out).

Example 2, with its replication in R: blood alcohol of young drivers
(Oka and Qu 2011, Section 6.1), a repeated cross section with 108 drivers
per quarter. In Stata:

. use https://www.eruygurakademi.com/datasets/qrbreak/driver.dta, clear

. qrbreak bac age gender winter, tau(0.70(0.05)0.85) nsize(108) trim(0.05) maxbreaks(3) alpha(5) cilevel(95) time(yq)

In R:

library(QR.break)

data(driver)

res <- rq.break(y = driver$bac, x = driver[, c("age", "gender", "winter")],

vec.tau = seq(0.70, 0.85, by = 0.05), N = 108, trim.e = 0.05,

vec.time = driver$yq, m.max = 3, v.a = 2, v.b = 2, verbose = TRUE)

All deterministic numbers again coincide; only the simulated DQ critical
values differ across runs (in both implementations), because the quantile
range is asymmetric and the R original draws them without a fixed seed.

Example 3. Choosing the quantiles with tau(). If the question concerns only the
center of the conditional distribution, a single quantile suffices; only the
SQ analysis is performed and the summary decision is based on it:

. use https://www.eruygurakademi.com/datasets/qrbreak/gdp.dta, clear

. qrbreak gdp lag1 lag2, tau(0.5) time(yq)

If breaks may affect different parts of the distribution differently (for
example the lower tail shifting while the median is stable), give a grid of
quantiles; each quantile gets its own SQ analysis and the DQ test pools them
for the overall decision:

. use https://www.eruygurakademi.com/datasets/qrbreak/gdp.dta, clear

. qrbreak gdp lag1 lag2, tau(0.2(0.15)0.8) time(yq)

If the application concerns one tail only, use an asymmetric range, as in the
driver example above with tau(0.70(0.05)0.85); note that for asymmetric
ranges the DQ critical values are obtained by simulation, which takes
additional time and makes those critical values (only) vary across runs.

Example 4. Repeated cross sections with nsize(). When each time period contains
N independent units (households, firms, individuals), sort the data so
that the first N observations are period 1, the next N period 2, and
so on, and give N in nsize(). Breaks are then breaks in calendar
time, not in the observation index:

. use https://www.eruygurakademi.com/datasets/qrbreak/driver.dta, clear

. qrbreak bac age gender winter, tau(0.75) nsize(108) trim(0.05) time(yq)

Example 5. Controlling the minimum regime length with trim(). trim() sets the
shortest regime the procedure is allowed to consider, as a share of the number
of periods. Increase it when T is small or when the coefficient tables
of short regimes would be too imprecise to be useful; decrease it (as in the
driver example, trim(0.05)) when breaks close to the sample boundaries
or close to each other are plausible and T*trim still comfortably
exceeds the number of regressors:

. use https://www.eruygurakademi.com/datasets/qrbreak/gdp.dta, clear

. qrbreak gdp lag1 lag2, tau(0.5) trim(0.25) time(yq)

Example 6. Capping the search with maxbreaks(). The sequential procedure stops at
maxbreaks() even if the last test still rejects. Raise it when the
sample is long and many regimes are plausible; each additional break adds
another round of subsample testing:

. use https://www.eruygurakademi.com/datasets/qrbreak/gdp.dta, clear

. qrbreak gdp lag1 lag2, tau(0.5) maxbreaks(5) time(yq)

Example 7. Choosing the decision level with alpha(). alpha() only selects
which significance level drives the reported DECISION lines and the summary;
alpha(10) is more liberal (more breaks found), alpha(1) more
conservative. All three levels are always computed and stored, so the choice
can be revisited from e() without re-running:

. use https://www.eruygurakademi.com/datasets/qrbreak/gdp.dta, clear

. qrbreak gdp lag1 lag2, tau(0.2(0.15)0.8) alpha(1) time(yq)

. matrix list e(sq_nbreak_4)

Example 8. Confidence interval coverage with cilevel(). cilevel(90) reports
narrower 90 percent intervals for the break dates instead of the default 95
percent; use it when the dating precision itself is of interest:

. use https://www.eruygurakademi.com/datasets/qrbreak/gdp.dta, clear

. qrbreak gdp lag1 lag2, tau(0.65) cilevel(90) time(yq)

Example 9. Readable dates with time(). Without time() break dates are
reported as observation (period) indices only. Supplying a date variable
(numeric or string; the value at the first observation of each period is used)
turns every reported date and confidence interval into calendar form:

. use https://www.eruygurakademi.com/datasets/qrbreak/gdp.dta, clear

. qrbreak gdp lag1 lag2, tau(0.65)

. qrbreak gdp lag1 lag2, tau(0.65) time(yq)

Example 10. Restricting the sample with if/in. Any if or in restriction
is applied before the analysis; with nsize() greater than one make sure
the restriction keeps whole periods:

. use https://www.eruygurakademi.com/datasets/qrbreak/gdp.dta, clear

. qrbreak gdp lag1 lag2 in 1/200, tau(0.5) time(yq)

Stored results

qrbreak stores the following in e() (k = 1, ..., number of
quantiles, in the order of tau()):

Scalars

e(N) number of observations

e(T) number of time periods

e(nsize) cross-section size per period

e(trimsize) minimum regime length

e(ntau) number of quantiles

e(sq_nb_k) number of breaks detected by the SQ procedure at quantile k and the chosen alpha

e(dq_nbreak) number of breaks detected by the DQ procedure at the chosen alpha

Matrices

e(tau) quantiles used

e(sq_test_k) SQ test statistics (1 x maxbreaks)

e(sq_cv_k) SQ critical values at 10, 5, 1 percent (3 x maxbreaks)

e(sq_nbreak_k) numbers of breaks at 10, 5, 1 percent (3 x 1)

e(sq_dates_k) estimated break dates by significance level (3 x maxbreaks)

e(sq_ci_k) break date estimates and confidence intervals

e(sq_coef_k) regime coefficient tables, stacked (Value, StdErr, t, p)

e(sq_bsize_k) break size tables, stacked

e(dq_test), e(dq_cv), e(dq_nbreak_all), e(dq_dates), e(dq_ci) the DQ counterparts

e(mq_coef_k), e(mq_bsize_k) regime coefficients and break sizes at quantile k, conditional on the DQ break dates

References

Bai, J. and P. Perron (1998). Estimating and testing linear models with
multiple structural changes. Econometrica 66(1), 47-78.

Bai, J. and P. Perron (2003). Computation and analysis of multiple structural
change models. Journal of Applied Econometrics 18(1), 1-22.

Qu, Z. (2008). Testing for structural change in regression quantiles.
Journal of Econometrics 146(1), 170-184.

Oka, T. and Z. Qu (2011). Estimating structural changes in regression quantiles.
Journal of Econometrics 162(2), 248-267.

Koenker, R. (2005). Quantile Regression. Cambridge University Press.

Qu, Z., T. Oka, and S. Messer (2025). QR.break: Structural Breaks in Quantile
Regression. R package version 1.0.3.

Author

H. Ozan Eruygur

AHBV University, Ankara, Turkiye.

Department of Economics

https://www.ozaneruygur.com

eruygur@gmail.com

Eruygur Academy and Consulting (Eruygur Akademi ve Danismanlik), Ankara, Turkiye.

https://www.eruygurakademi.com

eruygurakademi@gmail.com

This command is a faithful Stata/Mata port of the R package QR.break v1.0.3 by Zhongjun Qu, Tatsushi Oka, and Samuel Messer, including verbatim ports of the quantreg 6.1 solvers of Roger Koenker.

qrbreak v1.11.0 - July 2026

Please cite as:

Eruygur, H. O. 2026. qrbreak: Structural breaks in quantile regression (testing and estimation).
Stata package version 1.11.1. Available from: https://www.eruygurakademi.com