Skip to content

Synthetic panel generators for examples, tests, and documentation. All emit raw canonical-column panels (date, asset_id, price, then one factor column for the single-factor generators or n_factors factor columns for the multi-factor ones); attach forward_return via factrix.preprocess.compute_forward_return before passing to evaluate.

The dataset's signal_horizon is a property of the generated synthetic signal, not a pipeline parameter. When evaluate()'s forward_periods == signal_horizon the pipeline realizes the nominal information coefficient (IC) / drift; other horizons realize a decayed signal.

Single-factor generators

factrix.datasets.make_cs_panel

make_cs_panel(*, n_assets: int = 50, n_dates: int = 252, ic_target: float = 0.04, signal_horizon: int = 5, seed: int = 42, start_date: str = _DEFAULT_START) -> DataFrame

Synthetic cross-sectional panel with a calibrated target information coefficient (IC).

Construction
  1. Per-asset volatility σ_i ~ U[0.01, 0.03]; daily arithmetic returns are ε_{t,i} ~ N(0, σ_i).
  2. Prices p[t,i] = 100 · cumprod(1 + ε).
  3. Signal-horizon forward return fr[t] = (p[t+1+H]/p[t+1] − 1) / H where H = signal_horizon.
  4. Factor is a cross-sectional mixture of standardized forward return and iid noise::

    factor[t] = ρ · z(fr[t]) + √(1−ρ²) · z(η[t])

where ρ = clip(ic_target, −0.99, 0.99) and z is plain Gaussian (not MAD) z-score so the identity Corr(factor, fr) = ρ holds exactly per date at horizon H. Factorlib's ic_mean uses Spearman rank IC, which tracks Pearson ρ tightly at small |ρ| but is not identical — realized ic_mean at |ic_target| ≳ 0.2 may diverge by a few bp. 5. The last H+1 dates have no defined forward return; factor values there are pure noise and will be dropped along with the null forward returns once compute_forward_return runs.

Parameters:

Name Type Description Default
n_assets int

Cross-sectional width.

50
n_dates int

Number of calendar dates (daily index, includes weekends — factrix doesn't prescribe a calendar). Must satisfy n_dates >= signal_horizon + 2 — the floor that yields any defined forward return. For a shorter test panel, lower signal_horizon rather than working around the floor.

252
ic_target float

Target per-date Pearson CS correlation between factor and forward return at signal_horizon. Realized realized per-date IC after fx.evaluate will fall near this within a couple of standard errors — overlapping forward returns reduce effective independent dates by signal_horizon so s.e. ≈ 1 / √((n_dates / signal_horizon) · n_assets).

0.04
signal_horizon int

Horizon (in bars) at which the synthetic density lives — a property of the generated data, not a pipeline parameter. Pipelines measuring at forward_periods == signal_horizon realize the nominal IC; different horizons realize a decayed IC (correct physics for a density with a natural time-scale, not a bug).

5
seed int

RNG seed.

42
start_date str

ISO date for the first row.

_DEFAULT_START

Returns:

Type Description
DataFrame

Long DataFrame with date, asset_id, price, factor and

DataFrame

date dtype pl.Datetime("ms"). Attach forward_return

DataFrame

(e.g. via factrix.preprocess.compute_forward_return)

DataFrame

before passing to fx.evaluate.

Examples:

>>> import factrix as fx
>>> raw = fx.datasets.make_cs_panel(n_assets=20, n_dates=120)
>>> set(raw.columns) == {"date", "asset_id", "price", "factor"}
True
>>> raw["asset_id"].n_unique() == 20
True

Attach a forward return before evaluating:

>>> from factrix.preprocess import compute_forward_return
>>> panel = compute_forward_return(raw, forward_periods=5)
>>> "forward_return" in panel.columns
True

factrix.datasets.make_event_panel

make_event_panel(*, n_assets: int = 50, n_dates: int = 252, event_rate: float = 0.02, event_magnitude: float = 1.0, event_magnitude_jitter: float = 0.0, post_event_drift_bps: float = 10.0, signal_horizon: int = 5, seed: int = 42, start_date: str = _DEFAULT_START) -> DataFrame

Synthetic event-density panel — sparse {0, R} schema.

Construction
  1. Baseline returns as in make_cs_panel.
  2. Independent Bernoulli(event_rate) per (t, i); sign ±1 with equal probability; magnitude R = event_magnitude. Non-event cells get 0.
  3. Post-event drift: for each event with sign s, add s · post_event_drift_bps / 1e4 / signal_horizon to the signal_horizon bars t+2 .. t+1+H of that asset — the exact window a pipeline measuring forward return at the same horizon will see. Drift magnitude is small (≈ bps-per-day) so the event density is discoverable but not trivial.
  4. Prices are cumulated after drift injection.

Suitable for evaluating sparse metrics (e.g. event study caar).

Parameters:

Name Type Description Default
n_assets int

Cross-sectional width.

50
n_dates int

Number of calendar dates. Must satisfy n_dates >= signal_horizon + 2 — the floor that yields any defined forward return. For a shorter test panel, lower signal_horizon rather than working around the floor.

252
event_rate float

Per-cell event probability (≈ expected events per asset per date).

0.02
event_magnitude float

Magnitude of the event signal.

1.0
event_magnitude_jitter float

Relative half-width for continuous event magnitudes. 0.0 emits {0, R} with signed R; positive values make event_ic usable by giving |factor| variation.

0.0
post_event_drift_bps float

Total drift in basis points injected across the signal_horizon bars of the forward-return window (bars t+2 .. t+1+H).

10.0
signal_horizon int

Horizon (in bars) over which post-event drift is distributed — a property of the generated data, not a pipeline parameter. Pipelines measuring at forward_periods == signal_horizon realize the nominal drift; different horizons realize a weakened or diluted density (correct physics for a density with a natural time-scale, not a bug).

5
seed int

RNG seed.

42
start_date str

ISO date for the first row.

_DEFAULT_START

Returns:

Type Description
DataFrame

Long DataFrame with date, asset_id, price, factor. Factor

DataFrame

is Float64 with sparse {0, R} values, where R may be

DataFrame

signed, when event_magnitude_jitter=0. Attach

DataFrame

forward_return (e.g. via

DataFrame

factrix.preprocess.compute_forward_return) before

DataFrame

passing to fx.evaluate.

Examples:

>>> import factrix as fx
>>> raw = fx.datasets.make_event_panel(n_assets=20, n_dates=120, event_rate=0.05, event_magnitude=2.0)
>>> set(raw["factor"].unique().to_list()) <= {-2.0, 0.0, 2.0}
True

Multi-factor generators

For factor-screening / multiple-testing workflows — each emits n_factors factor columns on one shared panel.

factrix.datasets.make_multi_factor_panel

make_multi_factor_panel(*, n_factors: int = 10, n_assets: int = 50, n_dates: int = 252, ic_target: float = 0.04, factor_correlation: float = 0.0, signal_horizon: int = 5, seed: int = 42, start_date: str = _DEFAULT_START) -> DataFrame

Synthetic multi-factor panel with calibrated IC and tunable cross-factor correlation.

Each of n_factors factor columns is constructed as in make_cs_panel (ρ · z(fr) + √(1−ρ²) · z(η_k)), with the per-factor noise terms η_k sharing a common cross-sectional component so that pairwise factor-factor correlation is controllable:

η_k = √c · ξ_common + √(1−c) · ξ_idio_k

where c = factor_correlation. The realized factor-factor cross-sectional correlation is approximately ρ² + (1 − ρ²) · c.

The last H + 1 rows have no defined forward return; factor values there are pure noise (same construction convention as make_cs_panel) and will be dropped along with the null forward returns once compute_forward_return runs.

Parameters:

Name Type Description Default
n_factors int

Number of factor columns to emit.

10
n_assets int

Cross-sectional width.

50
n_dates int

Number of calendar dates.

252
ic_target float

Target per-date Pearson CS correlation between each factor and the forward return at signal_horizon.

0.04
factor_correlation float

Pairwise correlation between factor noise terms in [0, 1). 0 reproduces independent factors; higher values share more of a common cross-sectional driver.

0.0
signal_horizon int

Horizon (in bars) at which the synthetic density lives.

5
seed int

RNG seed.

42
start_date str

ISO date for the first row.

_DEFAULT_START

Returns:

Type Description
DataFrame

Long DataFrame with ``date, asset_id, price, factor_0000,

DataFrame

factor_0001, ....factor_*`` column count equals

DataFrame

n_factors and column width is zero-padded to a stable

DataFrame

sort order.

factrix.datasets.make_multi_factor_event_panel

make_multi_factor_event_panel(*, n_factors: int = 55, n_assets: int = 25, n_dates: int = 400, event_rate: float = 0.04, event_magnitude: float = 1.0, event_magnitude_jitter: float = 0.0, post_event_drift_bps: float = 10.0, signal_horizon: int = 5, seed: int = 42, start_date: str = _DEFAULT_START) -> DataFrame

Synthetic multi-factor event-density panel.

Each of n_factors factor columns is independently sampled as a sparse {0, R} matrix where R may be signed and |R| = event_magnitude when event_magnitude_jitter=0; positive jitter emits continuous magnitudes. Post-event drift from all factors accumulates into the shared underlying asset returns.

Suitable for evaluating sparse multi-factor screening workflows.

Parameters:

Name Type Description Default
n_factors int

Number of factor columns to emit.

55
n_assets int

Cross-sectional width.

25
n_dates int

Number of calendar dates.

400
event_rate float

Per-cell event probability.

0.04
event_magnitude float

Magnitude of the event signal.

1.0
event_magnitude_jitter float

Relative half-width for continuous event magnitudes. 0.0 emits ternary event signals; positive values make event_ic usable in synthetic screening experiments.

0.0
post_event_drift_bps float

Total drift in basis points injected per event across the signal_horizon bars of the forward-return window (bars t+2 .. t+1+H).

10.0
signal_horizon int

Horizon (in bars) over which post-event drift is distributed.

5
seed int

RNG seed.

42
start_date str

ISO date for the first row.

_DEFAULT_START

Returns:

Type Description
DataFrame

Long DataFrame with ``date, asset_id, price, factor_0000,

DataFrame

factor_0001, ....factor_*`` column count equals

DataFrame

n_factors and column width is zero-padded to a stable

DataFrame

sort order.

Examples:

>>> import factrix as fx
>>> raw = fx.datasets.make_multi_factor_event_panel(n_factors=3, n_assets=10, n_dates=60)
>>> raw.columns[:4]
['date', 'asset_id', 'price', 'factor_0000']
>>> raw.height == 10 * 60
True