Skip to main content

Time series factor models for robust portfolio construction and risk analysis

Project description

facmodts_py: Time Series Factor Models in Python

Python implementation of the facmodTS R package for fitting time series factor models using robust methods. Companion to Robust Portfolio Construction and Risk Analysis (Springer, 2025).

Implementation Status

All planned phases are implemented and covered by the test suite (202 passing, 7 R-comparison tests skipped unless R/rpy2 is available).

Phase 1: Foundation & Core Fitting ✅

  • ✅ Data models (TsfmModel, TsfmControl, TsfmUpDn)
  • ✅ Control parameter handling (fit_tsfm_control)
  • ✅ Utility functions (DLS weights, excess returns, NA handling)
  • ✅ LS (Ordinary Least Squares) regression
  • ✅ DLS (Discounted Least Squares) regression
  • ✅ Test infrastructure (fixtures, tolerances, synthetic data)

Phase 2: Robust Regression & Variable Selection ✅

  • ✅ Robust regression (M-estimators via statsmodels RLM)
  • ✅ Stepwise variable selection
  • ✅ Best subsets variable selection
  • ✅ LARS/Lasso variable selection

Phase 3: Risk Decomposition ✅

  • ✅ Factor model covariance (fm_cov)
  • ✅ SD decomposition (fm_sd_decomp)
  • ✅ VaR decomposition (fm_var_decomp)
  • ✅ ES decomposition (fm_es_decomp)

Phase 4: Wrapper Functions ✅

  • ✅ Market-timing models (fit_tsfm_mt)
  • ✅ Up/Down market models (fit_tsfm_up_dn)
  • ✅ Fama-French wrappers (FF3, FF4)
  • ⬜ Lag/Lead beta models (not yet implemented)

Phase 5: Performance Attribution ✅

  • ✅ Performance attribution (pa_fm)
  • ✅ Summary methods
  • ✅ Print methods
  • ✅ Predict methods

Phase 6: Visualization ✅

  • ✅ Comprehensive plotting suite
  • ✅ Matplotlib and Plotly support

Installation

# From PyPI
pip install facmodts

# With optional plotting / test dependencies
pip install "facmodts[plot]"
pip install "facmodts[test]"

For local development:

# Using UV (recommended)
uv pip install -e ".[test]"

# Or using pip
pip install -e ".[test]"

Quick Start

import polars as pl
from facmodts import fit_tsfm

# Load your data (date, asset returns, factor returns)
data = pl.read_csv("returns.csv")

# Fit LS model
model = fit_tsfm(
    data=data,
    asset_names=["Asset1", "Asset2", "Asset3"],
    factor_names=["Factor1", "Factor2", "Factor3"],
    fit_method="LS"
)

# Extract results
print("Alpha (intercepts):", model.alpha)
print("Beta (factor loadings):\n", model.beta)
print("R-squared:", model.r_squared)
print("Residual SD:", model.resid_sd)

DLS (Discounted Least Squares)

# DLS gives more weight to recent observations
model_dls = fit_tsfm(
    data=data,
    asset_names=["Asset1", "Asset2"],
    factor_names=["Factor1", "Factor2"],
    fit_method="DLS",
    decay=0.95  # Default decay factor
)

Excess Returns

# Subtract risk-free rate from returns
model_excess = fit_tsfm(
    data=data,
    asset_names=["Asset1", "Asset2"],
    factor_names=["MKT", "SMB", "HML"],
    rf_name="RF",  # Risk-free rate column
    fit_method="LS"
)

Running Tests

# Run all tests
pytest

# Run with coverage
pytest --cov=facmodts --cov-report=term-missing

# Run specific test file
pytest tests/test_fitting.py

# Run tests that don't require R
pytest -m "not r_comparison"

Development

# Install development dependencies
uv pip install -e ".[dev,test,plot]"

# Format code
black facmodts/ tests/

# Lint code
ruff check facmodts/ tests/

# Type checking
mypy facmodts/

Project Structure

facmodts_py/
├── facmodts/               # Main package
│   ├── __init__.py
│   ├── models.py          # TsfmModel, TsfmControl data classes
│   ├── fitting.py         # fit_tsfm() and helpers
│   ├── control.py         # fit_tsfm_control()
│   ├── utils.py           # Utility functions (Numba-accelerated)
│   └── ...                # (Phase 2-6 modules)
│
├── tests/
│   ├── conftest.py        # Fixtures, tolerances
│   ├── test_fitting.py    # Core fitting tests
│   ├── data/
│   │   └── stocks_factors.csv  # Real test data (294 assets)
│   └── ...
│
├── examples/              # Usage examples
├── docs/                  # Documentation
├── pyproject.toml        # Package configuration
└── README.md

Key Differences from R facmodTS

  1. Data Handling: Uses Polars for data operations (2-5x faster), converts to pandas for statsmodels regression
  2. Robust Methods: Python uses M-estimators (Huber, Bisquare) via statsmodels RLM, whereas R uses MM-estimators. Breakdown points may differ.
  3. Column Names: Automatically converts spaces to periods like R xts
  4. NA Handling: Per-asset NA removal to allow unequal histories (same as R)

License

GPL-3.0 (same as R package)

Authors

Python conversion team, based on the original facmodTS R package.

References

Robust Portfolio Construction and Risk Analysis (2025). Springer.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

facmodts-0.1.0.tar.gz (634.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

facmodts-0.1.0-py3-none-any.whl (45.4 kB view details)

Uploaded Python 3

File details

Details for the file facmodts-0.1.0.tar.gz.

File metadata

  • Download URL: facmodts-0.1.0.tar.gz
  • Upload date:
  • Size: 634.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.17 {"installer":{"name":"uv","version":"0.11.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for facmodts-0.1.0.tar.gz
Algorithm Hash digest
SHA256 4b83ae11d6d189ff95b112ad23d53d99ffde3f5c4c10c9aee056b46df87a4488
MD5 d5bd839da15cc38c1bdb7f3da5b17bd2
BLAKE2b-256 bcb7f3ab22a87c5f14d16bcda3122513a19b060e7e4aeac0c9c213fb5852ec52

See more details on using hashes here.

File details

Details for the file facmodts-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: facmodts-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 45.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.17 {"installer":{"name":"uv","version":"0.11.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for facmodts-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 689c84ee451c725e28ced69b1fdd14519df88d166ca06c66b19dd7fe44cb689c
MD5 109f8c213dead2c09322653c7dae851d
BLAKE2b-256 bd105a013989c5d145c7d4b55cf225623a55257ff6348032f1bd57a1f999c47c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page