Data schema
Single-source contract for every factrix entry point that consumes a panel. Every dispatch cell evaluate runs floors its input schema at the same four columns described here. Per-cell extensions (optional weight / price columns) are listed under Optional columns.
Four-column contract¶
| Column | dtype | Semantics |
|---|---|---|
date |
Date (preferred) or Datetime |
Observation timestamp. Sorted ascending per asset. Frequency-agnostic — factrix shifts rows, never calendar time. |
asset_id |
Utf8 / Categorical |
Cross-section identifier. Identical for COMMON-scope factors (df.group_by("date").agg(pl.col("factor").n_unique() == 1).all() is True). |
factor |
numeric (Int* / Float*) |
The signal value. Dense: real-valued exposure (z-score, IC-rankable). Sparse: zero-encoded {0, R} event trigger, where 0 marks non-events. |
forward_return |
Float64 |
Look-ahead return over the horizon used at evaluate time. Attach via compute_forward_return so the horizon is explicit and aligned with forward_periods. |
The minimal panel is therefore long-format (date, asset_id, factor, forward_return). A 3-row preview:
For sparse factors, null factor cells are missing values, not non-events, and
are excluded from sparse-ratio detection. Fill missing values to 0 only when
that is the intended event contract; see
Sparse and event signals.
import polars as pl
from datetime import date
panel = pl.DataFrame({
"date": [date(2024, 1, 1), date(2024, 1, 1),
date(2024, 1, 2), date(2024, 1, 2),
date(2024, 1, 3), date(2024, 1, 3)],
"asset_id": ["A", "B", "A", "B", "A", "B"],
"factor": [0.12, -0.08, 0.20, 0.04, -0.15, 0.18],
"forward_return": [0.01, 0.00, 0.02, 0.00, -0.01, 0.03],
})
The two synthetic dataset generators emit this layout (plus a price column) ready for compute_forward_return: fx.datasets.make_cs_panel (cross-sectional) and fx.datasets.make_event_panel (event-study).
Accepted input type: DataInput¶
Every data-consuming entry point annotates its first argument as DataInput — an eager pl.DataFrame or a pl.LazyFrame. A LazyFrame is collected internally, so the choice is purely ergonomic; the schema contract above is identical either way.
factrix.DataInput ¶
Accepted panel input type for every data-consuming entry point.
Either an eager pl.DataFrame or a pl.LazyFrame carrying the panel
schema (see Data schema). A LazyFrame is
collected internally, so passing one is purely an ergonomic convenience —
the validation and dispatch contract is identical.
factor_cols= — signal column names¶
Panels often arrive with the signal column named something other than "factor" (e.g. "alpha", "score", "momentum_12_1"). Pass a list of column names in factor_cols= to fx.evaluate to evaluate them:
from factrix.metrics import ic
results = fx.evaluate(
panel,
metrics={"ic": ic(inference=fx.inference.NEWEY_WEST)},
factor_cols=["momentum_12_1"],
forward_periods=5,
)
Behaviour:
evaluateprojects each entry infactor_colsto the canonical"factor"name internally so every metric callable still sees the four-column schema.factor_cols=[...]accepts a list of column names — IC stage-1 and batch-native primitives share one polars query across the batch.- Each returned
EvaluationResulthasresult.factorandresult.forward_periods.
Error cases (both raise UserInputError):
| Trigger | Message hint |
|---|---|
factor_cols not present on the panel |
Lists the actual columns; suggests a fuzzy match. |
Optional columns¶
Per-cell extensions activate additional standalone metrics when present and short-circuit (NaN with reason) when absent — they never gate the core procedure.
| Column | Activates | Cell |
|---|---|---|
market_cap (or any name passed as weight_col=) |
quantile_spread_vw value-weighting |
Individual × Continuous |
price |
event_around_return, mfe_mae, event-window diagnostics |
Individual × Sparse |
Common errors¶
Schema-related failures and their fix paths:
| Message | Trigger | Fix |
|---|---|---|
factor_cols 'X' not in panel columns |
Typo / wrong column name | Check panel.columns; pass the actual name to factor_cols=. |
forward_return column missing |
Forgot the preprocess step | panel = compute_forward_return(raw, forward_periods=h) before evaluate. |
Full error taxonomy and recovery patterns: Errors.
Preprocess pipeline¶
The canonical pipeline from raw price/event data to evaluate-ready panel:
raw price panel ──compute_forward_return(h)──▶ (date, asset_id, factor, forward_return)
│
▼
evaluate / by_slice / ...
Pre-attachment helpers live in factrix.preprocess; synthetic panels in factrix.datasets. Wide-format multi-factor inputs are handled by passing the column names through factor_cols= on a single evaluate call rather than by reshaping the panel.