Research#

Pair discovery and cointegration screening.

PairFinder#

class spreadpy.research.pairFinder.PairFinder(series: list[PriceTimeSeries], significance: float = 0.05, npd_threshold: float | None = 0.3, log_prices: bool = False)[source]#

Scan a universe of assets and rank candidate cointegrated pairs.

For each pair (s₁, s₂) the following sequential pipeline is applied:

  1. NPD pre-filter — normalised price distance. Skips pairs whose rebased price paths diverge too much, avoiding expensive statistical tests on clearly non-cointegrated pairs.

  2. Engle-Granger cointegration test — bivariate OLS + ADF on the OLS residuals. Reports the EG p-value.

  3. ADF on OLS residuals — direct stationarity test on the spread.

  4. Half-life — mean-reversion speed via AR(1) on the spread.

  5. Hurst exponent — degree of mean-reversion from the log-variance method.

Only pairs passing both the EG and ADF significance thresholds are returned.

Parameters:
  • series (list[PriceTimeSeries]) – Universe of price series to scan.

  • significance (float) – p-value threshold applied to both the EG and ADF tests (default 0.05).

  • npd_threshold (float) – Maximum normalised price distance to pass the pre-filter. Set to None to disable the pre-filter.

  • log_prices (bool) – If True, apply log-transform to all series before running any test. Recommended when prices span very different scales or when using the Kalman filter downstream.

scan() DataFrame[source]#

Scan all pairs in the universe and return a ranked DataFrame.

Iterates over all C(n, 2) pairs, applies the NPD pre-filter, runs the Engle-Granger and ADF tests, and retains only pairs that pass both significance thresholds. Results are sorted by EG p-value ascending (strongest cointegration first).

Returns:

DataFrame with one row per qualifying pair, columns: x, y, npd, eg_stat, eg_pvalue, adf_stat, adf_pvalue, adf_crit_1%, adf_crit_5%, adf_crit_10%, half_life, hurst, hedge_ratio. Returns an empty DataFrame (with the same columns) if no pair passes both thresholds.

Return type:

pd.DataFrame