Skip to content

Quickstart

forward_periods counts rows, not calendar time

factrix is frequency-agnostic — it only shifts row indices. forward_periods=5 on a daily panel means 5 trading days; on a weekly panel, 5 weeks. The caller is responsible for ensuring the panel is sorted per asset and has regular time spacing.

30-second smoke test

import factrix as fx
from factrix.preprocess import compute_forward_return
from factrix.metrics import ic

# 1. Generate synthetic panel data and compute forward returns
raw   = fx.datasets.make_cs_panel(n_assets=100, n_dates=500, ic_target=0.08, seed=2024)
data  = compute_forward_return(raw, forward_periods=5)

# 2. Run single-factor evaluation using the ic metric with Newey-West
results = fx.evaluate(
    data,
    metrics={"ic": ic(inference=fx.inference.NEWEY_WEST)},
    factor_cols=["factor"],
    forward_periods=5,
)

res = results["factor"]
ic_res = res.metrics["ic"]

print('ic_mean =', round(ic_res.value, 4))
# → ic_mean = 0.0722
print('p_value =', round(ic_res.p_value, 4))
# → p_value = 0.0

See Concepts for what each axis means.


Bringing your own data

The smoke test uses synthetic data that already carries factrix's canonical column names (date, asset_id, price). Real-world panels rarely do, so adapt is the first step of the pipeline — it renames your columns to the canonical names (and optionally cleans non-finite values), before compute_forward_return:

import factrix as fx
from factrix.adapt import adapt
from factrix.preprocess import compute_forward_return

raw = adapt(
    your_df,
    date="trade_date", asset_id="ticker", price="close_adj",
    fill_forward=True,   # map NaN/±inf → null, then forward-fill per asset
)
data = compute_forward_return(raw, forward_periods=5)
results = fx.evaluate(data, metrics={"ic": fx.metrics.ic()}, factor_cols=["factor"])

So the full pipeline is adaptcompute_forward_returnevaluate. fill_forward is opt-in: leave it False (default) if your panel is already clean, or set it True for raw OHLCV that may contain sporadic missing or non-finite values.


Research question → metric mapping

In factrix, rather than constructing a central config object, you pass metric instances imported from factrix.metrics directly to the metrics parameter of fx.evaluate().

To learn how to choose the right metrics and configure them, see Choosing a metric and Concepts.


EvaluationResult.to_dict() and warnings

Calling .to_dict() on the returned EvaluationResult returns a flat, JSON-friendly representation of the results, including evaluation metadata, statistics, and any active warnings:

{
  "factor": "factor",
  "cell": {
    "scope": "individual",
    "density": "dense",
    "structure": "panel"
  },
  "forward_periods": 5,
  "n_periods": 494,
  "n_pairs": 49400,
  "n_assets": 100,
  "params": {},
  "metadata": {},
  "metrics": {
    "ic": {
      "value": 0.0722,
      "p_value": 2.129e-40,
      "alternative": "two-sided",
      "stat": 14.60,
      "n_obs": 494,
      "n_obs_axis": "periods",
      "is_applicable": true,
      "reason": null,
      "metadata": {
        "n_periods": 494,
        "forward_periods": 5,
        "stat_type": "t",
        "h0": "mu=0",
        "method": "Newey-West HAC t-test",
        "tie_ratio": 0.0,
        "n_periods_in": 494,
        "n_periods_out": 494,
        "dropped_periods": 0,
        "drop_rate": 0.0,
        "drop_reason": null
      }
    }
  },
  "warnings": [],
  "plan": "1. compute_ic [batchable]\n2. ic [per-factor] requires=compute_ic"
}

The most common warnings include:

  • UNRELIABLE_SE_SHORT_PERIODS\(20 \le T < 30\); Newey-West (NW) HAC SE is unstable. (Falling below the metric's hard sample floor raises InsufficientSampleError under strict=True; the exact floor is metric-specific).
  • PERSISTENT_REGRESSOR — factor augmented Dickey-Fuller (ADF) \(p\)-value exceeds the configured threshold (default 0.10).
  • EVENT_WINDOW_OVERLAP — event windows overlap on the same asset.
  • SERIAL_CORRELATION_DETECTED — Ljung-Box \(p\)-value < 0.05 on residuals.

For the full enum and the trigger conditions for each WarningCode, see Reference § Warning codes.

For exception classes (InsufficientSampleError, IncompatibleAxisError, UserInputError, ...) and their catch patterns, see Errors.


Next steps

You have the evaluation results for one or more factors. The common follow-ups:

You want to… Reach for Guide / Reference
Screen candidate factors with false discovery rate (FDR) control multi_factor.bhy(results) — or partial_conjunction / bhy_hierarchical for nested structure multi_factor overview
Rank factors after screening compare(results) — leaderboard with rank
Explore one metric across slices (sector / regime / universe / ADV bucket) by_slicedict[str, EvaluationResult] Slice analysis
Test whether slices differ statistically slice_pairwise_test / slice_joint_test Slice analysis

For function semantics and the input contract, see the API reference landing and Reading results.