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.1.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.1-py3-none-any.whl (45.4 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: facmodts-0.1.1.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.1.tar.gz
Algorithm Hash digest
SHA256 01befac6587edcd030c30b3ff98420a4f5d895ac60f8fe16232ad41d586f93ae
MD5 55bf5ce2dcb5c938824d2c4bc2bab9b8
BLAKE2b-256 5e26c81051addb050227ce5dc2cb3f66e9fa446796ec049fba1f0302cc8e10b4

See more details on using hashes here.

File details

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

File metadata

  • Download URL: facmodts-0.1.1-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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 294678b8c47c6959f389e8de459d1f699fedcb336b7aa545835f1ca2f57b23cf
MD5 94a5c9bd711afad5743b13d7f4e35a66
BLAKE2b-256 99e433073f1c93df7cb300a8dc0d0e2932c0cb62060eafabe329d1548cc1b5aa

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