Skip to content

factrix.EvaluationResult dataclass

EvaluationResult(factor: str, cell: tuple[FactorScope, FactorDensity, DataStructure], forward_periods: int, n_periods: int, n_pairs: int, n_assets: int, metrics: Mapping[str, MetricResult], plan: str, params: Mapping[str, Hashable] = dict(), metadata: Mapping[str, Any] = dict(), warnings: list[Warning] = list())

Bundle-level result for one factor.

Attributes:

Name Type Description
factor str

Factor column name from the source panel.

cell tuple[FactorScope, FactorDensity, DataStructure]

(scope, density, structure) tuple derived from the panel structure at dispatch time. structure is DataStructure.PANEL or DataStructure.TIMESERIES resolved from the panel's asset count; scope and density default to INDIVIDUAL / DENSE.

forward_periods int

The data's overlap horizon — read from the panel's compute_forward_return stamp (or the declared fallback for a self-attached panel). A property of the data, not a per-metric knob.

n_periods int

Number of unique dates in the factor panel where the factor column is non-null. A panel structural property — independent of any individual metric's estimator.

n_pairs int

Number of non-null (date, asset_id) pairs in the factor panel. A panel structural property.

n_assets int

Unique assets in the panel (cell-invariant; 1 is legal for TIMESERIES).

metrics Mapping[str, MetricResult]

Read-only label -> MetricResult mapping carrying per-metric outputs, keyed by the caller-supplied label. Structural metrics (e.g. greedy_forward_selection) carry their non-scalar payload in MetricResult.metadata — the value is still a :class:MetricResult.

params Mapping[str, Hashable]

Caller-supplied hypothesis parameters — the sweep knobs that decide which hypothesis this result is (e.g. {"timeframe": "1h", "universe": "tw50"}). Every value joins the hypothesis identifier, so two results that differ only in params are two distinct hypotheses. expand_over may name these keys to partition a family.

metadata Mapping[str, Any]

Caller-supplied bookkeeping labels that do not define the hypothesis (e.g. {"run_id": ..., "vintage": ...}). Never joins the identifier and never partitions a family, so two results differing only in metadata still collide as a duplicate hypothesis.

warnings list[Warning]

Flat list of :class:Warning records. Per-metric entries carry source=label; cross-metric or pre-dispatch entries carry source=None.

plan str

Multi-line DAG execution plan (topological order, [batchable] / [per-factor] annotations).

unexpected_warnings property

unexpected_warnings: list[Warning]

Warnings the caller did not declare via expected_warnings.

The alert view for pipelines and humans: :attr:warnings is the complete record (declared regimes included, flagged expected=True); this subset is what still deserves attention.

metric

metric(label: str) -> MetricResult

Return the :class:MetricResult for label.

Convenience over result.metrics[label] — the same lookup with a message that lists the available labels on a miss, so a typo in an interactive session fails loudly instead of with a bare KeyError.

to_dict

to_dict() -> dict[str, Any]

JSON-friendly nested dict view.

Layout (top-level keys, stable order):

  • factor / cell / forward_periods / n_periods / n_pairs / n_assets / params / metadata
  • metrics: label -> {value, p_value, alternative, stat, n_obs, n_obs_axis, is_applicable, reason, metadata}
  • warnings: list of {code, source, message, expected}
  • plan

Float NaN / Inf are emitted as None.

to_frame

to_frame() -> DataFrame

One row per produced metric, prefixed with bundle identity.

Schema (column order is stable):

column dtype source
factor str :attr:factor
n_assets i64 :attr:n_assets
metric_name str MetricResult.name
value f64 | null MetricResult.value
p_value f64 | null MetricResult.p_value
alternative str | null MetricResult.alternative
stat f64 | null MetricResult.stat
n_obs i64 | null MetricResult.n_obs — estimator effective sample size
n_obs_axis str | null MetricResult.n_obs_axis — axis n_obs counts along (periods / events / pairs / assets)
is_applicable bool false for strict=False short-circuits
reason str | null short-circuit reason when not applicable
warning_codes list[str] per-metric warning codes

Designed for stacking across factors: pl.concat([r.to_frame() for r in results.values()])


Serialization Methods

EvaluationResult provides two main methods to serialize evaluation outputs:

to_frame()

Converts the metric results into a stable, long-form Polars pl.DataFrame. This makes it easy to stack results across multiple factors using pl.concat([r.to_frame() for r in results]) before writing to disk (e.g., Parquet).

Schema: - factor (str): The factor column name. - n_assets (i64): Total unique assets. - metric_name (str): The metric identifier. - value (f64 | null): The calculated metric value (NaN/Inf are normalized to null). - p_value (f64 | null): The p-value, if applicable. - alternative (str | null): The tested alternative (two-sided, greater, or less), present exactly when p_value is present. - stat (f64 | null): The underlying test statistic, if applicable. - n_obs (i64 | null): Effective sample size the metric's estimator used. null only where a single integer count is not meaningful (e.g. a multi-window CAAR series). - n_obs_axis (str | null): The dimension n_obs counts along — periods / events / pairs / assets. A bare count is uninterpretable without it (a Fama-MacBeth n_obs is periods; a pooled-OLS one is (date, asset) pairs). null exactly when n_obs is. - is_applicable (bool): false when strict=False returned a short-circuit placeholder for an unsupported metric/input combination. - reason (str | null): Short-circuit reason when is_applicable is false. - warning_codes (list[str]): List of warnings attached to the metric.

to_dict()

Converts the result into a JSON-friendly nested dictionary. It normalizes floats (e.g., NaN and Inf to None) so that it can be serialized directly using standard json.dumps without raising errors.


The metrics mapping

EvaluationResult.metrics is a read-only Mapping[str, MetricResult] (a MappingProxyType) keyed by the caller-supplied metric label, including short-circuit NaN outputs. Access it like any dict — result.metrics["ic"] returns the MetricResult for "ic", and keys() / values() / items() / get() / in / len() / iteration all work as usual. The mapping is immutable; attempting to assign into it raises TypeError.

result.metric("ic") is a convenience over result.metrics["ic"]: the same lookup, but a miss raises KeyError listing the available labels (no metric 'sharpe' on this result; available: ic, ic_ir) instead of a bare key — handy in interactive sessions where a typo would otherwise fail opaquely.


factrix.MetricResult dataclass

MetricResult(value: float, p_value: float | None = None, alternative: PValueAlternative | None = None, n_obs: int | None = None, n_obs_axis: SampleAxis | None = None, stat: float | None = None, metadata: dict[str, object] = dict(), warning_codes: tuple[str, ...] = (), name: str = '')

Single-metric result produced by a factrix.metrics.* primitive.

Attributes:

Name Type Description
value float

Raw metric value.

p_value float | None

P-value for the metric's hypothesis test. None for descriptive metrics that carry no formal test.

alternative PValueAlternative | None

Alternative-hypothesis direction used to construct p_value. Present exactly when p_value is present.

n_obs int | None

Effective sample size the estimator actually used (e.g. number of non-overlapping IC periods, number of events, number of bootstrap windows). None where a single integer count is not meaningful (e.g. multi-window CAAR series).

n_obs_axis SampleAxis | None

Sample dimension n_obs counts along — one of "periods" / "events" / "pairs" / "assets". A bare count is uninterpretable without its axis (a Fama-MacBeth n_obs is periods; a pooled-OLS one is (date, asset) pairs), so producers stamp the axis alongside the count. None exactly when n_obs is.

stat float | None

Test statistic (t, z, W, chi2, ...), when applicable.

metadata dict[str, object]

Estimator-specific context beyond the top-level fields (stat_type, h0, method are the standard keys).

warning_codes tuple[str, ...]

Per-metric advisory :class:WarningCode values (as strings) the producer attached to this output. Empty tuple when the metric raised no advisory.

name str

Metric name stamped by the DAG executor at dispatch time. Empty string for outputs constructed outside the registry.

is_applicable property

is_applicable: bool

Whether the metric produced a usable result for this input.

strict=False short-circuits unsupported metrics into placeholder outputs with metadata["reason"]. This flag lets reporting and grid-search code filter those rows without relying on metadata shape.

reason property

reason: str | None

Stable short-circuit reason, when the metric did not run cleanly.


Key Fields

MetricResult represents the outcome of a single metric calculation. Its primary fields are:

  • value (float): The calculated numeric output of the metric.
  • p_value (float | None): The calibrated statistical p-value. It must be finite and in [0, 1].
  • alternative (str | None): The corresponding alternative hypothesis (two-sided, greater, or less). p_value and alternative must either both be present or both be None. > [!IMPORTANT] > p_value is the canonical field for metric p-values.
  • stat (float | None): The test statistic (e.g. t-statistic, z-statistic).
  • n_obs (int | None): Effective sample size the estimator used in this specific metric calculation.
  • n_obs_axis (str | None): Sample dimension n_obs counts along — one of periods / events / pairs / assets. Stamped by the producer alongside n_obs; None exactly when n_obs is.
  • is_applicable (bool): False for strict=False short-circuit placeholders, so reporting code can filter them without inspecting metadata["reason"].
  • reason (str | None): Stable short-circuit reason, copied from metadata["reason"] when present.
  • metadata (dict): Underlying dictionary of metric-specific metadata.
  • warning_codes (tuple[str, ...]): Advisory warnings attached to the metric.
  • name (str): The name of the metric, automatically populated during dispatch.

factrix.Warning dataclass

Warning(code: WarningCode, source: str | None = None, message: str = '', expected: bool = False)

Flat per-evaluation diagnostic record.

Source convention: a per-metric warning carries source == <metric label>; a panel-level / cross-metric warning carries source is None.

Attributes:

Name Type Description
code WarningCode

The :class:WarningCode enum member.

source str | None

Metric label that emitted the warning, or None for bundle-level diagnostics.

message str

Human-readable detail.

expected bool

True when the caller declared this code as the study's design via evaluate(..., expected_warnings=(...,)). The record is never dropped — the flag says "acknowledged", not "absent" — so human-facing channels (stderr echo, repr emphasis) can go quiet while the audit trail stays complete.


Fields

A Warning object represents a warning emitted during data inspection or metric evaluation:

  • code (WarningCode): The enum identifier for the warning type (e.g. WarningCode.UNRELIABLE_SE_SHORT_PERIODS).
  • source (str | None): The name of the metric that generated the warning. If the warning is data-level or cross-metric, source is None.
  • message (str): A human-readable detail message describing the issue.