Skip to main content

xtbreak

Structural break detection and estimation for time series and panel data in Python.

"Did the relationship change? When? By how much?" — The three questions every applied researcher faces when parameters might not be constant.


Why Structural Breaks Matter

Economic and financial time series rarely stay stable forever. Policy shifts, crises, and regime changes cause the data-generating process to break: coefficients jump, variances shift, trends bend. Ignoring these breaks means your regressions are misspecified, your confidence intervals are wrong, and policy conclusions drawn from pooled samples are unreliable.

Structural break methods ask: did something change, when, and by how much? The Bai–Perron (1998, 2003) framework answers these questions with formal test statistics, break-date estimation via global SSR minimization, and asymptotic confidence intervals for each break location.

Despite two decades of theoretical maturity, Python had no dedicated implementation that returns break dates, confidence intervals, regime coefficients, test statistics, and selection decisions as programmatic objects. xtbreak fills that gap.

What xtbreak Does

  • Test for structural breaks — SupF, UDmax, and sequential tests with known or unknown break counts
  • Estimate break dates — global SSR minimization via the Bai–Perron dynamic programming algorithm
  • Confidence intervals — asymptotic CIs for each estimated break location
  • Break number selection — sequential testing and information criteria (BIC/LWZ)
  • Regime statistics — per-regime coefficients, standard errors, and sample sizes in structured result objects
  • Panel data support — partial structural breaks with cross-sectional dependence factors
  • Serializable results — every result object is JSON-safe for logging, storage, and pipeline integration
  • Pure Python + NumPy — no compiled extensions, no Stata dependency, installs anywhere Python runs

Installation

pip install git+https://github.com/gorgeousfish/pyxtbreak.git#subdirectory=xtbreak-py

Optional dependencies for full functionality:

pip install scipy    # p-values for Chow tests
pip install pandas   # DataFrame input support

Quick Example

Detect and estimate a single mean shift in a simulated series:

import numpy as np
from xtbreak import test, estimate

# Simulate: mean jumps from 0 to 3 at observation 50
np.random.seed(2024)
y = np.concatenate([np.random.normal(0, 1, 50), np.random.normal(3, 1, 50)])
x = np.ones((100, 1))

# Test for one structural break
result = test(y, x, breaks=1, trimming=0.15, vce='ssr')
print(f"SupF statistic: {result.statistic:.2f}")
# SupF statistic: 232.47

# Estimate the break location
est = estimate(y, x, breaks=1, trimming=0.15)
brk = est.break_estimates[0]
print(f"Estimated break at index: {brk.index}")
# Estimated break at index: 50

print(f"95% confidence interval: {brk.ci_index}")
# 95% confidence interval: (48, 52)

# Inspect regime-specific parameters
for rs in est.regime_statistics:
    print(f"Regime {rs.regime_index}: coef={rs.coefficients[0]:.4f}  "
          f"se={rs.standard_errors[0]:.4f}  n={rs.n_observations}")
# Regime 0: coef=-0.0002  se=0.1369  n=50
# Regime 1: coef=3.0600  se=0.1468  n=50

The estimated break at index 50 exactly recovers the true change point. The confidence interval is tight (48–52), and regime coefficients cleanly separate the two means.

What You Get Back

Every call returns a structured result object, not a print dump. You can:

# Access break dates programmatically
est.break_estimates[0].index       # 50
est.break_estimates[0].ci_index    # (48, 52)

# Iterate over regimes
for rs in est.regime_statistics:
    rs.coefficients   # np.ndarray
    rs.standard_errors
    rs.n_observations

# Serialize for reports
import json
json.dumps(est.to_dict())  # JSON-safe dict

No screen-scraping. No regex on printed output. Just Python objects.

When to Use xtbreak

Situation xtbreak fits? Notes
Testing whether a regression relationship changed at unknown dates Yes Core use case — SupF and UDmax tests
Estimating when structural breaks occurred Yes Global SSR minimization with CIs
Choosing how many breaks best describe the data Yes Sequential tests + BIC/LWZ selection
Panel data with common break dates Yes Partial break model with factor CSD
Cointegration or unit-root break testing No Use dedicated cointegration packages
Real-time online change-point detection No Designed for retrospective full-sample analysis
Markov-switching or threshold models No Different modeling framework

API Overview

Function Purpose Returns
test() Test null of no breaks against alternative of k breaks TestResult with statistic, critical values
estimate() Estimate break locations and regime parameters EstimateResult with breaks, CIs, regime stats
select() Determine number of breaks via sequential/information criteria SelectResult with selected count, step details

All three functions accept NumPy arrays directly. Panel structure is specified via entity and time parameters.

For complete API documentation, see docs/api-reference.md.
For extended usage patterns (selection, robust VCE, panel, serialization), see docs/quickstart.md.
For runnable example scripts, see examples/.

Current Boundaries

  • Retrospective analysis only — requires the full sample; not designed for streaming/online detection
  • Linear models — breaks in linear regression coefficients; nonlinear models are out of scope
  • No unit-root/cointegration break tests — focuses on Bai–Perron structural change in stationary or trend-stationary settings
  • Trimming constraint — minimum regime length is controlled by the trimming parameter (default 15%); very short regimes near endpoints cannot be detected
  • scipy optional — without scipy, Chow test p-values are unavailable (test statistics still computed)

Methodology

This package implements the econometric framework from:

  • Bai, J., & Perron, P. (1998). Estimating and testing linear models with multiple structural changes. Econometrica, 47–78.
  • Bai, J., & Perron, P. (2003). Computation and analysis of multiple structural change models. Journal of Applied Econometrics, 18(1), 1–22.
  • Ditzen, J., Karavias, Y., & Westerlund, J. (2025). Testing and estimating structural breaks in time series and panel data in Stata. The Stata Journal, 25(3), 526–560.
  • Ditzen, J., Karavias, Y., & Westerlund, J. (2022). Multiple structural breaks in interactive effects panel data and the impact of quantitative easing on bank lending. arXiv preprint arXiv:2211.06707.

Citation

@software{xtbreak_python2026,
  title   = {xtbreak: Structural Break Detection and Estimation in Python},
  author  = {Cai, Xuanyu and Xu, Wenli},
  year    = {2026},
  version = {0.1.0},
  url     = {https://github.com/gorgeousfish/xtbreak-py}
}

@article{ditzen2025xtbreak,
  title   = {Testing and estimating structural breaks in time series and panel data in {Stata}},
  author  = {Ditzen, Jan and Karavias, Yiannis and Westerlund, Joakim},
  journal = {The Stata Journal},
  volume  = {25},
  number  = {3},
  pages   = {526--560},
  year    = {2025}
}

Authors

Python Implementation:

Methodology:

  • Jan Ditzen, Free University of Bozen-Bolzano
  • Yiannis Karavias, University of Birmingham
  • Joakim Westerlund, Lund University

License

AGPL-3.0

Metadata

Release files for xtbreak 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for xtbreak 0.1.1
File Size Uploaded
xtbreak-0.1.1.tar.gz 95.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for xtbreak 0.1.1
File Interpreter ABI Platform
xtbreak-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 196.2 kB

Release files / xtbreak-0.1.1.tar.gz

Download URL xtbreak-0.1.1.tar.gz
Size 95.2 kB
Tags Source
SHA-256 checksum
How to use checksums
a7b347135a565eef1b24e7e339be1ab70e77b301d41fbe6a9c33395c7c247db6
BLAKE2b-256 checksum
How to use checksums
82a94c16693373f55afde387c8145e68ff6bf92911d97a78d2b1529a92753601
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.6

Release files / xtbreak-0.1.1-py3-none-any.whl

Download URL xtbreak-0.1.1-py3-none-any.whl
Size 101.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b175ec81cd795bfee8fd285cd057d1d5f6aed2d05825784eff66acba10cadf23
BLAKE2b-256 checksum
How to use checksums
7181ff92705d404220b3cf065da0b5f8825aab79d241d3a0cd66d5af523f6d4b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.6

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page