*! version 1.0.0 09jul2026

Title

xtkpybreak break -- Multiple structural breaks in slopes and
error-factor loadings of non-stationary heterogeneous panels
(Baltagi, Feng & Wang 2025)

Syntax

xtkpybreak break depvar indepvars [if] [in]
, nbreaks(#) [options]

Main
nbreaks(#) number of structural breaks m to estimate
(required, >= 1)

loadings also allow breaks in the error-factor loadings
(BFW model 5); the default is breaks in slopes only (model 4)

proxy(x|yx) factor proxy: cross-section averages of the
regressors only (x, the BFW default) or of (depvar,indepvars)
(yx)

trim(#) trimming fraction; breaks are searched in
[#T, (1-#)T]; default trim(0.10) as in BFW

nonstationary label the regressors as I(1) after the CCE
transform (BFW Case 2, T-consistent slopes); affects only the reported theory,
not the point estimates

noconstant proxy f(t) by the cross-section averages alone, with
no intercept in the proxy block (strict BFW eq. 9)

hac(#) Bartlett (Newey-West) window for the individual-slope
standard errors (BFW Prop. 1); default is the automatic
floor(4(T/100)^(2/9))

level(#) confidence level; default level(95)

Graphs
breakplot plot the cross-section average of depvar over time
with the estimated break dates marked

coefevolution plot the regime-by-regime mean-group slope of the
first regressor as a step function with confidence band

name(stub) name stub for the saved graphs (default xtkpb)

Description

xtkpybreak break estimates m unknown structural break points and the
regime-specific slopes in a non-stationary heterogeneous panel with an
unobserved multifactor error structure, following Baltagi, Feng & Wang (2025).
Building on Kapetanios, Pesaran & Yamagata (2011), the unobserved I(1) factors
are proxied by cross-section averages; breaks in slopes and (optionally) in
error-factor loadings then reduce to breaks in a linear panel regression, which
are estimated by least squares using the Bai & Perron (1998, 2003)
dynamic-programming algorithm.

The break dates are found by minimizing the panel sum of squared residuals
of the unrestricted regression, in which the augmented regressor
z(it) = (x(it), proxy(t)) is fully interacted with the regimes, over all
admissible m-partitions (BFW eqs 11-13); the global optimum is obtained by
dynamic programming, not a heuristic. As N grows, the estimated break dates
converge to the truth (BFW Theorems 1-2). Given the breaks, the regime slopes
are computed by the partitioned CCE regression b(i) = [X(i)(K0)' M X(i)(K0)]^-1
X(i)(K0)' M Y(i) (BFW eqs 14-15) and averaged across panels to give a
mean-group estimate per regime, whose standard error comes from the
cross-panel dispersion (BFW Proposition 2). A pooled estimate is also stored.

Two break specifications. Because the break dates come from the unrestricted
model, the loadings option does not change the break dates - it
changes only how the regime slopes are then estimated:

o model 4 (default) - the error-factor loadings are held
constant; the proxy projection M is global (BFW eq. 14). This is the correctly
specified, more efficient estimator when only the slopes break.

o model 5 (loadings) - the loadings may break together
with the slopes; the proxy projection M is regime-specific (BFW eq. 15). Use when
the error-factor variance may also shift.

Requirements. The data must be xtset and balanced.
Time-series operators are allowed in indepvars. Because the unrestricted
break search fits z(it) = (x(it), proxy(t)) in every regime, with m breaks
and trimming # at least (m+1) regimes each of length >= max(#T, k+p+1)
must fit in T, where p is the width of the proxy block (1 constant + the
regressor averages, plus the depvar average under proxy(yx)); other-
wise the command stops and asks you to reduce nbreaks() or trim().

Options

nbreaks(#) sets the number of break points m (required). The sample
is split into m+1 regimes. When loadings is not specified, all breaks
are in the slopes; when it is, the breaks are a joint set of slope and loading
breaks (BFW pool them, eq. 11).

loadings switches from model 4 (slope breaks) to model 5 (slope and
loading breaks). See Description.

proxy(x|yx) selects the cross-section averages used as the factor proxy;
x (regressors only) is the BFW default, yx adds the average of the
dependent variable (Pesaran/KPY style).

trim(#) sets the minimum regime length as a fraction of T. BFW use 0.10
(search over 0.1T ... 0.9T). Must lie in (0, 0.5).

nonstationary declares the idiosyncratic regressor component v(it) to be
I(1) (BFW Case 2). In that case y(it) and x(it) cointegrate within each regime
and the individual slopes are T-consistent (super-consistent), and the relative
rate restriction is not needed. This option changes only the theory note printed
and stored in e(regressors); the point estimates and break dates are
computed identically.

noconstant proxies the unobserved factors by the cross-section averages
x-bar(t) (and y-bar(t) under proxy(yx)) with no separate
intercept, matching BFW eq. (9) exactly. By default a constant (the KPY
deterministic D term) is included in the proxy block; it is either held
constant (model 4) or allowed to break with the loadings (model 5). Note the
minimum regime length falls by one when noconstant is used.

hac(#) sets the Bartlett/Newey-West truncation window used for the
individual-panel slope standard errors (BFW Proposition 1, eqs 17-18). The
default (a negative value) uses the automatic bandwidth
floor(4(T/100)^(2/9)). These per-panel HAC standard errors are stored in
e(se_i); they are distinct from the mean-group standard errors shown in the
table, which come from the cross-panel dispersion (Proposition 2) and need no
kernel. The window actually used is stored in e(hac).

level(#) sets the confidence level for the reported intervals and the
coefevolution band.

breakplot plots the cross-section average of depvar against time with
vertical dashed lines at the estimated break dates.

coefevolution plots the mean-group slope of the first regressor as a
step function across regimes, with a shaded level% confidence band and
vertical lines at the break dates - the standard "structural change"
picture used in applied panels.

name(stub) sets the stub for saved graph names: stub_break and
stub_evo.

Stored results

xtkpybreak break stores the following in e():

Scalars

e(N) number of observations

e(N_g) number of panels (N)

e(Tbar) time periods per panel (T)

e(k) number of regressors

e(nbreaks) number of breaks m

e(ssr) minimized total sum of squared residuals

e(trim) trimming fraction

e(hac) Newey-West window used for the individual s.e.

Macros

e(cmd) xtkpybreak

e(subcmd) break

e(model) break specification (model 4 / model 5)

e(regressors) Case 1 (I(0)) or Case 2 (I(1))

e(proxy) x or yx

Matrices

e(b), e(V) stacked regime mean-group slopes (equations
r1..r(m+1)) and their variance

e(breakdates) m x 1 vector of estimated break dates (time values)

e(breakobs) m x 1 vector of break positions (observation index)

e(b_regime), e(se_regime) (m+1) x k regime mean-group slopes

e(bp_regime), e(sep_regime) (m+1) x k regime pooled slopes

e(b_i) (k(m+1)) x N matrix of per-panel regime slopes

e(se_i) (k(m+1)) x N matrix of per-panel Newey-West s.e. (Prop. 1)

Remarks and interpretation

Reading the output. The header reports N, T, the break specification
(model 4 vs 5), the regressor case (I(0) vs I(1)), and the factor proxy. Next
come the estimated break dates (in time units, e.g. calendar years) and the
minimized SSR. The main block gives, for each of the m+1 regimes, the
mean-group slope of every regressor with its cross-panel standard error, z and
p-value, and significance stars.

What each estimator is for.

o Mean-group (shown): the average of the N per-panel slopes in each
regime, with a standard error from their dispersion (BFW Prop. 2). This is the
headline estimator for the population slope in each regime.

o Pooled (e(bp_regime)): a precision-weighted average (BFW
footnote 13); more efficient when the slopes are homogeneous.

o Individual (e(b_i)/e(se_i)): each panel's own regime
slopes with Newey-West HAC standard errors (BFW Prop. 1). Use these when a single
unit is of interest.

Choosing m. nbreaks() is the total number of breaks. The command does
not test how many breaks exist; select m on substantive grounds, an
information criterion, or an external test (e.g. Bai-Perron sup-F, or the common-
break CUSUM test of Jiang and Kurozumi 2023). Over-stating m inflates the
per-regime parameter count and the minimum regime length required.

model 4 vs model 5. The break dates are identical either way (both use
the unrestricted fully-interacted DP). Choose the slope estimator by whether
you believe the error-factor loadings are stable (model 4, default, more
efficient) or may themselves shift (model 5, loadings). When only the
slopes truly break, model 4 is the correctly specified and tighter estimator.

Consistency. Break dates are consistently estimated as (N,T) grow, and the
probability of picking the true dates rises sharply with N (BFW Theorems 1-2).
Nonstationary regressors make breaks easier to date; I(1) idiosyncratic
errors (spurious regression) make them harder.

Examples

Setup

. webuse grunfeld, clear

. xtset company year

One break in the slopes; inspect the estimated date

. xtkpybreak break invest mvalue kstock, nbreaks(1)

. matrix list e(breakdates)

Same, with the two journal-style graphs

. xtkpybreak break invest mvalue kstock, nbreaks(1) breakplot coefevolution

Did the mvalue slope change across the break?

. test [r1]mvalue = [r2]mvalue

Two breaks, allowing the loadings to break too, with 15% trimming

. xtkpybreak break invest mvalue kstock, nbreaks(2) loadings trim(0.15)

Individual-panel slopes with Newey-West s.e. (window 2)

. xtkpybreak break invest mvalue kstock, nbreaks(1) hac(2)

. matrix list e(b_i)

. matrix list e(se_i)

Strict BFW eq. (9) proxy (no intercept); (y-bar, x-bar) proxy

. xtkpybreak break invest mvalue kstock, nbreaks(1) noconstant

. xtkpybreak break invest mvalue kstock, nbreaks(1) proxy(yx)

Case 2 (I(1) regressors, T-consistent slopes) labelling

. xtkpybreak break invest mvalue kstock, nbreaks(1) nonstationary

Author

Dr Merwan Roudane

merwanroudane920@gmail.com

github.com/merwanroudane