Skip to content

factrix.inference

Curated inference methods for tests on a per-period series mean.

NON_OVERLAPPING strides the series, NEWEY_WEST applies a Bartlett- kernel HAC variance to the full series, and STATIONARY_BOOTSTRAP resamples blocks from the full series. Each member exposes the same compute contract and returns an :class:InferenceResult containing the tested alternative, p-value, estimate, sample size, diagnostics, and warnings.

The inference= parameter is intentionally a closed, per-metric allowlist. It is available on ic, quantile_spread, quantile_spread_vw, and k_spread; other metrics use an estimator fixed by their statistical shape. Passing a method outside a metric's allowlist raises :class:~factrix.IncompatibleInferenceError rather than falling back.

HansenHodrick is available only from factrix.inference.series_mean for standalone comparisons. Its rectangular kernel has no positive-semidefinite guarantee, so no registered metric admits it.

See Inference selection for why the union is closed and what the per-metric allowlist records, Statistical methods for selection guidance, and the calibration reference for measured regimes and known limits.

Inference

Bases: Protocol

Statistical inference method identity.

Implementations are frozen dataclasses that additionally carry a compute whose signature is fixed per target shape (series-mean members share compute(data, *, value_col, overlap_periods, alternative="two-sided")). compute is intentionally absent here — see module docstring.

summary instance-attribute

summary: str

One-line human-readable description of the method.

test instance-attribute

test: str

Test-statistic family label (e.g. "t").

InferenceResult dataclass

InferenceResult(stat: float, p_value: float, alternative: PValueAlternative, metadata: Mapping[str, Any], warnings: frozenset[WarningCode], estimate: float | None = None, n_obs: int | None = None)

Harmonized return shape for an Inference.compute call.

stat / p_value are the test statistic and its requested-tail p-value; alternative names that tail on the same result, and all three feed a MetricResult directly. metadata is a flat str -> Any map (non-overlapping emits stride / sample counts; Newey-West emits newey_west_lags). warnings carries soft-floor / kernel-clamp signals.

NeweyWest dataclass

NeweyWest()

Newey-West HAC t-test on the full series with a Bartlett kernel.

The bandwidth uses the LLSW (2018) 1.3·√T rule, floored at 3(h - 1) and capped at T/3. The variance is scaled by T/(T - L - 1), and the statistic uses effective degrees of freedom bounded by T/h - 1. All three are derived from the input sample, so this class carries no lag parameter; the resolved bandwidth and degrees of freedom are reported as metadata["newey_west_lags"] and metadata["hac_dof"].

This method retains observations that NonOverlapping drops, but it is not uniformly more powerful or better calibrated. Persistence that remains after striding at overlap_periods raises WarningCode.SERIAL_CORRELATION_DETECTED. See the statistical-methods and inference-calibration references for selection guidance and measured limits.

min_input_periods

min_input_periods(overlap_periods: int) -> int

Minimum input series length (periods) below which the HAC t-test cannot run.

NonOverlapping dataclass

NonOverlapping()

Non-overlapping stride subsample inference: OLS t-test on every overlap_periods-th observation.

Sub-samples the cleaned series at a stride equal to overlap_periods to break the MA(h-1) autocorrelation that overlapping h-period forward returns induce (Hansen-Hodrick 1980), then runs a textbook OLS t-test on the survivors. The most conservative overlap-aware path — it discards h-1 of every h observations rather than correcting the SE; NeweyWest is the less-lossy HAC alternative on the full series.

min_input_periods

min_input_periods(overlap_periods: int) -> int

Minimum input series length (periods): need base · h rows to land base after striding.

StationaryBootstrap dataclass

StationaryBootstrap(n_resamples: int = 999, rng: Rng = None)

Stationary-bootstrap empirical-p inference on a series mean.

Resamples geometric-length blocks (Politis-Romano 1994) from the series, centred under \(H_0: \mathbb{E}[x] = 0\), and reports the empirical p-value from a studentized bootstrap-t root. Block length is selected automatically per Politis-White (2004) and cannot be shorter than overlap_periods. This is a second read for an adequately long, stationary series with distributional doubt; it is not a short-sample or strong-persistence remedy.

Metadata records the resolved block length, seed, usable resample count, and Monte Carlo standard error. If studentization is impossible, the method uses a raw-mean root and raises WarningCode.DEGENERATE_VARIANCE. See the inference-calibration reference for measured limits.

Parameters:

Name Type Description Default
n_resamples int

Number of bootstrap draws. Must be at least BOOTSTRAP_RESAMPLES_FLOOR; defaults to 999.

999
rng Rng

An int, None, or a numpy.random.Generator. None resolves and reports a seed. A Generator is advanced in place and reports no seed because the caller owns the stream.

None

min_input_periods

min_input_periods(overlap_periods: int) -> int

Minimum input series length (periods); no overlap-specific floor.

Direct compute result

Every series-mean member has the same direct-call shape:

from datetime import date, timedelta

import numpy as np
import polars as pl
from factrix.inference import NEWEY_WEST

data = pl.DataFrame(
    {
        "date": [date(2024, 1, 1) + timedelta(days=i) for i in range(60)],
        "value": np.linspace(-0.1, 0.2, 60),
    }
)
result = NEWEY_WEST.compute(
    data,
    value_col="value",
    overlap_periods=5,
    alternative="greater",
)
assert result.alternative == "greater"

Direct calls require a non-null Polars Date or Datetime column named date, exactly one observation per date, a numeric column named by value_col, and a positive integer overlap_periods. Missing or non-numeric value columns raise UserInputError. If the source contains multiple observations in one period, aggregate them explicitly before calling compute; factrix does not guess whether mean, last, or another reduction represents the series.

InferenceResult.p_value is always paired with InferenceResult.alternative, which is the validated "two-sided", "greater", or "less" tail passed to the statistical kernel. Read these two fields together; metadata contains method-specific diagnostics such as bandwidth, effective degrees of freedom, or bootstrap seed.