extendedmosaicperm.factor_data module

class FactorModelDataGenerator(n_timepoints=60, n_assets=10, n_factors=3, seed=123)[source]

Bases: object

Generator of synthetic data for factor-model simulations.

Supports multiple residual correlation structures, time-varying exposures, and configurable distributional asymmetry.

Parameters:
  • n_timepoints (int) – Number of time periods T.

  • n_assets (int) – Number of assets N.

  • n_factors (int) – Number of factors K.

  • seed (int) – Random seed for reproducibility.

Examples

Basic usage with constant exposures and symmetric residuals:

>>> from extendedmosaicperm.factor_data import FactorModelDataGenerator
>>> gen = FactorModelDataGenerator(n_timepoints=20, n_assets=6, n_factors=2, seed=0)
>>> Y, L_time, X, eps = gen.generate_data_random_correlation(
...     violation_strength=0.1,
...     exposures_update_interval=None,
...     symmetric_residuals=True,
... )
>>> Y.shape, L_time.shape, X.shape, eps.shape
((20, 6), (20, 6, 2), (20, 2), (20, 6))

Time-varying exposures, redrawn every 5 periods:

>>> gen = FactorModelDataGenerator(n_timepoints=15, n_assets=5, n_factors=3, seed=1)
>>> Y, L_time, X, eps = gen.generate_data_block_correlation(
...     violation_strength=0.2,
...     block_ratio=0.4,
...     exposures_update_interval=5,
...     symmetric_residuals=True,
... )
>>> L_time[0].shape
(5, 3)

Asymmetric residuals (gamma-based, standardized):

>>> gen = FactorModelDataGenerator(n_timepoints=12, n_assets=7, n_factors=2, seed=2)
>>> Y, L_time, X, eps = gen.generate_data_diagonal_plus_common_factor(
...     violation_strength=0.3,
...     exposures_update_interval=None,
...     symmetric_residuals=False,
...     gamma_shape=2.0,
...     gamma_scale=1.0,
... )
>>> eps.shape == Y.shape == (12, 7)
True
generate_data_block_correlation(violation_strength=0.0, block_ratio=0.5, exposures_update_interval=None, symmetric_residuals=True, gamma_shape=2.0, gamma_scale=1.0)[source]

Generate data with block-correlated residuals.

A subset of assets (a “block”) exhibits stronger cross-sectional correlation than the rest. The size of the block and correlation strength are controlled by block_ratio and violation_strength.

Parameters:
  • violation_strength (float) – Within-block correlation strength in [0, 1].

  • block_ratio (float) – Fraction of assets forming the strongly correlated block in (0, 1].

  • exposures_update_interval (Optional[int]) – Interval (in timepoints) for refreshing exposures; None means constant exposures.

  • symmetric_residuals (bool) – Whether residuals are symmetric (Gaussian) or asymmetric (gamma-based).

  • gamma_shape (float) – Shape parameter for asymmetric (Gamma) noise.

  • gamma_scale (float) – Scale parameter for asymmetric (Gamma) noise.

Returns:

A tuple (Y, L_time, X, eps) where:

  • Y – simulated outcomes, shape (T, N),

  • L_time – exposures, shape (T, N, K),

  • X – latent factors, shape (T, K),

  • eps – residuals, shape (T, N).

Return type:

tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]

Examples

>>> from extendedmosaicperm.factor_data import FactorModelDataGenerator
>>> gen = FactorModelDataGenerator(n_timepoints=24, n_assets=10, n_factors=3, seed=0)
>>> Y, L_time, X, eps = gen.generate_data_block_correlation(
...     violation_strength=0.3, block_ratio=0.5, exposures_update_interval=6
... )
>>> Y.shape[1], L_time.shape[2], X.shape[1]
(10, 3, 3)
generate_data_diagonal_plus_common_factor(violation_strength=0.0, exposures_update_interval=None, symmetric_residuals=True, gamma_shape=2.0, gamma_scale=1.0)[source]

Generate data with diagonal residual covariance plus a common factor.

Residuals are decomposed into a diagonal idiosyncratic component and a single common factor component with strength controlled by violation_strength.

Parameters:
  • violation_strength (float) – Strength of the common residual factor in [0, 1].

  • exposures_update_interval (Optional[int]) – Interval (in timepoints) for refreshing exposures; None means constant exposures.

  • symmetric_residuals (bool) – Whether residuals are symmetric (Gaussian) or asymmetric (gamma-based).

  • gamma_shape (float) – Shape parameter for asymmetric (Gamma) noise.

  • gamma_scale (float) – Scale parameter for asymmetric (Gamma) noise.

Returns:

A tuple (Y, L_time, X, eps) where:

  • Y – simulated outcomes, shape (T, N),

  • L_time – exposures, shape (T, N, K),

  • X – latent factors, shape (T, K),

  • eps – residuals, shape (T, N).

Return type:

tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]

Examples

>>> from extendedmosaicperm.factor_data import FactorModelDataGenerator
>>> gen = FactorModelDataGenerator(n_timepoints=25, n_assets=9, n_factors=2, seed=0)
>>> Y, L_time, X, eps = gen.generate_data_diagonal_plus_common_factor(
...     violation_strength=0.2
... )
>>> X.shape
(25, 2)
generate_data_random_correlation(violation_strength=0.0, exposures_update_interval=None, symmetric_residuals=True, gamma_shape=2.0, gamma_scale=1.0)[source]

Generate data with a random residual correlation structure.

Residuals are generated from a random positive-definite correlation matrix, with the degree of cross-sectional dependence controlled by violation_strength.

Parameters:
  • violation_strength (float) – Strength of cross-sectional residual correlation in [0, 1]. 0 corresponds to independence, 1 to the raw random correlation structure.

  • exposures_update_interval (Optional[int]) – Interval (in timepoints) for refreshing exposures; None means constant exposures.

  • symmetric_residuals (bool) – Whether residuals are symmetric (Gaussian) or asymmetric (gamma-based).

  • gamma_shape (float) – Shape parameter for asymmetric (Gamma) noise.

  • gamma_scale (float) – Scale parameter for asymmetric (Gamma) noise.

Returns:

A tuple (Y, L_time, X, eps) where:

  • Y – simulated outcomes, shape (T, N),

  • L_time – exposures, shape (T, N, K),

  • X – latent factors, shape (T, K),

  • eps – residuals, shape (T, N).

Return type:

tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]

Examples

>>> from extendedmosaicperm.factor_data import FactorModelDataGenerator
>>> gen = FactorModelDataGenerator(n_timepoints=30, n_assets=8, n_factors=3, seed=0)
>>> Y, L_time, X, eps = gen.generate_data_random_correlation(violation_strength=0.2)
>>> Y.shape, L_time.shape, X.shape, eps.shape
((30, 8), (30, 8, 3), (30, 3), (30, 8))