Skip to content

factrix.metrics.common_quantile

Time-series quantile bucketing + monotonicity test.

Diagnostic for the (COMMON, DENSE, PANEL) cell (needs n_assets >= 2 assets; raises at n_assets == 1): bucket factor history into quantiles and check the conditional mean forward return per bucket. Catches U-shape / inverted-U / extreme-only signals that ordinary least squares (OLS) β assumes away (linear) and reports pass / fail on as a single slope.

SPARSE / binary signals are out of scope; the input gate redirects to event_quality helpers.

Notes

Pipeline. Per-date aggregation to a common (_f, _r) series (cross-section step), then quantile-bucketed Newey-West (NW) heteroskedasticity-and-autocorrelation-consistent (HAC) OLS on that time series; Wald (finite-sample F) on the top-bottom bucket spread.

factrix.metrics.common_quantile.common_quantile_spread

common_quantile_spread(data: DataFrame, *, factor_col: str = 'factor', return_col: str = 'forward_return', n_groups: int = DEFAULT_N_GROUPS, overlap_periods: int | None = None, newey_west_lags: int | None = None, expected_warnings: tuple[str, ...] = ()) -> MetricResult

Bucket time-series factor by historical quantiles, test conditional means.

Reported:

  • value = top-bottom spread (β_{K-1} - β_0)
  • stat = Wald on H0: β_{K-1} = β_0 → two-sided p in metadata
  • metadata["spearman_rho"] / spearman_p = small-sample monotonicity diagnostic across the K bucket means
  • metadata["buckets"] = per-bucket {idx, mean_return, n}

Gate for conditional means/piecewise slopes: n_unique(factor) >= n_groups * 2. Below the gate the factor cannot sustain quantile cuts — short-circuits with a redirect to event_quality.* for binary / sparse signals.

Parameters:

Name Type Description Default
data DataFrame

Long panel; aggregated to per-date (_f, _r) internally.

required
factor_col str

Column carrying the factor.

'factor'
return_col str

Column carrying the forward return.

'forward_return'
n_groups int

Number of quantile buckets K to cut the factor history into. At least :data:~factrix._types.N_GROUPS_FLOOR = 2 (the top-minus-bottom contrast needs two buckets); the Spearman shape check is reported as NaN below K = 3.

DEFAULT_N_GROUPS
overlap_periods int | None

Overlap horizon of the forward return; floors the Bartlett bandwidth at 3 * (overlap_periods - 1) and caps the reference degrees of freedom at T / overlap_periods - 1.

None
newey_west_lags int | None

Override for the Bartlett lag count. None resolves to the standard rule given overlap_periods and T; the finite-sample scale and reference df follow the resolved bandwidth either way.

None

Returns:

Type Description
MetricResult

MetricResult whose value is the top-bottom bucket

MetricResult

spread; bucket detail and the Spearman monotonicity diagnostic

MetricResult

live in metadata. Short-circuits with a reason code when

MetricResult

input shape is insufficient (no factor / return column, fewer

MetricResult

than MIN_PORTFOLIO_PERIODS_HARD rows, or factor variation

MetricResult

below n_groups * 2 distinct values); a missing date /

MetricResult

asset_id is a UserInputError from the panel key-column gate.

Notes

Aggregate the panel to per-date (_f, _r), ordinal-rank into K = n_groups buckets by historical _f quantile, run r_t = sum_k beta_k * I(bucket_t = k) + eps with NW heteroskedasticity-and-autocorrelation-consistent (HAC) covariance, and form the spread value = beta_{K-1} - beta_0 with Wald p-value on H0: beta_{K-1} = beta_0. That is a single restriction, so the bandwidth, the T / (T - L - 1) variance scale and the fixed-b effective degrees of freedom come from :func:~factrix._stats.hac._resolve_scalar_wald_hac — the same recipe the scalar series-mean HAR t-test uses, and the one this metric's size table is measured on (inference-calibration). A Spearman(0..K-1, beta) rank-monotonicity diagnostic across buckets is reported alongside.

HAC_BANDWIDTH_ILL_CONDITIONED reports a resolved bandwidth estimated from too few lag products on samples of at least 30 periods. Shorter samples follow this metric's effective-sample warning contract.

factrix uses NW HAC + Wald rather than Welch t for cross-method comparability with common_asymmetry / common_beta and because overlap_periods > 1 breaks the iid assumption Welch relies on.

References

Newey-West 1987: HAC covariance under-pinning the Wald test. Newey-West 1994: automatic Bartlett bandwidth used by the default lag resolver. Hansen-Hodrick 1980: the MA(h-1) structure the overlap floor covers. LLSW 2018: the HAR bandwidth and effective-df recipe the single-restriction contrast reads.

Examples:

>>> import factrix as fx
>>> from factrix.preprocess import compute_forward_return
>>> from factrix.metrics.common_quantile import common_quantile_spread
>>> panel = compute_forward_return(
...     fx.datasets.make_cs_panel(n_assets=80, n_dates=180, rng=0),
...     forward_periods=5,
... )
>>> result = common_quantile_spread(panel, n_groups=5)
>>> result.name == ""
True

Common-factor regression conventions

Plain stage-1 SE rationale and the forward_periods vs signal_horizon bias framing apply here as for the rest of the Common × Continuous family. See Common-factor regression conventions.

Use cases

  • Detect non-linear factor → return shape


    Linear ordinary least squares (OLS) \(\beta\) reports a single slope and fails on U-shape / inverted-U / extreme-only signals. common_quantile_spread aggregates the panel to a per-date \((\_f, \_r)\) series, buckets _f into \(K\) historical quantiles, and reads the conditional mean return per bucket — preserves whatever shape the relationship has.

  • Top-bottom spread significance with Newey-West (NW) heteroskedasticity-and-autocorrelation-consistent (HAC)


    Headline is \(\beta_{K-1} - \beta_0\) — the conditional mean difference between the top and bottom quantile of factor history. Inference is a Wald \(\chi^2\) on \(H_0: \beta_{K-1} = \beta_0\) with Newey-West HAC covariance; kernel choice is consistent with common_asymmetry so cross-method \(p\)-values stay comparable under overlapping forward returns.

  • Rank-monotonicity diagnostic across buckets


    metadata["spearman_rho"] / spearman_p give a non-parametric Spearman rank check on the bucket-mean sequence \((\beta_0, \ldots, \beta_{K-1})\). Catches a monotone shape that the top-bottom Wald would conflate with a wider U.

Worked example — quantile-bucketed conditional means on a common-factor panel

broadcast common factor → common_quantile_spread

import factrix as fx
import polars as pl
from factrix.metrics.common_quantile import common_quantile_spread
from factrix.preprocess import compute_forward_return

# Build a panel whose ``factor`` is broadcast (one value per date,
# shared across all assets) — VIX / USD-index style.
raw = fx.datasets.make_cs_panel(
    n_assets=50, n_dates=1000, ic_target=0.08, rng=2024,
)
common = raw.group_by("date").agg(pl.col("factor").mean().alias("factor"))
panel  = raw.drop("factor").join(common, on="date")
panel  = compute_forward_return(panel, forward_periods=5)

out = common_quantile_spread(panel, n_groups=5, overlap_periods=5)
print(out.value, out.stat, out.p_value)
# 0.0018  3.20  0.0014   (approximate)
print(out.metadata["spearman_rho"], out.metadata["spearman_p"])
# 0.90  0.037   (approximate; positive ⇒ monotone shape)
for b in out.metadata["buckets"]:
    print(b)
# {"idx": 0, "mean_return": -0.00091, "n": 199}
# ...
# {"idx": 4, "mean_return":  0.00091, "n": 199}

See also

  • common_beta / common_asymmetry


    Linear \(\beta\) and signed-slope asymmetry diagnostics on the same broadcast-factor panel. Use common_quantile_spread when a Spearman rank check or U-shape detection matters; the others assume a monotone or piecewise-linear response.

    api/metrics/common_beta →

  • event_quality family


    Where the input gate redirects when the factor cannot sustain quantile cuts (binary / sparse signals): event_hit_rate / event_ic / profit_factor / event_skewness.

    api/metrics/event_quality →

  • by_slice / slice_pairwise_test


    Axis-agnostic slice dispatcher and pairwise Wald (Holm / Romano-Wolf adjusted \(p\)) for per-slice spread comparisons.

    api/by-slice →

  • Statistical methods


    NW HAC SE, Newey-West (1994) auto bandwidth, Hansen-Hodrick overlap floor, and the Wald-on-linear-restriction framing.

    reference/statistical-methods →

  • Common-factor regression conventions


    Plain stage-1 SE rationale, forward_periods vs signal_horizon bias framing.

    reference/ts-mode-conventions →

  • Metric applicability reference


    When this metric applies and the sample-size guards that gate it (MIN_PORTFOLIO_PERIODS_HARD, n_distinct(factor) >= n_groups * 2).

    reference/metric-applicability →

  • Common × Continuous landing


    Adjacent macro-common metrics in the same cell.

    api/metrics/common-continuous →