*! version 0.5.2 18apr2026
help xtdpthresh

Title

xtdpthresh -- Dynamic Panel Threshold Model with Endogeneity,
supporting Unbalanced Panels via Forward Orthogonal Deviations, and Grid
Bootstrap Inference (Gong-Seo 2026)

Syntax

xtdpthresh depvar [indepvars] [if] [in]
, qx(varname) [options]

where:

depvar — dependent variable y

indepvars — exogenous regressors (enter β and δ parts of the model)

qx(varname) — threshold variable (REQUIRED; self-documenting style following xthreg2)

Model specification
qx(varname) threshold variable (REQUIRED)

endogenous(varlist) endogenous regressors; lagged levels used as IV

exogenous(varlist) extra exogenous regressors (same treatment as indepvars)

iv(varlist[, sub-opts]) additional user-supplied instruments.
Concise xtabond2-style sub-options allowed: iv(varlist, maxlag(# [#]) collapse).
Sub-options override the top-level maxlag()/collapse when both are given.

kink enforce continuity (kink) restriction

static static model; do NOT auto-add L.depvar as regressor

td purge common time shocks by within-time demeaning of y and regressors

collapse collapse block-diagonal instruments across time (Roodman 2009); drastically reduces #instruments when T is large

maxlag(# [#]) restrict lag depth for instruments in the TRANSFORMED equation; maxlag(L) caps at lag L; maxlag(a b) uses lags a through b

levmaxlag(# [#]) lag range for level-equation IVs in method(system); default (1 1) (Blundell-Bond convention); levmaxlag(1 2) uses Δy_ and Δy_

Transformation and estimation
method(fd|fod|system) panel transformation; default is fd

grid(#) # grid points for γ search; default 30

trim(#) trim rate for γ grid (xthenreg convention); default 0.10

Inference (Grid Bootstrap, Gong-Seo 2026)
citype(grid|none) CI type for threshold; default grid.
Asymptotic CI not provided — the threshold estimator has a non-standard
limiting distribution (n^(1/4)-rate under continuity; Gong-Seo 2026 show
asymptotic CIs are invalid in that case). Use grid bootstrap instead.

gridci(#) # grid points for CI construction; default 25

boot(#) bootstrap replications; default 299

nosearch skip grid bootstrap (point estimate only)

Reporting
level(#) confidence level; default 95

verbose print per-γ bootstrap progress (25+ lines); default is a compact one-dot-per-γ progress bar

Use xtset before running xtdpthresh.

Description

xtdpthresh estimates the dynamic panel threshold model of
Seo and Shin (2016), extended to unbalanced panels via Forward Orthogonal
Deviations (Arellano-Bover 1995) and System GMM (Blundell-Bond 1998).
Inference for the threshold location uses the grid bootstrap of
Gong and Seo (2026), which is uniformly valid regardless of whether the
threshold model is continuous (kink) or discontinuous (jump).

The estimated dynamic model is:

y_it = β1·y_ + x_it'β2 + (1, y_, x_it')δ · 1(q_it > γ) + η_i + ε_it

where x_it stacks the regressors listed in indepvars plus any
variables specified via endogenous() / exogenous(). The lagged
dependent variable y_ is appended automatically (the command is
dynamic by default; see static to disable). The coefficient vector δ
contains both the intercept jump (δ_1) and the regime-specific slope changes
for y_ and each element of x_it. In the static case
(static), the term β1·y_ drops out of both the β and δ
blocks.

When the true model is continuous (satisfies δ_1 + δ_p·γ = 0 and δ_2:p-1 = 0),
the GMM threshold estimator converges at n^(1/4)-rate with a non-normal
distribution; the standard nonparametric bootstrap is inconsistent. The grid
bootstrap in xtdpthresh imposes the null at each candidate γ and is
valid regardless of continuity.

Syntax conventions relative to xthenreg

xtdpthresh is designed to feel familiar to users of xthenreg
(Kim-Kim-Seo 2019) while extending it along several dimensions. Key
differences:

* Positional arguments are depvar [indepvars]. The threshold
variable is passed via the REQUIRED option qx(varname),
not as a positional argument. This follows the self-documenting
convention of xthreg2 (Wang-Lian 2019).

* Added: method() for FD/FOD/System choice. method(fd)
is the default and reproduces xthenreg; method(fod) enables
unbalanced panel support; method(system) adds Blundell-Bond level
moments.

* Added: iv(varlist[, sub-opts]) for external
instruments, with xtabond2-style sub-options maxlag() and
collapse that override the top-level settings. Functionally
similar to xthenreg's inst() but with finer control.

* Added: collapse, maxlag(), levmaxlag() for
xtabond2-style instrument count management — essential when T is
moderate and the Hansen J diagnostic would otherwise be unreliable.

* Added: citype(), gridci(), boot(), nosearch
for grid bootstrap threshold CI (not in xthenreg).

* Added: td to purge common time shocks by within-time
demeaning.

* Added: exogenous() for explicit extra exogenous vars. In
practice, putting these in indepvars achieves the same effect.

Options

Model specification

endogenous(varlist) specifies endogenous regressors. These are
appended to the regressor matrix (in addition to indepvars), and the
command automatically uses their lagged levels as instruments. endogenous()
variables must NOT appear in indepvars.

exogenous(varlist) specifies additional exogenous regressors. These
are treated identically to indepvars and included in Δx as IV. This
option is redundant with indepvars but provided for explicitness.

Default instrument structure (iv() is OPTIONAL). When iv() is
NOT specified, the command still builds a valid instrument matrix Z
automatically, per Arellano-Bond convention. Per time block t, Z contains:

(i) a constant column;

(ii) lags of the dependent variable y_, y_, ... (dynamic models);

(iii) for each exogenous regressor (listed in indepvars or
exogenous()): the contemporaneous Δx_t or x_t itself — exog vars
instrument themselves under E[x · ε]=0;

(iv) for each variable in endogenous(): its own lags x_,
x_, ... as Arellano-Bond moment conditions.

So a minimal call like xtdpthresh y x1 x2, qx(q) already uses
x1, x2, and the lagged y as instruments — no need to specify iv().

iv(varlist[, sub-opts]) specifies additional user-supplied
instruments that enter Z without being added as regressors. Useful when
an external IV exists (e.g., industry-level average that moves with
a firm endogenous variable). Each iv variable contributes one extra
column per time block. Under method(system), user IVs are added to
BOTH transformed- and level-equation moment blocks — valid when the user
IV is exogenous in levels. User is responsible for supplying only IVs
satisfying E[z · ε] = 0 in levels.
Sub-options maxlag(# [#]) and collapse inside iv()
override the corresponding top-level options (xtabond2-style).

kink requests the continuity-restricted (kink) model of Seo-Shin
(2016). Under this restriction, the model is continuous at γ:
δ_2 = 0_

and δ_1 + δ_3·γ = 0. The threshold variable's slope changes
at γ, but no jump occurs. The coefficient vector has p+2 elements
(β_1, ..., β_p, kink_slope) instead of 2p+2 in the unrestricted (jump)
model.

static specifies a static model. The default is dynamic, which
automatically includes L.depvar as a regressor. With static,
L.depvar is not auto-added; users must include any lag explicitly
in indepvars.

td purges common time shocks by subtracting the cross-sectional
mean at each time period from depvar, indepvars, and variables
listed in endogenous(), exogenous(), and iv(). The
threshold variable q is left untouched so γ retains its original
scale and interpretation. Demeaning is applied after internal preserve,
so user data is not modified permanently. This is the standard panel
econometrics approach to controlling for aggregate time effects (e.g.,
macroeconomic shocks); it is equivalent to including year dummies whose
coefficients are restricted to be equal across regimes.

collapse collapses block-diagonal instruments across time periods
(Roodman 2009). By default, each moment (lag of y, Δx, endog lag, user
inst) gets a separate column per time block, causing the instrument
count to grow quadratically with T. With collapse, instruments
are stacked into a single shared column per lag depth, reducing the
total count by a factor of (T−2). Use this for long panels (T ≥ 10) to
mitigate instrument proliferation and produce reliable Hansen J tests.
Downside: weaker identification at each γ due to fewer moments.

maxlag(# [#]) restricts which lags are used as instruments,
analogous to xtabond2's lag() suboption.

maxlag(L) caps instrument lag depth at L (uses lags 1 through L
for endogenous variables; lags 2 through L+1 for the auto-added L.y).

maxlag(a b) uses lags a through b inclusive. For example,
maxlag(2 4) uses lags 2, 3, 4. Useful when short lags are
"too recent" to be valid IVs (possibly still correlated with ε).

Combine with collapse for aggressive instrument reduction:
maxlag(2 4) collapse yields few moments and reliable Hansen J
at the cost of identification strength. Monitor e(N_iv) to
ensure the model remains identified (N_iv ≥ # regressors).

levmaxlag(# [#]) controls lag depth for LEVEL-equation instruments
under method(system). Default is levmaxlag(1) = single
lag (Blundell-Bond 1998 convention): Δy_ as IV for y_,
Δx_t for exog x, Δx_ for endog x. Specify levmaxlag(1 2)
to add Δy_ and corresponding second-lag differences for exog/endog.
Multiple level lags can improve efficiency under stationarity but are
typically redundant with transformed-equation moments. Use cautiously.

Transformation and estimation

method(fd|fod|system) selects the panel transformation used for
moment conditions:

fd — first-difference (Arellano-Bond 1991). Requires strongly
balanced panel or near-balanced (gaps drop obs). Matches xthenreg
results.

fod — forward orthogonal deviations (Arellano-Bover 1995).
Recommended for unbalanced panels. Transforms each observation as a
weighted difference from the mean of future observations; preserves
observations whenever at least one future value exists.

system — system GMM (Blundell-Bond 1998). Stacks FOD equations
with level equations using Δ-lag instruments.

grid(#) sets the number of grid points for the γ search. Default 30.
For Monte Carlo or final estimation, use a denser grid (50-100).

trim(#) sets the trimming rate for the γ grid, using xthenreg's
convention: trim(0.2) means grid spans the 10th to 90th percentile
of q_var. Must be in [0.01, 0.45]. Default 0.10.

Inference

citype(grid|none) chooses CI construction method for the threshold.

grid — grid bootstrap CI via test inversion (Gong-Seo 2026 Algorithm 1),
uniformly valid regardless of model continuity. Default.

none — skip threshold CI; report point estimate and coefficient SE
only.

Asymptotic CI is NOT provided as an option. Under the continuous (kink)
model, γ̂ is n^(1/4)-consistent with a non-normal limit distribution
(Theorem 2 of Gong-Seo 2026), making standard asymptotic intervals
invalid. The grid bootstrap is uniformly valid across continuous and
discontinuous cases.

gridci(#) sets grid points for CI construction. Finer grid gives
more precise CI but slower runtime. Default 25.

boot(#) sets bootstrap replications. Minimum 10 (enforced for debugging
only; a warning is issued if # < 99). For valid 5% inference follow
Davidson and MacKinnon (2000, Econometric Reviews): 99+ is the minimum,
299-499 is recommended for production, 99-199 for exploratory runs.
Default 299.

nosearch skips the grid bootstrap CI entirely. Equivalent to
citype(none).

Reporting

level(#) sets the confidence level. Default 95.

verbose prints per-γ progress during the grid bootstrap (one line
per γ point, 25+ lines of output). Useful for monitoring long-running
bootstraps on large panels or for debugging convergence. Without
verbose, the command prints a compact one-dot-per-γ progress bar.

Examples

Firm investment model with debt threshold, all regressors exogenous:

. xtset firm year

. xtdpthresh invest tobin_q cashflow, qx(debt) method(fd)

Same but with cashflow as endogenous (auto-lag instruments):

. xtdpthresh invest tobin_q, qx(debt)

endogenous(cashflow) method(fd)

Unbalanced banking panel, FOD transformation, with user-supplied IV:

. xtdpthresh roa gdp_growth credit_growth, qx(car)

endogenous(L.roa) iv(industry_avg_roa) method(fod)

Concise xtabond2-style: lag range and collapse set inside iv():

. xtdpthresh invest tobin_q cashflow, qx(debt)

iv(L2_tobin, maxlag(2 4) collapse) method(fd)

Point estimate only (skip bootstrap, useful for quick checks):

. xtdpthresh invest tobin_q cashflow, qx(debt)

method(fd) nosearch

Full grid bootstrap with fine settings:

. xtdpthresh invest tobin_q cashflow, qx(debt)

method(fd) grid(50) gridci(40) boot(499) trim(0.10)

System GMM with dense instruments:

. xtdpthresh y x1 x2, qx(q)

endogenous(L.y) method(system) grid(40)

Kink (continuity-restricted) model; continuity test compares kink vs
jump:

. xtdpthresh invest tobin_q cashflow, qx(debt) method(fd) kink

. xtdpthresh invest tobin_q cashflow, qx(debt) method(fd)

. display "Continuity test p-value: " e(pval_cont)

The second call (unrestricted) reports e(pval_cont); if less than
0.05, the jump model is preferred; otherwise kink is not rejected.

Stored results

Scalars

e(N) number of observations used in GMM (= N_trans + N_level)

e(N_raw) raw sample size (rows after touse, before transformation)

e(N_trans) transformed rows (FD or FOD equations)

e(N_level) level equation rows (nonzero only for method(system))

e(N_iv) number of instruments (columns of Z after dropping zero cols)

e(N_units) number of panel units used

e(hansen) Hansen J over-identification statistic

e(hansen_df) Hansen J degrees of freedom (N_iv − #params)

e(hansen_p) Hansen J p-value (H_0: moments valid)

e(ar1) Arellano-Bond AR(1) m-statistic

e(ar1_p) AR(1) p-value (typically rejects for FD due to MA(1))

e(ar2) Arellano-Bond AR(2) m-statistic

e(ar2_p) AR(2) p-value (should NOT reject if moments valid)

e(gamma) threshold point estimate γ̂

e(gamma_lo) grid bootstrap CI lower bound

e(gamma_hi) grid bootstrap CI upper bound

e(pval_lin) linearity test p-value (Seo-Shin 2016 style)

e(pval_cont) continuity test p-value (Gong-Seo 2026, Section 4.3 and Theorem 7); missing when kink is set

e(obj) GMM objective at γ̂

e(k_exog) # exogenous regressors

e(k_endog) # endogenous regressors

e(k_inst) # user-supplied instruments

e(flag_kink) 1 if kink option specified

e(flag_static) 1 if static option specified

e(flag_td) 1 if td option specified

e(balanced) 1 if panel is strongly balanced

Macros

e(cmd) xtdpthresh

e(depvar) name of dependent variable

e(q_var) name of threshold variable

e(indepvars) names of exogenous regressors

e(endog) names of endogenous regressors

e(exog_extra) names of extra exogenous regressors (from exogenous())

e(inst) names of user-supplied instruments

e(method) transformation method used

e(panelvar) panel variable name

e(timevar) time variable name

Matrices

e(b) coefficient vector (β, δ)

e(V) variance-covariance matrix

Coefficient labels

The coefficient vector e(b) is labeled following xthenreg
convention.

Unrestricted (jump) model — 2K+1 coefficients:

Lag_y_b coefficient on L.depvar in β (if dynamic)

<var>_b coefficient on var in β (β part)

cons_d intercept jump δ_1

Lag_y_d coefficient on L.depvar in δ (if dynamic)

<var>_d coefficient on var in δ (δ part)

Kink (continuity-restricted) model — K+1 coefficients:

Lag_y_b coefficient on L.depvar (if dynamic)

<var>_b coefficient on var

kink_slope change in slope of threshold variable at γ (δ_3)

Specification tests (reported automatically)

xtdpthresh reports three standard dynamic panel GMM specification
tests after every estimation:

Hansen J over-identification test: H_0 = moment conditions are
valid. Statistic e(hansen) = n·ḡ'Ω̂⁻¹ḡ at θ̂ ~ χ²(df), where
df = N_iv − #params. Reject → moment misspecification. Caveat: under
instrument proliferation the test over-rejects (Roodman 2009). Apply
collapse or maxlag() and monitor whether rejection persists.

Arellano-Bond AR(1) test: H_0 = no first-order autocorrelation
in the transformed residuals. Statistic e(ar1) follows N(0,1)
asymptotically. For FD, AR(1) is expected to REJECT (by construction,
Δε has MA(1) structure); for FOD, both directions are possible.

Arellano-Bond AR(2) test: H_0 = no second-order autocorrelation.
e(ar2). Should NOT reject at conventional levels. Rejection
signals that moment conditions are invalid (ε_ correlated with ε_t),
and the GMM estimator is inconsistent.

Hypothesis tests (bootstrap-based, require citype(grid))

xtdpthresh reports three specification tests when grid bootstrap
inference is enabled (default, citype(grid)):

Threshold CI (Gong-Seo 2026 §4.1): 100(1-α)% confidence interval
for γ constructed by test inversion. For each γ_ℓ in a grid, the null
γ = γ_ℓ is tested via the GMM distance statistic D_n(γ_ℓ); γ_ℓ is
accepted if D_n(γ_ℓ) ≤ (1-α)-quantile of bootstrap distribution D*_n.
The CI is the convex hull of accepted γ_ℓ. Uniformly valid regardless
of whether the model is continuous or discontinuous. Stored in
e(gamma_lo), e(gamma_hi).

Linearity test (Seo-Shin 2016): tests H0: δ = 0 (no threshold
effect). Sup-Wald statistic with wild bootstrap under H0. Unit-level
Mammen weights. Low p-value rejects linearity → threshold effect is
significant. Stored in e(pval_lin).

Continuity test (Gong-Seo 2026, Section 4.3 and Theorem 7): tests H0: model is
continuous (kink) vs H1: discontinuous (jump). Test statistic
T_n = n·(Q̂_kink(θ̃) - Q̂_jump(θ̂)). Bootstrap p-value under kink DGP.
Low p-value rejects continuity → use the unrestricted (jump) model.
High p-value (> 0.10) supports the kink specification. Stored in
e(pval_cont). Only computed when kink is NOT set (the test
compares unrestricted vs kink; it makes no sense under kink estimation).

Notes and known limitations

* Sample size: the framework requires large n for reliable
inference. Gong-Seo (2026) Table 1 simulations use n ∈ {400, 800, 1600}.
With n < 100, both point estimation and CI show substantial finite-sample
variance (we verified this on invest.dta subsets: at n=50, both
xtdpthresh and xthenreg produce unstable γ̂ across different
50-firm subsets).

* FD vs FOD: on balanced data, FD gives the same point estimate
as xthenreg. FOD identifies a potentially different threshold
because the moment structure differs; FOD's advantage is robustness to
unbalanced patterns (late entry, early exit, random missing).

* Grid bootstrap runtime: scales roughly as
gridci × boot × grid × n. With the per-γ cache and the fixed
first-stage weight (Gong-Seo 2026 Algorithm 1), each bootstrap
replication is a single matrix-vector product. With default settings
grid(30) gridci(25) boot(299), expect 3-10 minutes per call
for n = 500 (System GMM is slowest, FD fastest). For exploratory work
use grid(15) gridci(10) boot(99) or nosearch; for published
results use the defaults.

* Linearity test: the p-value from e(pval_lin) uses a
wild bootstrap implementation of the sup-Wald test of Seo and Shin
(2016). Both xtdpthresh and xthenreg use bootstrap-based
critical values; finite-sample power is comparable when bootstrap reps
are set equal.

* Continuity test interpretation: reject H0 (continuous) at
5% → evidence for jump model with discontinuous threshold. Fail to
reject → either model is truly continuous, OR sample is underpowered.
The test is based on Gong-Seo (2026, Section 4.3 and Theorem 7) and uses bootstrap under
the kink DGP; critical values depend on a non-standard limiting
distribution V_1 - V_2 + V_3.

References

Arellano, M., and O. Bover. 1995. Another look at the instrumental
variable estimation of error-components models. Journal of
Econometrics 68: 29-51.

Arellano, M., and S. Bond. 1991. Some tests of specification for panel
data: Monte Carlo evidence and an application to employment equations.
Review of Economic Studies 58: 277-297.

Blundell, R., and S. Bond. 1998. Initial conditions and moment
restrictions in dynamic panel data models. Journal of Econometrics
87: 115-143.

Gong, W., and M. H. Seo. 2026. Bootstraps for dynamic panel threshold
models. Journal of Econometrics 253: 106153.

Hansen, B. E. 1999. The grid bootstrap and the autoregressive model.
Review of Economics and Statistics 81: 594-607.

Kim, S., Y. J. Kim, and M. H. Seo. 2019. Estimation of dynamic panel
threshold model using Stata. Stata Journal 19: 685-697.

Seo, M. H., and Y. Shin. 2016. Dynamic panels with threshold effect and
endogeneity. Journal of Econometrics 195: 169-186.

Authors

Duy Chinh Nguyen

School of Business, International University, Ho Chi Minh City, Vietnam

Vietnam National University Ho Chi Minh City, Vietnam

Email: ndchinh@hcmiu.edu.vn

ORCID: 0000-0002-9157-9358

Nhat Duy Lai (corresponding author)

Faculty of Finance and Accounting, Saigon University,

273 An Duong Vuong St, Cho Quan Ward, Ho Chi Minh City, Vietnam

Email: lnduy@sgu.edu.vn

ORCID: 0009-0008-5365-2893

Also see

Online: xtset, xthenreg (Kim-Kim-Seo 2019), xtabond,
xtabond2 (Roodman 2009)