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
- Data Handling: Uses Polars for data operations (2-5x faster), converts to pandas for statsmodels regression
- Robust Methods: Python uses M-estimators (Huber, Bisquare) via statsmodels RLM, whereas R uses MM-estimators. Breakdown points may differ.
- Column Names: Automatically converts spaces to periods like R xts
- 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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
01befac6587edcd030c30b3ff98420a4f5d895ac60f8fe16232ad41d586f93ae
|
|
| MD5 |
55bf5ce2dcb5c938824d2c4bc2bab9b8
|
|
| BLAKE2b-256 |
5e26c81051addb050227ce5dc2cb3f66e9fa446796ec049fba1f0302cc8e10b4
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
294678b8c47c6959f389e8de459d1f699fedcb336b7aa545835f1ca2f57b23cf
|
|
| MD5 |
94a5c9bd711afad5743b13d7f4e35a66
|
|
| BLAKE2b-256 |
99e433073f1c93df7cb300a8dc0d0e2932c0cb62060eafabe329d1548cc1b5aa
|