Skip to content

factrix.stats

Statistical tooling shared across the library.

The slice-test selection classes carry pure identity semantics (name / description, no compute); their numerics live in the slice-test dispatch path and the factrix._stats kernels. Series-mean HAC inference lives in factrix.inference. InferenceResult — harmonized return shape (canonical home is factrix.inference; re-exported here). WaldNWCluster / WaldTwoWayCluster — cluster-robust Wald χ² selection-only instances for slice contrasts. DriscollKraayDriscoll-Kraay (1998) cross-section-robust HAC SE for pooled-panel slopes; selection-only identity handle, numerics consumed by pooled_beta. BlockBootstrap — block-bootstrap empirical-p selection-only instance for paired-diff slice tests. multiple_testing — BHY false-discovery plus Holm and Romano-Wolf family-wise error-rate adjustments across a declared search family. bootstrap — stationary-bootstrap resampling + CI for dependent series.

BlockBootstrap

BlockBootstrap(block_length: int | Literal['auto'] = 'auto', n_resamples: int = 999, scheme: Literal['fixed', 'stationary'] = 'stationary', rng_seed: int | None = None)

Block-bootstrap empirical p-value Estimator for paired-diff slice tests.

Resamples a paired-difference series under H₀: E[diff] = 0 using one of two dependent-bootstrap schemes:

  • "stationary" (Politis-Romano (1994)) — geometric block lengths with mean L; each resample is itself a stationary process. Default; preferred when downstream stats (CI, Sharpe) rely on stationarity.
  • "fixed" (Künsch (1989)) — deterministic block length L; cleaner for variance estimation; loses stationarity at block joins but tighter at small B.

Block length resolves automatically from the input series via Politis-White (2004) when block_length="auto"; pass an integer to fix it.

Applicability is restricted to (INDIVIDUAL, DENSE) — consistent with the slice-test functions that produce paired per-date diffs (slice information coefficient (IC), slice FM-λ, …).

Constructor parameters are stored on the instance and read by the slice-test function procedure when it calls factrix._stats.bootstrap._block_bootstrap_diff_p. Two BlockBootstrap instances with different scheme / block length are distinct Estimators from the function's perspective; scheme and block length live in the result metadata.

DriscollKraay

Driscoll & Kraay (1998) cross-section-robust heteroskedasticity-and-autocorrelation-consistent (HAC) SE for a pooled-panel slope.

Aggregates the per-observation OLS scores cross-sectionally within each period, then runs a Bartlett-kernel HAC on the resulting time series of cross-sectional sums and sandwiches with (X'X)⁻¹. The result is robust to arbitrary contemporaneous cross-sectional correlation — the gap a one-way cluster-on-date SE leaves open, which understates SE for small, cross-sectionally correlated panels (Petersen (2009)). Numerics live in factrix._stats.hac._driscoll_kraay_cov; pooled_beta drives them directly.

Pass an instance to a function to make the inference choice explicit. Constructor takes no arguments in this release; the Bartlett bandwidth is resolved automatically (Newey-West (1994) auto_bartlett on the period count) and an explicit-lag override lives on the pooled_beta call rather than on the instance.

InferenceResult dataclass

InferenceResult(stat: float, p_value: float, metadata: Mapping[str, Any], warnings: frozenset[WarningCode])

Harmonized return shape for an Inference.compute call.

stat / p_value are the test statistic and two-sided p-value; they feed a MetricResult directly. metadata is a flat str -> Any map (non-overlapping emits stride / sample counts; Newey-West emits nw_lags). warnings carries soft-floor / kernel-clamp signals.

WaldNWCluster

Cluster-robust Wald χ² with Newey-West (NW) Bartlett heteroskedasticity-and-autocorrelation-consistent (HAC) + 1-way slice cluster.

Backs the slice test on a per-date metric panel: K parallel per-slice metric series (information coefficient (IC), FM λ, etc.) are stacked and a Wald contrast tests the equality of slice means under joint NW HAC of the K-vector. Numerics live in factrix._stats.wald._wald_nw_cluster_means.

Applicability is restricted to (INDIVIDUAL, DENSE) — the PANEL inference cells whose per-date scalars feed the stacked panel. COMMON cells produce one number per date by definition of the scope and have no within-cell cross-section to slice over.

This is the sole analytic estimator the slice tests run; it is applied internally (the slice-test functions take no estimator argument). The class names that inference path for documentation and introspection.

Constructor takes no arguments in this release; the Bartlett-kernel bandwidth is resolved by _wald_nw_cluster_means (auto_bartlett(T) default, floored at forward_periods - 1 by the slice tests to cover overlapping-return autocorrelation).

WaldTwoWayCluster

Two-way cluster Wald χ² on (date, asset) — Cameron-Gelbach-Miller (2011).

Backs the raw asset-date panel inference path (factor × slice interaction with full panel SE). Numerics live in factrix._stats.wald._wald_two_way_cluster.

Reserved interface; no function consumes it until factor_decomposition lands later.

bhy_adjust

bhy_adjust(p_values: ArrayLike, fdr: float = 0.05, *, n_tests: int | None = None) -> ndarray

Benjamini-Hochberg-Yekutieli (BHY) step-up rejection mask.

Parameters:

Name Type Description Default
p_values ArrayLike

1-D array of p-values in [0, 1]. Each must come from the same test family (e.g. all information coefficient (IC) p-values or all CAAR p-values). Public screening helpers enforce family consistency before calling this primitive.

required
fdr float

Target false discovery rate (FDR) (default 0.05).

0.05
n_tests int | None

Full candidate family size for two-stage screening. If caller already pre-filtered from a larger pool (e.g. 1000 candidates → 50 submitted), pass the pre-filter size here. Must be >= len(p_values). None (default) uses len(p_values), i.e. single-stage BHY.

None

Returns:

Type Description
ndarray

Boolean mask of length len(p_values) — True where the null

ndarray

is rejected. Order matches the input.

References
  • Benjamini & Yekutieli (2001). "The Control of the False Discovery Rate in Multiple Testing under Dependency." Annals of Statistics, 29(4), 1165–1188. The c(m) = Σ 1/i correction underlying this step-up rule.

bhy_adjusted_p

bhy_adjusted_p(p_values: ArrayLike, *, n_tests: int | None = None) -> ndarray

Per-hypothesis Benjamini-Hochberg-Yekutieli (BHY)-adjusted p-values (clipped at 1).

Formula: scale p_(k) by (m * c(m)) / k then cummin from the right to enforce monotonicity in ranked order. Gives a stable per-factor "how significant under false discovery rate (FDR) control" number.

n_tests follows the same contract as bhy_adjust — pass the pre-filter size when the submitted p's are survivors of a larger candidate family.

References
  • Benjamini & Yekutieli (2001). "The Control of the False Discovery Rate in Multiple Testing under Dependency." Annals of Statistics, 29(4), 1165–1188. The per-hypothesis adjusted-p mapping derived from the same step-up rule used by bhy_adjust.

bootstrap_mean_ci

bootstrap_mean_ci(values: ndarray, *, n_bootstrap: int = 1000, ci: float = 0.95, block_length: float | None = None, seed: int | None = None, statistic: Callable[[ndarray], float] | None = None) -> tuple[float, float, float]

Stationary-bootstrap confidence interval for a statistic.

Default statistic is the arithmetic mean (matches the parametric t-test's H₀ null). Pass a callable taking a 1-D array and returning a scalar to CI other statistics (e.g. Sharpe, median, skewness).

Parameters:

Name Type Description Default
values ndarray

1-D array of the original series.

required
n_bootstrap int

Resample count.

1000
ci float

Two-sided coverage, e.g. 0.95 for a 95% CI. Must be in (0, 1).

0.95
block_length float | None

See stationary_bootstrap_resamples.

None
seed int | None

Reproducibility seed.

None
statistic Callable[[ndarray], float] | None

Scalar function applied to each resample. Defaults to np.mean.

None

Returns:

Type Description
float

(ci_low, ci_high, point) where point is the statistic

float

on the original sample.

References
  • Politis & Romano (1994). "The Stationary Bootstrap." Journal of the American Statistical Association, 89(428), 1303–1313. Underlying resampling scheme; percentile CI on the bootstrap distribution of the statistic.

holm_adjusted_p

holm_adjusted_p(p_values: ArrayLike, *, n_tests: int | None = None) -> ndarray

Holm (1979) step-down FWER-adjusted p-values.

Holm controls the probability of at least one false rejection within a declared family under arbitrary dependence. It is appropriate when a search produces one selected winner or when every retained hypothesis must be protected from any false positive. Use BHY instead when the goal is to retain a batch while controlling the expected false-discovery proportion.

The submitted p-values are ordered from smallest to largest and scaled by m, m - 1, ..., m - n + 1 before a cumulative maximum enforces the step-down rejection order. m is n_tests when supplied and otherwise len(p_values).

Parameters:

Name Type Description Default
p_values ArrayLike

One-dimensional, finite p-values in [0, 1] from one search family.

required
n_tests int | None

Full number of hypotheses tried when p_values contains only the most-significant survivors of a larger search. Must be an integer >= len(p_values). Omitted hypotheses are assumed to rank after every submitted p-value; submit the complete family if that ordering is not guaranteed.

None

Returns:

Type Description
ndarray

Adjusted p-values in input order as a NumPy array, clipped to

ndarray

[0, 1].

References
  • Holm (1979). "A Simple Sequentially Rejective Multiple Test Procedure." Scandinavian Journal of Statistics, 6(2), 65-70.

romano_wolf_adjusted_p

romano_wolf_adjusted_p(statistics: ArrayLike, bootstrap_statistics: ArrayLike, *, one_sided: bool = False) -> ndarray

Romano-Wolf (2005) step-down max-t adjusted p-values.

Romano-Wolf controls the family-wise error rate while using the joint bootstrap distribution to account for dependence among hypotheses. Each bootstrap row must be one joint draw across all m hypotheses. Building columns with independent resampling would destroy that dependence and invalidate the method's power advantage over Holm.

This is an expert-level adjusted-p primitive, not a resampling workflow. The caller is responsible for generating bootstrap statistics under the joint null, centring them at the null, and using the same studentization as the observed statistics. Every hypothesis tried in the search must occupy one column; unlike holm_adjusted_p(n_tests=...), this function cannot account for omitted hypotheses without their joint bootstrap statistics. The empirical p-value grid has resolution 1 / (B + 1) because the calculation uses add-one smoothing. Bootstrap values tied with the observed statistic count as exceedances (>=), a conservative tie rule for discrete bootstrap distributions.

Parameters:

Name Type Description Default
statistics ArrayLike

Finite one-dimensional observed test statistics of length m. Large positive values favour rejection; two-sided mode uses their absolute values.

required
bootstrap_statistics ArrayLike

Finite (B, m) bootstrap test-statistic matrix. Rows are joint null draws and columns align exactly with statistics.

required
one_sided bool

True for the positive-tail alternative or False (default) for a two-sided absolute-value test.

False

Returns:

Type Description
ndarray

Adjusted p-values in input order as a NumPy array, each in [0, 1].

References
  • Romano & Wolf (2005). "Stepwise Multiple Testing as Formalized Data Snooping." Econometrica, 73(4), 1237-1282.
  • Romano & Wolf (2016). "Efficient Computation of Adjusted P-Values for Resampling-Based Stepdown Multiple Testing." Statistics & Probability Letters, 113, 38-40.

stationary_bootstrap_resamples

stationary_bootstrap_resamples(values: ndarray, n_bootstrap: int = 1000, *, block_length: float | None = None, seed: int | None = None) -> ndarray

Draw n_bootstrap stationary-bootstrap resamples of values.

Each resample has the same length T as the input. One-dimensional input returns (B, T); two-dimensional (T, m) input returns (B, T, m) and applies the same sampled row indices to every column. The latter preserves cross-hypothesis dependence for joint bootstrap procedures such as Romano-Wolf. Blocks have geometric lengths with mean block_length and sampling is circular.

Parameters:

Name Type Description Default
values ndarray

Finite (T,) time series or aligned (T, m) matrix. Matrix columns are always resampled jointly; do not call the function separately per column when cross-column dependence matters.

required
n_bootstrap int

Number of resamples to draw.

1000
block_length float | None

Mean geometric block length. Defaults to the Politis-White (2004) automatic spectral plug-in (falling back to the practical 1.75 * T^(1/3) rule when the series is too short or degenerate). Must be >= 1; block_length=1 reduces to the ordinary iid bootstrap (Efron).

None
seed int | None

Seed for np.random.default_rng to make the resample reproducible.

None

Returns:

Type Description
ndarray

(n_bootstrap, T) array for vector input or

ndarray

(n_bootstrap, T, m) for matrix input.

References
  • Politis & Romano (1994). "The Stationary Bootstrap." Journal of the American Statistical Association, 89(428), 1303–1313. Stationary block bootstrap with geometric block lengths — the resampling scheme this function implements.
  • Politis & White (2004). "Automatic Block- Length Selection for the Dependent Bootstrap." Econometric Reviews, 23(1), 53–70. Source of the spectral plug-in block_length=None resolves to.

Inference-method instances + standalone statistical helpers under factrix.stats.

Estimator catalogue

The selection-only estimator classes under factrix.stats:

Class Algorithm family Description
WaldNWCluster Cluster-Wald \(\chi^2\) (1-way cluster on slice) 1-way cluster-robust Wald contrast test
WaldTwoWayCluster Cluster-Wald \(\chi^2\) (two-way cluster on (date, asset)) 2-way cluster-robust Wald contrast test
BlockBootstrap Politis-Romano stationary or Künsch fixed block bootstrap Empirical p-value block bootstrap for paired contrast
DriscollKraay Driscoll-Kraay cross-section-robust HAC SE Selection-only base Estimator for Driscoll-Kraay robust standard errors

Multiplicity / bootstrap utilities

  • bhy_adjust(p_values, fdr=0.05, *, n_tests=None): Benjamini-Yekutieli step-up rejection mask. Returns a boolean array.
  • bhy_adjusted_p(p_values, *, n_tests=None): BHY-adjusted p-values (clipped at 1.0).
  • holm_adjusted_p(p_values, *, n_tests=None): Holm step-down FWER-adjusted p-values under arbitrary dependence. Use FWER when a search selects one winner or every retained hypothesis must avoid any false positive; use FDR when retaining a batch and controlling its expected false-discovery proportion.
  • romano_wolf_adjusted_p(statistics, bootstrap_statistics, *, one_sided=False): Dependence-aware step-down max-t FWER-adjusted p-values. This expert primitive requires every searched hypothesis and each bootstrap row to be a joint, null-centred draw with the same studentization as the observed statistics; independently resampled or omitted columns are invalid. Its empirical p-value resolution is 1 / (B + 1). Use Holm when a valid joint bootstrap family is unavailable.
  • stationary_bootstrap_resamples(values, n_bootstrap, ...): Politis-Romano (1994) bootstrap resamples. An aligned (T, m) per-period statistic matrix is resampled with common row indices and returns (B, T, m), preserving cross-hypothesis dependence for Romano-Wolf; separate per-column calls do not.
  • bootstrap_mean_ci(values, *, n_bootstrap, ci, ...): Stationary-bootstrap CI for a statistic.

Holm and BHY consume already calibrated p-values, so a declared family may contain a documented mix of two-sided, greater, and less alternatives; the procedures do not reinterpret tails. Factrix intentionally provides no generic one-sided-to-two-sided conversion because that conversion depends on the null distribution and producer contract.

romano_wolf_adjusted_p remains an expert primitive: the caller must provide the complete joint, H0-centred, correctly studentized (B, m) matrix. Factrix does not currently expose a multi_factor.romano_wolf or panel-aware bootstrap workflow; use Holm unless that joint bootstrap contract is available.