dfm-python 0.6.14__tar.gz → 0.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dfm_python-0.6.14 → dfm_python-0.7.0}/.gitignore +2 -1
- dfm_python-0.7.0/CHANGELOG.md +11 -0
- dfm_python-0.7.0/LICENSE +21 -0
- dfm_python-0.7.0/PKG-INFO +186 -0
- dfm_python-0.7.0/README.md +123 -0
- dfm_python-0.7.0/config/afm_finance.yaml +27 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/pyproject.toml +12 -8
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/__init__.py +11 -2
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/config/__init__.py +6 -6
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/config/constants.py +40 -9
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/config/schema/__init__.py +6 -6
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/config/schema/model.py +165 -27
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/config/schema/params.py +35 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/config/schema/results.py +58 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/dataset/__init__.py +2 -0
- dfm_python-0.7.0/src/dfm_python/dataset/afm_dataset.py +119 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/dataset/ivdfm_dataset.py +87 -28
- dfm_python-0.7.0/src/dfm_python/layer/mixing.py +37 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/layer/mlp.py +34 -17
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/layer/pca.py +46 -0
- dfm_python-0.7.0/src/dfm_python/layer/regime.py +53 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/models/__init__.py +10 -0
- dfm_python-0.7.0/src/dfm_python/models/afm/__init__.py +23 -0
- dfm_python-0.7.0/src/dfm_python/models/afm/afm.py +385 -0
- dfm_python-0.7.0/src/dfm_python/models/afm/baselines.py +72 -0
- dfm_python-0.7.0/src/dfm_python/models/afm/factors.py +192 -0
- dfm_python-0.7.0/src/dfm_python/models/afm/longconv.py +97 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/models/base.py +15 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/models/ivdfm/__init__.py +2 -0
- dfm_python-0.7.0/src/dfm_python/models/ivdfm/decoder.py +85 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/models/ivdfm/encoder.py +11 -6
- dfm_python-0.7.0/src/dfm_python/models/ivdfm/ivdfm.py +1838 -0
- dfm_python-0.7.0/src/dfm_python/models/ivdfm/optuna.py +647 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/models/ivdfm/prior.py +77 -4
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/numeric/builder.py +39 -1
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/numeric/estimator.py +78 -9
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/numeric/validator.py +5 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/ssm/companion.py +210 -2
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/ssm/kalman.py +100 -3
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/utils/loss.py +53 -121
- dfm_python-0.7.0/src/test/dataset/test_dfm_dataset.py +0 -0
- dfm_python-0.7.0/src/test/models/test_afm.py +241 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/models/test_ivdfm.py +93 -56
- dfm_python-0.7.0/src/test/models/test_ivdfm_optuna.py +262 -0
- dfm_python-0.7.0/src/test/models/test_ivdfm_regime.py +190 -0
- dfm_python-0.7.0/src/test/ssm/test_companion_regime.py +133 -0
- dfm_python-0.6.14/.cursor/agents/test-runner.md +0 -118
- dfm_python-0.6.14/=0.11.0 +0 -1
- dfm_python-0.6.14/PKG-INFO +0 -56
- dfm_python-0.6.14/data/exchange_rate.csv +0 -7589
- dfm_python-0.6.14/data/finance.csv +0 -9022
- dfm_python-0.6.14/data/macro.csv +0 -2539
- dfm_python-0.6.14/src/dfm_python/models/ivdfm/decoder.py +0 -137
- dfm_python-0.6.14/src/dfm_python/models/ivdfm/ivdfm.py +0 -1271
- dfm_python-0.6.14/uv.lock +0 -3817
- {dfm_python-0.6.14 → dfm_python-0.7.0}/.python-version +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/MANIFEST.in +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/config/ddfm_exchange.yaml +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/config/ddfm_finance.yaml +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/config/ddfm_macro.yaml +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/config/dfm_exchange.yaml +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/config/dfm_finance.yaml +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/config/dfm_macro.yaml +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/config/ivdfm_exchange.yaml +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/config/ivdfm_finance.yaml +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/config/ivdfm_macro.yaml +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/config/adapter.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/config/schema/block.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/config/types.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/dataset/ddfm_dataset.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/dataset/dfm_dataset.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/dataset/time.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/functional/__init__.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/functional/em.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/functional/krylov.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/logger/__init__.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/logger/ddfm_logger.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/logger/dfm_logger.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/logger/inference_logger.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/logger/ivdfm_logger.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/logger/logger.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/logger/train_logger.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/models/ddfm/__init__.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/models/ddfm/ddfm.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/models/ddfm/decoder.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/models/ddfm/encoder.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/models/ddfm/sampling.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/models/dfm/__init__.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/models/dfm/dfm.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/models/dfm/initialization.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/models/dfm/mixed_freq.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/models/dfm/tent.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/numeric/stability.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/numeric/statistic.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/ssm/__init__.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/ssm/base.py +0 -0
- /dfm_python-0.6.14/src/test/dataset/test_dfm_dataset.py → /dfm_python-0.7.0/src/dfm_python/ssm/residual.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/utils/__init__.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/utils/checkpoint.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/utils/errors.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/utils/helper.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/utils/metric.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/utils/misc.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/dfm_python/utils/validation.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/__init__.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/config/__init__.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/config/schema/__init__.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/config/schema/test_block.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/config/schema/test_model.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/config/schema/test_results.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/config/test_adapter.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/config/test_constants.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/config/test_tent_weights_config.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/config/test_types.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/conftest.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/dataset/test_ddfm_dataset.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/dataset/test_ivdfm_dataset.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/functional/__init__.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/functional/test_em.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/functional/test_em_correctness.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/functional/test_em_properties.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/logger/__init__.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/logger/test_inference_logger.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/logger/test_logger.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/logger/test_train_logger.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/models/__init__.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/models/test_ddfm.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/models/test_ddfm_sampling.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/models/test_dfm.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/numeric/__init__.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/numeric/test_builder.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/numeric/test_cov_rowvar_regression.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/numeric/test_estimator.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/numeric/test_initialization.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/numeric/test_stability.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/numeric/test_validator.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/ssm/__init__.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/ssm/test_kalman.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/ssm/test_kalman_correctness.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/utils/__init__.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/utils/test_errors.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/utils/test_helper.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/utils/test_metric.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/src/test/utils/test_misc.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/tutorial/tutorial_exchange_ddfm.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/tutorial/tutorial_exchange_dfm.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/tutorial/tutorial_exchange_ivdfm.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/tutorial/tutorial_finance_ddfm.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/tutorial/tutorial_finance_dfm.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/tutorial/tutorial_finance_ivdfm.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/tutorial/tutorial_macro_ddfm.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/tutorial/tutorial_macro_dfm.py +0 -0
- {dfm_python-0.6.14 → dfm_python-0.7.0}/tutorial/tutorial_macro_ivdfm.py +0 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.7.0
|
|
4
|
+
|
|
5
|
+
- The Attention Factor Model (`dfm_python.models.afm`: `AFM`, attention and PCA
|
|
6
|
+
factors, LongConv filter, Avellaneda-Lee baseline) now ships in the
|
|
7
|
+
distribution; the 0.6.14 wheel on PyPI did not include it.
|
|
8
|
+
- README added and used as the package long description.
|
|
9
|
+
- Metadata: project URLs point to `github.com/minkeymouse/dfm-python`.
|
|
10
|
+
- `build` and `twine` moved from runtime dependencies to the `dev` extra.
|
|
11
|
+
- `__version__` now matches the release; the sdist no longer bundles the example CSVs or the lock file.
|
dfm_python-0.7.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Minkey Chang
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: dfm-python
|
|
3
|
+
Version: 0.7.0
|
|
4
|
+
Summary: Dynamic Factor Model (DFM) estimation and forecasting in Python
|
|
5
|
+
Project-URL: Homepage, https://github.com/minkeymouse/dfm-python
|
|
6
|
+
Project-URL: Documentation, https://github.com/minkeymouse/dfm-python#readme
|
|
7
|
+
Project-URL: Repository, https://github.com/minkeymouse/dfm-python
|
|
8
|
+
Project-URL: Issues, https://github.com/minkeymouse/dfm-python/issues
|
|
9
|
+
Author: Minkey Chang
|
|
10
|
+
License: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: dfm,dynamic-factor-model,econometrics,forecasting,time-series
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Requires-Dist: einops>=0.8.1
|
|
24
|
+
Requires-Dist: hydra-core>=1.3.2
|
|
25
|
+
Requires-Dist: matplotlib>=3.5.0
|
|
26
|
+
Requires-Dist: numpy>=1.24.0
|
|
27
|
+
Requires-Dist: optuna>=4.7.0
|
|
28
|
+
Requires-Dist: pandas>=2.0.0
|
|
29
|
+
Requires-Dist: pyarrow>=22.0.0
|
|
30
|
+
Requires-Dist: pykalman>=0.11.0
|
|
31
|
+
Requires-Dist: pytorch-lightning>=2.0.0
|
|
32
|
+
Requires-Dist: scikit-learn>=1.7.2
|
|
33
|
+
Requires-Dist: scipy>=1.10.0
|
|
34
|
+
Requires-Dist: sktime>=0.40.1
|
|
35
|
+
Requires-Dist: torch>=2.0.0
|
|
36
|
+
Provides-Extra: all
|
|
37
|
+
Requires-Dist: build>=1.4.0; extra == 'all'
|
|
38
|
+
Requires-Dist: hydra-core>=1.3.0; extra == 'all'
|
|
39
|
+
Requires-Dist: omegaconf>=2.3.0; extra == 'all'
|
|
40
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == 'all'
|
|
41
|
+
Requires-Dist: pytest>=7.0.0; extra == 'all'
|
|
42
|
+
Requires-Dist: scikit-learn>=1.0.0; extra == 'all'
|
|
43
|
+
Requires-Dist: sktime>=0.27.0; extra == 'all'
|
|
44
|
+
Requires-Dist: sqlalchemy>=2.0.0; extra == 'all'
|
|
45
|
+
Requires-Dist: twine>=6.2.0; extra == 'all'
|
|
46
|
+
Provides-Extra: db
|
|
47
|
+
Requires-Dist: sqlalchemy>=2.0.0; extra == 'db'
|
|
48
|
+
Provides-Extra: deep
|
|
49
|
+
Provides-Extra: dev
|
|
50
|
+
Requires-Dist: build>=1.4.0; extra == 'dev'
|
|
51
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
|
|
52
|
+
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
53
|
+
Requires-Dist: scikit-learn>=1.0.0; extra == 'dev'
|
|
54
|
+
Requires-Dist: twine>=6.2.0; extra == 'dev'
|
|
55
|
+
Provides-Extra: forecasting
|
|
56
|
+
Requires-Dist: sktime[forecasting]>=0.40.1; extra == 'forecasting'
|
|
57
|
+
Provides-Extra: hydra
|
|
58
|
+
Requires-Dist: hydra-core>=1.3.0; extra == 'hydra'
|
|
59
|
+
Requires-Dist: omegaconf>=2.3.0; extra == 'hydra'
|
|
60
|
+
Provides-Extra: transform
|
|
61
|
+
Requires-Dist: sktime>=0.27.0; extra == 'transform'
|
|
62
|
+
Description-Content-Type: text/markdown
|
|
63
|
+
|
|
64
|
+
# dfm-python
|
|
65
|
+
|
|
66
|
+
Dynamic factor models in Python.
|
|
67
|
+
|
|
68
|
+
- **DFM**: linear, mixed-frequency Dynamic Factor Model estimated by EM with
|
|
69
|
+
Kalman filtering and smoothing.
|
|
70
|
+
- **DDFM**: Deep Dynamic Factor Model with a nonlinear (PyTorch) encoder.
|
|
71
|
+
- **iVDFM**: Identifiable Variational Dynamic Factor Model.
|
|
72
|
+
- **AFM**: the Attention Factor Model of Epstein, Wang, Choi and Pelger (2025),
|
|
73
|
+
a cross-sectional conditional factor model whose residuals are traded
|
|
74
|
+
portfolios, with PCA and Avellaneda-Lee benchmarks.
|
|
75
|
+
|
|
76
|
+
Mixed frequencies are handled with a clock: latent factors evolve at one
|
|
77
|
+
frequency (for example monthly) and lower-frequency series load on them through
|
|
78
|
+
tent-kernel aggregation in the observation equation. Series faster than the
|
|
79
|
+
clock are not supported.
|
|
80
|
+
|
|
81
|
+
## Install
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
pip install dfm-python # or: uv add dfm-python
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Requires Python 3.10 or later; PyTorch is a required dependency.
|
|
88
|
+
|
|
89
|
+
## DFM
|
|
90
|
+
|
|
91
|
+
Pass preprocessed data; the model standardizes it internally.
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
import numpy as np
|
|
95
|
+
import pandas as pd
|
|
96
|
+
from dfm_python import DFM, DFMDataset
|
|
97
|
+
from dfm_python.config import DFMConfig
|
|
98
|
+
|
|
99
|
+
rng = np.random.default_rng(0)
|
|
100
|
+
cols = ["s0", "s1", "s2", "s3"]
|
|
101
|
+
df = pd.DataFrame(rng.standard_normal((120, 4)), columns=cols)
|
|
102
|
+
df["date"] = pd.date_range("2010-01-31", periods=120, freq="ME")
|
|
103
|
+
|
|
104
|
+
config = DFMConfig(
|
|
105
|
+
blocks={"global": {"num_factors": 1, "series": cols}},
|
|
106
|
+
frequency={c: "m" for c in cols},
|
|
107
|
+
clock="m",
|
|
108
|
+
max_iter=50,
|
|
109
|
+
)
|
|
110
|
+
dataset = DFMDataset(config=config, data=df, time_index="date")
|
|
111
|
+
model = DFM(dataset=dataset, config=config)
|
|
112
|
+
model.fit() # EM + Kalman smoother
|
|
113
|
+
X_forecast, Z_forecast = model.predict(horizon=6)
|
|
114
|
+
print(X_forecast.shape, Z_forecast.shape) # (6, 4) series, (6, state dim)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
`DDFM` (`from dfm_python import DDFM, DDFMDataset`) and `iVDFM`
|
|
118
|
+
(`from dfm_python.models.ivdfm import iVDFM`) follow the same
|
|
119
|
+
dataset-then-model pattern. Hydra YAML configurations for each model are in
|
|
120
|
+
[`config/`](https://github.com/minkeymouse/dfm-python/tree/main/config) and
|
|
121
|
+
end-to-end scripts in
|
|
122
|
+
[`tutorial/`](https://github.com/minkeymouse/dfm-python/tree/main/tutorial).
|
|
123
|
+
|
|
124
|
+
## AFM
|
|
125
|
+
|
|
126
|
+
AFM takes a returns panel `(T, N)` and, for learned attention factors, firm
|
|
127
|
+
characteristics `(T, N, M)`. It is trained on an after-cost Sharpe ratio plus an
|
|
128
|
+
explained-variance term (`lambda_var`).
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
import numpy as np
|
|
132
|
+
import torch
|
|
133
|
+
from dfm_python import AFM, AFMDataset
|
|
134
|
+
from dfm_python.models.afm.factors import residuals
|
|
135
|
+
|
|
136
|
+
rng = np.random.default_rng(0)
|
|
137
|
+
T, N, M = 120, 20, 8 # dates, assets, characteristics
|
|
138
|
+
returns = 0.01 * rng.standard_normal((T, N))
|
|
139
|
+
characteristics = rng.standard_normal((T, N, M))
|
|
140
|
+
|
|
141
|
+
ds = AFMDataset(returns=returns, characteristics=characteristics)
|
|
142
|
+
model = AFM(dataset=ds, n_factors=3, hist_len=20, max_epochs=20, seed=0)
|
|
143
|
+
model.fit()
|
|
144
|
+
|
|
145
|
+
out = model.predict()
|
|
146
|
+
out["residuals"].shape # (1, T, N) residual returns
|
|
147
|
+
out["weights"].shape # (1, T - hist_len, N) portfolio weights
|
|
148
|
+
out["book_returns"].shape # (1, T - hist_len) after-cost returns
|
|
149
|
+
result = model.get_result()
|
|
150
|
+
print(result.sharpe, result.explained_variance)
|
|
151
|
+
|
|
152
|
+
# Residuals from the fitted factor block directly
|
|
153
|
+
R, X = ds.get_tensors(model.device)
|
|
154
|
+
with torch.no_grad():
|
|
155
|
+
omega_f, beta_t = model.factor_block(X) # (T, K, N), (T, N, K)
|
|
156
|
+
eps = residuals(omega_f, beta_t, R) # (T, N)
|
|
157
|
+
|
|
158
|
+
# Benchmarks: PCA factors need no characteristics
|
|
159
|
+
pca = AFM(dataset=AFMDataset(returns=returns), n_factors=3, hist_len=20,
|
|
160
|
+
factor_model="pca", trading="ou") # or trading="longconv"
|
|
161
|
+
pca.fit()
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Layout
|
|
165
|
+
|
|
166
|
+
```
|
|
167
|
+
src/dfm_python/
|
|
168
|
+
models/ dfm/, ddfm/, ivdfm/, afm/ model classes
|
|
169
|
+
dataset/ DFMDataset, DDFMDataset, iVDFMDataset, AFMDataset
|
|
170
|
+
config/ model configs (DFMConfig, ..., AFMConfig), YAML adapter, results
|
|
171
|
+
ssm/ state-space form and Kalman filtering
|
|
172
|
+
functional/ EM algorithm
|
|
173
|
+
numeric/, layer/, utils/, logger/ shared numerics, network layers, helpers
|
|
174
|
+
src/test/ pytest suite
|
|
175
|
+
config/ example Hydra YAML configurations
|
|
176
|
+
tutorial/ end-to-end scripts per model and dataset
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Tests, from a clone: `uv sync --group dev && uv run pytest src/test -q`.
|
|
180
|
+
|
|
181
|
+
The paper repository [minkeymouse/nfe](https://github.com/minkeymouse/nfe) uses
|
|
182
|
+
AFM as a baseline.
|
|
183
|
+
|
|
184
|
+
## License
|
|
185
|
+
|
|
186
|
+
MIT. See [LICENSE](https://github.com/minkeymouse/dfm-python/blob/main/LICENSE).
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# dfm-python
|
|
2
|
+
|
|
3
|
+
Dynamic factor models in Python.
|
|
4
|
+
|
|
5
|
+
- **DFM**: linear, mixed-frequency Dynamic Factor Model estimated by EM with
|
|
6
|
+
Kalman filtering and smoothing.
|
|
7
|
+
- **DDFM**: Deep Dynamic Factor Model with a nonlinear (PyTorch) encoder.
|
|
8
|
+
- **iVDFM**: Identifiable Variational Dynamic Factor Model.
|
|
9
|
+
- **AFM**: the Attention Factor Model of Epstein, Wang, Choi and Pelger (2025),
|
|
10
|
+
a cross-sectional conditional factor model whose residuals are traded
|
|
11
|
+
portfolios, with PCA and Avellaneda-Lee benchmarks.
|
|
12
|
+
|
|
13
|
+
Mixed frequencies are handled with a clock: latent factors evolve at one
|
|
14
|
+
frequency (for example monthly) and lower-frequency series load on them through
|
|
15
|
+
tent-kernel aggregation in the observation equation. Series faster than the
|
|
16
|
+
clock are not supported.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pip install dfm-python # or: uv add dfm-python
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Requires Python 3.10 or later; PyTorch is a required dependency.
|
|
25
|
+
|
|
26
|
+
## DFM
|
|
27
|
+
|
|
28
|
+
Pass preprocessed data; the model standardizes it internally.
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
import numpy as np
|
|
32
|
+
import pandas as pd
|
|
33
|
+
from dfm_python import DFM, DFMDataset
|
|
34
|
+
from dfm_python.config import DFMConfig
|
|
35
|
+
|
|
36
|
+
rng = np.random.default_rng(0)
|
|
37
|
+
cols = ["s0", "s1", "s2", "s3"]
|
|
38
|
+
df = pd.DataFrame(rng.standard_normal((120, 4)), columns=cols)
|
|
39
|
+
df["date"] = pd.date_range("2010-01-31", periods=120, freq="ME")
|
|
40
|
+
|
|
41
|
+
config = DFMConfig(
|
|
42
|
+
blocks={"global": {"num_factors": 1, "series": cols}},
|
|
43
|
+
frequency={c: "m" for c in cols},
|
|
44
|
+
clock="m",
|
|
45
|
+
max_iter=50,
|
|
46
|
+
)
|
|
47
|
+
dataset = DFMDataset(config=config, data=df, time_index="date")
|
|
48
|
+
model = DFM(dataset=dataset, config=config)
|
|
49
|
+
model.fit() # EM + Kalman smoother
|
|
50
|
+
X_forecast, Z_forecast = model.predict(horizon=6)
|
|
51
|
+
print(X_forecast.shape, Z_forecast.shape) # (6, 4) series, (6, state dim)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`DDFM` (`from dfm_python import DDFM, DDFMDataset`) and `iVDFM`
|
|
55
|
+
(`from dfm_python.models.ivdfm import iVDFM`) follow the same
|
|
56
|
+
dataset-then-model pattern. Hydra YAML configurations for each model are in
|
|
57
|
+
[`config/`](https://github.com/minkeymouse/dfm-python/tree/main/config) and
|
|
58
|
+
end-to-end scripts in
|
|
59
|
+
[`tutorial/`](https://github.com/minkeymouse/dfm-python/tree/main/tutorial).
|
|
60
|
+
|
|
61
|
+
## AFM
|
|
62
|
+
|
|
63
|
+
AFM takes a returns panel `(T, N)` and, for learned attention factors, firm
|
|
64
|
+
characteristics `(T, N, M)`. It is trained on an after-cost Sharpe ratio plus an
|
|
65
|
+
explained-variance term (`lambda_var`).
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
import numpy as np
|
|
69
|
+
import torch
|
|
70
|
+
from dfm_python import AFM, AFMDataset
|
|
71
|
+
from dfm_python.models.afm.factors import residuals
|
|
72
|
+
|
|
73
|
+
rng = np.random.default_rng(0)
|
|
74
|
+
T, N, M = 120, 20, 8 # dates, assets, characteristics
|
|
75
|
+
returns = 0.01 * rng.standard_normal((T, N))
|
|
76
|
+
characteristics = rng.standard_normal((T, N, M))
|
|
77
|
+
|
|
78
|
+
ds = AFMDataset(returns=returns, characteristics=characteristics)
|
|
79
|
+
model = AFM(dataset=ds, n_factors=3, hist_len=20, max_epochs=20, seed=0)
|
|
80
|
+
model.fit()
|
|
81
|
+
|
|
82
|
+
out = model.predict()
|
|
83
|
+
out["residuals"].shape # (1, T, N) residual returns
|
|
84
|
+
out["weights"].shape # (1, T - hist_len, N) portfolio weights
|
|
85
|
+
out["book_returns"].shape # (1, T - hist_len) after-cost returns
|
|
86
|
+
result = model.get_result()
|
|
87
|
+
print(result.sharpe, result.explained_variance)
|
|
88
|
+
|
|
89
|
+
# Residuals from the fitted factor block directly
|
|
90
|
+
R, X = ds.get_tensors(model.device)
|
|
91
|
+
with torch.no_grad():
|
|
92
|
+
omega_f, beta_t = model.factor_block(X) # (T, K, N), (T, N, K)
|
|
93
|
+
eps = residuals(omega_f, beta_t, R) # (T, N)
|
|
94
|
+
|
|
95
|
+
# Benchmarks: PCA factors need no characteristics
|
|
96
|
+
pca = AFM(dataset=AFMDataset(returns=returns), n_factors=3, hist_len=20,
|
|
97
|
+
factor_model="pca", trading="ou") # or trading="longconv"
|
|
98
|
+
pca.fit()
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Layout
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
src/dfm_python/
|
|
105
|
+
models/ dfm/, ddfm/, ivdfm/, afm/ model classes
|
|
106
|
+
dataset/ DFMDataset, DDFMDataset, iVDFMDataset, AFMDataset
|
|
107
|
+
config/ model configs (DFMConfig, ..., AFMConfig), YAML adapter, results
|
|
108
|
+
ssm/ state-space form and Kalman filtering
|
|
109
|
+
functional/ EM algorithm
|
|
110
|
+
numeric/, layer/, utils/, logger/ shared numerics, network layers, helpers
|
|
111
|
+
src/test/ pytest suite
|
|
112
|
+
config/ example Hydra YAML configurations
|
|
113
|
+
tutorial/ end-to-end scripts per model and dataset
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Tests, from a clone: `uv sync --group dev && uv run pytest src/test -q`.
|
|
117
|
+
|
|
118
|
+
The paper repository [minkeymouse/nfe](https://github.com/minkeymouse/nfe) uses
|
|
119
|
+
AFM as a baseline.
|
|
120
|
+
|
|
121
|
+
## License
|
|
122
|
+
|
|
123
|
+
MIT. See [LICENSE](https://github.com/minkeymouse/dfm-python/blob/main/LICENSE).
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Attention Factor Model (Epstein et al., 2025) — finance / statistical arbitrage.
|
|
2
|
+
# Flat AFMConfig keys; loaded via AFMConfig.from_dict(OmegaConf.to_container(cfg)).
|
|
3
|
+
clock: d
|
|
4
|
+
scaler: null
|
|
5
|
+
|
|
6
|
+
# Factor / trading structure
|
|
7
|
+
num_factors: 5
|
|
8
|
+
factor_model: attention # 'attention' (learned) | 'pca' (benchmark)
|
|
9
|
+
trading: longconv # 'longconv' (learned) | 'ou' (Avellaneda-Lee)
|
|
10
|
+
|
|
11
|
+
# Architecture
|
|
12
|
+
embed_dim: 32 # characteristic embedding dimension d
|
|
13
|
+
hist_len: 20 # residual-history length s for the trading filter
|
|
14
|
+
n_kernels: 32 # number of long convolutions
|
|
15
|
+
ridge: 0.01 # ridge penalty for the closed-form loadings
|
|
16
|
+
|
|
17
|
+
# Objective and costs (paper values: 5bps turnover, 1bp shorting)
|
|
18
|
+
lambda_var: 0.1
|
|
19
|
+
turnover_cost: 0.0005
|
|
20
|
+
short_cost: 0.0001
|
|
21
|
+
risk_free: 0.0
|
|
22
|
+
|
|
23
|
+
# Training
|
|
24
|
+
learning_rate: 0.001
|
|
25
|
+
max_epochs: 50
|
|
26
|
+
patience: 10
|
|
27
|
+
seed: 0
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "dfm-python"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.7.0"
|
|
4
4
|
description = "Dynamic Factor Model (DFM) estimation and forecasting in Python"
|
|
5
|
+
readme = "README.md"
|
|
5
6
|
requires-python = ">=3.10"
|
|
6
7
|
license = {text = "MIT"}
|
|
7
8
|
authors = [
|
|
@@ -16,14 +17,15 @@ classifiers = [
|
|
|
16
17
|
"Programming Language :: Python :: 3.10",
|
|
17
18
|
"Programming Language :: Python :: 3.11",
|
|
18
19
|
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"Programming Language :: Python :: 3.13",
|
|
19
21
|
"Topic :: Scientific/Engineering",
|
|
20
22
|
]
|
|
21
23
|
dependencies = [
|
|
22
|
-
"build>=1.4.0",
|
|
23
24
|
"einops>=0.8.1",
|
|
24
25
|
"hydra-core>=1.3.2",
|
|
25
26
|
"matplotlib>=3.5.0",
|
|
26
27
|
"numpy>=1.24.0",
|
|
28
|
+
"optuna>=4.7.0",
|
|
27
29
|
"pandas>=2.0.0",
|
|
28
30
|
"pyarrow>=22.0.0",
|
|
29
31
|
"pykalman>=0.11.0",
|
|
@@ -32,7 +34,6 @@ dependencies = [
|
|
|
32
34
|
"scipy>=1.10.0",
|
|
33
35
|
"sktime>=0.40.1",
|
|
34
36
|
"torch>=2.0.0",
|
|
35
|
-
"twine>=6.2.0",
|
|
36
37
|
]
|
|
37
38
|
|
|
38
39
|
[project.optional-dependencies]
|
|
@@ -58,6 +59,8 @@ dev = [
|
|
|
58
59
|
"pytest>=7.0.0",
|
|
59
60
|
"pytest-cov>=4.0.0",
|
|
60
61
|
"scikit-learn>=1.0.0",
|
|
62
|
+
"build>=1.4.0",
|
|
63
|
+
"twine>=6.2.0",
|
|
61
64
|
]
|
|
62
65
|
all = [
|
|
63
66
|
"dfm-python[hydra,db,dev,deep,transform]",
|
|
@@ -83,7 +86,8 @@ packages = [
|
|
|
83
86
|
exclude = [
|
|
84
87
|
"test_venv",
|
|
85
88
|
"test_venv/**",
|
|
86
|
-
"
|
|
89
|
+
"data/**",
|
|
90
|
+
"uv.lock",
|
|
87
91
|
]
|
|
88
92
|
|
|
89
93
|
[dependency-groups]
|
|
@@ -92,7 +96,7 @@ dev = [
|
|
|
92
96
|
]
|
|
93
97
|
|
|
94
98
|
[project.urls]
|
|
95
|
-
Homepage = "https://github.com/
|
|
96
|
-
Documentation = "https://github.com/
|
|
97
|
-
Repository = "https://github.com/
|
|
98
|
-
Issues = "https://github.com/
|
|
99
|
+
Homepage = "https://github.com/minkeymouse/dfm-python"
|
|
100
|
+
Documentation = "https://github.com/minkeymouse/dfm-python#readme"
|
|
101
|
+
Repository = "https://github.com/minkeymouse/dfm-python"
|
|
102
|
+
Issues = "https://github.com/minkeymouse/dfm-python/issues"
|
|
@@ -63,7 +63,7 @@ Note: DFMConfig uses frequency dict to specify series (column names -> frequenci
|
|
|
63
63
|
For detailed documentation, see the README.md file and the tutorial notebooks/scripts.
|
|
64
64
|
"""
|
|
65
65
|
|
|
66
|
-
__version__ = "0.
|
|
66
|
+
__version__ = "0.7.0"
|
|
67
67
|
|
|
68
68
|
# ============================================================================
|
|
69
69
|
# PUBLIC API DEFINITION
|
|
@@ -98,6 +98,7 @@ from .utils.metric import calculate_rmse
|
|
|
98
98
|
# Users can import these directly from dfm_python
|
|
99
99
|
from .dataset.dfm_dataset import DFMDataset
|
|
100
100
|
from .dataset.ddfm_dataset import DDFMDataset
|
|
101
|
+
from .dataset.afm_dataset import AFMDataset
|
|
101
102
|
|
|
102
103
|
# Model implementations
|
|
103
104
|
from .models.base import BaseFactorModel
|
|
@@ -109,6 +110,12 @@ try:
|
|
|
109
110
|
except ImportError:
|
|
110
111
|
DDFM = None
|
|
111
112
|
|
|
113
|
+
# AFM high-level API (Attention Factor Model; PyTorch is mandatory)
|
|
114
|
+
try:
|
|
115
|
+
from .models.afm.afm import AFM
|
|
116
|
+
except ImportError:
|
|
117
|
+
AFM = None
|
|
118
|
+
|
|
112
119
|
__all__ = [
|
|
113
120
|
# Core classes
|
|
114
121
|
'DFM',
|
|
@@ -121,14 +128,16 @@ __all__ = [
|
|
|
121
128
|
'BaseResult', 'DFMResult', 'DDFMResult', 'calculate_rmse',
|
|
122
129
|
]
|
|
123
130
|
|
|
124
|
-
# DDFM high-level API (PyTorch is mandatory)
|
|
131
|
+
# DDFM / AFM high-level API (PyTorch is mandatory)
|
|
125
132
|
__all__.extend([
|
|
126
133
|
'DDFM', # High-level API class
|
|
134
|
+
'AFM', # Attention Factor Model
|
|
127
135
|
])
|
|
128
136
|
|
|
129
137
|
# Dataset classes
|
|
130
138
|
__all__.extend([
|
|
131
139
|
'DFMDataset', # DFM Dataset class
|
|
132
140
|
'DDFMDataset', # DDFM Dataset class
|
|
141
|
+
'AFMDataset', # AFM Dataset class
|
|
133
142
|
])
|
|
134
143
|
|
|
@@ -8,9 +8,9 @@ Note: Series are specified via frequency dict mapping column names to frequencie
|
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
from .schema import (
|
|
11
|
-
BaseModelConfig, DFMConfig, DDFMConfig,
|
|
12
|
-
BaseResult, DFMResult, DDFMResult,
|
|
13
|
-
DFMStateSpaceParams, DDFMStateSpaceParams,
|
|
11
|
+
BaseModelConfig, DFMConfig, DDFMConfig, AFMConfig,
|
|
12
|
+
BaseResult, DFMResult, DDFMResult, AFMResult,
|
|
13
|
+
DFMStateSpaceParams, DDFMStateSpaceParams, AFMModelState,
|
|
14
14
|
)
|
|
15
15
|
# DEFAULT_BLOCK_NAME is imported lazily where needed to avoid circular imports
|
|
16
16
|
from .constants import (
|
|
@@ -97,11 +97,11 @@ __all__ = [
|
|
|
97
97
|
'BaseModelConfig', 'BaseResult',
|
|
98
98
|
# 'DEFAULT_BLOCK_NAME', # Removed to avoid circular import
|
|
99
99
|
# Model-specific configs (from schema.py)
|
|
100
|
-
'DFMConfig', 'DDFMConfig',
|
|
100
|
+
'DFMConfig', 'DDFMConfig', 'AFMConfig',
|
|
101
101
|
# State-space parameters
|
|
102
|
-
'DFMStateSpaceParams', 'DDFMStateSpaceParams',
|
|
102
|
+
'DFMStateSpaceParams', 'DDFMStateSpaceParams', 'AFMModelState',
|
|
103
103
|
# Model-specific results (from results.py)
|
|
104
|
-
'DFMResult', 'DDFMResult',
|
|
104
|
+
'DFMResult', 'DDFMResult', 'AFMResult',
|
|
105
105
|
# Utilities
|
|
106
106
|
'validate_frequency',
|
|
107
107
|
# IO
|
|
@@ -348,18 +348,23 @@ DEFAULT_KDFM_MA_ORDER = 0 # Default MA order (MA lag order q) for KDFM (0 = pur
|
|
|
348
348
|
# iVDFM Defaults
|
|
349
349
|
# ============================================================================
|
|
350
350
|
|
|
351
|
-
# iVDFM
|
|
352
|
-
DEFAULT_IVDFM_SEQUENCE_LENGTH = 100 # Default sequence length for sliding windows
|
|
351
|
+
# iVDFM dimension defaults
|
|
353
352
|
DEFAULT_IVDFM_LATENT_DIM = 3 # Default number of factors
|
|
354
353
|
DEFAULT_IVDFM_AUX_DIM = 1 # Default auxiliary variable dimension
|
|
355
354
|
|
|
355
|
+
# iVDFM regime (K=1 = baseline iVDFM, no regime structure)
|
|
356
|
+
DEFAULT_IVDFM_NUM_REGIMES = 1 # Number of discrete regimes; 1 = baseline iVDFM
|
|
357
|
+
DEFAULT_IVDFM_REGIME_TEMPERATURE = 1.0 # Softmax temperature for π; τ < 1 sharpens (local commitment)
|
|
358
|
+
DEFAULT_IVDFM_MIXING = False # If True, apply global post-factor mixing f -> M f (identity init) before decode
|
|
359
|
+
|
|
356
360
|
# iVDFM network architecture defaults
|
|
357
361
|
DEFAULT_IVDFM_ENCODER_HIDDEN_DIM = 200 # Default encoder hidden dimension
|
|
358
|
-
|
|
362
|
+
DEFAULT_IVDFM_ENCODER_N_HIDDEN_LAYERS = 2 # Default encoder hidden layers
|
|
363
|
+
DEFAULT_IVDFM_DECODER_TYPE = "mlp" # Default: 'linear', 'residual', or 'mlp' (mlp = current behavior)
|
|
359
364
|
DEFAULT_IVDFM_DECODER_HIDDEN_DIM = 200 # Default decoder hidden dimension
|
|
360
|
-
|
|
365
|
+
DEFAULT_IVDFM_DECODER_N_HIDDEN_LAYERS = 2 # Default decoder hidden layers
|
|
361
366
|
DEFAULT_IVDFM_PRIOR_HIDDEN_DIM = 100 # Default prior network hidden dimension
|
|
362
|
-
|
|
367
|
+
DEFAULT_IVDFM_PRIOR_N_HIDDEN_LAYERS = 1 # Default prior network hidden layers
|
|
363
368
|
|
|
364
369
|
# iVDFM dynamics and distribution defaults
|
|
365
370
|
DEFAULT_IVDFM_FACTOR_ORDER = 1 # Default AR order for factors
|
|
@@ -384,6 +389,7 @@ DEFAULT_IVDFM_SCHEDULER_GAMMA = 0.5 # Default gamma for StepLR/ExponentialLR
|
|
|
384
389
|
DEFAULT_IVDFM_SCHEDULER_PATIENCE = 10 # Default patience for ReduceLROnPlateau
|
|
385
390
|
DEFAULT_IVDFM_SCHEDULER_FACTOR = 0.1 # Default factor for ReduceLROnPlateau
|
|
386
391
|
DEFAULT_IVDFM_SCHEDULER_MIN_LR = 0.0 # Default min_lr for ReduceLROnPlateau
|
|
392
|
+
DEFAULT_IVDFM_EARLY_STOP_PATIENCE = 20 # Default patience for early stopping (epochs without improvement)
|
|
387
393
|
|
|
388
394
|
# ============================================================================
|
|
389
395
|
# Tutorial Defaults
|
|
@@ -451,11 +457,35 @@ FREQUENCY_HIERARCHY: Dict[str, int] = {
|
|
|
451
457
|
# For frequency gaps larger than this, the missing data approach is used instead
|
|
452
458
|
MAX_TENT_SIZE: int = 12
|
|
453
459
|
|
|
460
|
+
# ============================================================================
|
|
461
|
+
# AFM (Attention Factor Model) defaults
|
|
462
|
+
# ============================================================================
|
|
463
|
+
DEFAULT_AFM_NUM_FACTORS = 5 # K latent factors
|
|
464
|
+
DEFAULT_AFM_FACTOR_MODEL = 'attention' # 'attention' | 'pca'
|
|
465
|
+
DEFAULT_AFM_TRADING = 'longconv' # 'longconv' | 'ou'
|
|
466
|
+
DEFAULT_AFM_EMBED_DIM = 32 # characteristic embedding dimension d
|
|
467
|
+
DEFAULT_AFM_HIST_LEN = 20 # residual-history length s for the filter
|
|
468
|
+
DEFAULT_AFM_N_KERNELS = 32 # number of long convolutions
|
|
469
|
+
DEFAULT_AFM_RIDGE = 1e-2 # ridge penalty for closed-form loadings
|
|
470
|
+
DEFAULT_AFM_SQUASH_LAMBDA = 1e-3 # LongConv Squash kernel regularizer strength
|
|
471
|
+
DEFAULT_AFM_PCA_WINDOW = 252 # trailing window for the PCA benchmark
|
|
472
|
+
DEFAULT_AFM_REESTIM = 21 # PCA re-estimation stride
|
|
473
|
+
DEFAULT_AFM_LAMBDA_VAR = 0.1 # explained-variance regularizer weight
|
|
474
|
+
DEFAULT_AFM_TURNOVER_COST = 5e-4 # 5bps per unit turnover (paper)
|
|
475
|
+
DEFAULT_AFM_SHORT_COST = 1e-4 # 1bp shorting cost (paper)
|
|
476
|
+
DEFAULT_AFM_MAX_EPOCHS = 50 # training epochs
|
|
477
|
+
|
|
454
478
|
# ============================================================================
|
|
455
479
|
# Export all constants
|
|
456
480
|
# ============================================================================
|
|
457
481
|
|
|
458
482
|
__all__ = [
|
|
483
|
+
# AFM
|
|
484
|
+
'DEFAULT_AFM_NUM_FACTORS', 'DEFAULT_AFM_FACTOR_MODEL', 'DEFAULT_AFM_TRADING',
|
|
485
|
+
'DEFAULT_AFM_EMBED_DIM', 'DEFAULT_AFM_HIST_LEN', 'DEFAULT_AFM_N_KERNELS',
|
|
486
|
+
'DEFAULT_AFM_RIDGE', 'DEFAULT_AFM_SQUASH_LAMBDA', 'DEFAULT_AFM_PCA_WINDOW',
|
|
487
|
+
'DEFAULT_AFM_REESTIM', 'DEFAULT_AFM_LAMBDA_VAR', 'DEFAULT_AFM_TURNOVER_COST',
|
|
488
|
+
'DEFAULT_AFM_SHORT_COST', 'DEFAULT_AFM_MAX_EPOCHS',
|
|
459
489
|
# Convergence
|
|
460
490
|
'DEFAULT_CONVERGENCE_THRESHOLD',
|
|
461
491
|
'DEFAULT_EM_THRESHOLD',
|
|
@@ -606,15 +636,16 @@ __all__ = [
|
|
|
606
636
|
'DEFAULT_KDFM_AR_ORDER',
|
|
607
637
|
'DEFAULT_KDFM_MA_ORDER',
|
|
608
638
|
# iVDFM defaults
|
|
609
|
-
'DEFAULT_IVDFM_SEQUENCE_LENGTH',
|
|
610
639
|
'DEFAULT_IVDFM_LATENT_DIM',
|
|
611
640
|
'DEFAULT_IVDFM_AUX_DIM',
|
|
612
641
|
'DEFAULT_IVDFM_ENCODER_HIDDEN_DIM',
|
|
613
|
-
'
|
|
642
|
+
'DEFAULT_IVDFM_ENCODER_N_HIDDEN_LAYERS',
|
|
643
|
+
'DEFAULT_IVDFM_NUM_REGIMES',
|
|
644
|
+
'DEFAULT_IVDFM_DECODER_TYPE',
|
|
614
645
|
'DEFAULT_IVDFM_DECODER_HIDDEN_DIM',
|
|
615
|
-
'
|
|
646
|
+
'DEFAULT_IVDFM_DECODER_N_HIDDEN_LAYERS',
|
|
616
647
|
'DEFAULT_IVDFM_PRIOR_HIDDEN_DIM',
|
|
617
|
-
'
|
|
648
|
+
'DEFAULT_IVDFM_PRIOR_N_HIDDEN_LAYERS',
|
|
618
649
|
'DEFAULT_IVDFM_FACTOR_ORDER',
|
|
619
650
|
'DEFAULT_IVDFM_INNOVATION_DIST',
|
|
620
651
|
'DEFAULT_IVDFM_DECODER_VAR',
|
|
@@ -7,13 +7,13 @@ This package contains:
|
|
|
7
7
|
Note: Series are specified via frequency dict mapping column names to frequencies.
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
|
-
from .model import BaseModelConfig, DFMConfig, DDFMConfig, iVDFMConfig
|
|
11
|
-
from .results import BaseResult, DFMResult, DDFMResult, iVDFMResult
|
|
12
|
-
from .params import DFMStateSpaceParams, DDFMStateSpaceParams, iVDFMModelState
|
|
10
|
+
from .model import BaseModelConfig, DFMConfig, DDFMConfig, iVDFMConfig, AFMConfig
|
|
11
|
+
from .results import BaseResult, DFMResult, DDFMResult, iVDFMResult, AFMResult
|
|
12
|
+
from .params import DFMStateSpaceParams, DDFMStateSpaceParams, iVDFMModelState, AFMModelState
|
|
13
13
|
|
|
14
14
|
__all__ = [
|
|
15
|
-
'BaseModelConfig', 'DFMConfig', 'DDFMConfig', 'iVDFMConfig',
|
|
16
|
-
'BaseResult', 'DFMResult', 'DDFMResult', 'iVDFMResult',
|
|
17
|
-
'DFMStateSpaceParams', 'DDFMStateSpaceParams', 'iVDFMModelState',
|
|
15
|
+
'BaseModelConfig', 'DFMConfig', 'DDFMConfig', 'iVDFMConfig', 'AFMConfig',
|
|
16
|
+
'BaseResult', 'DFMResult', 'DDFMResult', 'iVDFMResult', 'AFMResult',
|
|
17
|
+
'DFMStateSpaceParams', 'DDFMStateSpaceParams', 'iVDFMModelState', 'AFMModelState',
|
|
18
18
|
]
|
|
19
19
|
|