pymgarch 0.1.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.
Files changed (36) hide show
  1. pymgarch-0.1.0/.github/workflows/python-publish.yml +86 -0
  2. pymgarch-0.1.0/.gitignore +30 -0
  3. pymgarch-0.1.0/.readthedocs.yaml +15 -0
  4. pymgarch-0.1.0/LICENSE +21 -0
  5. pymgarch-0.1.0/PKG-INFO +107 -0
  6. pymgarch-0.1.0/README.md +88 -0
  7. pymgarch-0.1.0/docs/api.md +40 -0
  8. pymgarch-0.1.0/docs/conf.py +26 -0
  9. pymgarch-0.1.0/docs/index.md +27 -0
  10. pymgarch-0.1.0/docs/inference.md +53 -0
  11. pymgarch-0.1.0/docs/models.md +62 -0
  12. pymgarch-0.1.0/docs/quickstart.md +61 -0
  13. pymgarch-0.1.0/docs/requirements.txt +7 -0
  14. pymgarch-0.1.0/pyproject.toml +63 -0
  15. pymgarch-0.1.0/scripts/make_fixtures.R +68 -0
  16. pymgarch-0.1.0/src/pymgarch/__init__.py +22 -0
  17. pymgarch-0.1.0/src/pymgarch/_kernels.py +151 -0
  18. pymgarch-0.1.0/src/pymgarch/_version.py +24 -0
  19. pymgarch-0.1.0/src/pymgarch/correlation.py +95 -0
  20. pymgarch-0.1.0/src/pymgarch/distributions.py +48 -0
  21. pymgarch-0.1.0/src/pymgarch/estimation.py +149 -0
  22. pymgarch-0.1.0/src/pymgarch/inference.py +200 -0
  23. pymgarch-0.1.0/src/pymgarch/marginals.py +246 -0
  24. pymgarch-0.1.0/src/pymgarch/models.py +251 -0
  25. pymgarch-0.1.0/src/pymgarch/results.py +353 -0
  26. pymgarch-0.1.0/tests/conftest.py +73 -0
  27. pymgarch-0.1.0/tests/fixtures/dji30ret_5.csv +1001 -0
  28. pymgarch-0.1.0/tests/fixtures/rmgarch_fixtures.json +1 -0
  29. pymgarch-0.1.0/tests/test_forecast_filter.py +78 -0
  30. pymgarch-0.1.0/tests/test_inference.py +25 -0
  31. pymgarch-0.1.0/tests/test_kernels.py +70 -0
  32. pymgarch-0.1.0/tests/test_marginals.py +59 -0
  33. pymgarch-0.1.0/tests/test_models.py +100 -0
  34. pymgarch-0.1.0/tests/test_numba.py +27 -0
  35. pymgarch-0.1.0/tests/test_replication.py +102 -0
  36. pymgarch-0.1.0/uv.lock +2170 -0
@@ -0,0 +1,86 @@
1
+ # .github/workflows/python-publish.yml
2
+ name: pymgarch CI/CD
3
+
4
+ on:
5
+ push:
6
+ branches: [main]
7
+ tags: ["v*"]
8
+ pull_request:
9
+ branches: [main]
10
+
11
+ permissions:
12
+ contents: read
13
+
14
+ jobs:
15
+ test:
16
+ runs-on: ubuntu-latest
17
+ strategy:
18
+ matrix:
19
+ python-version: ["3.11", "3.13"]
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+ with:
23
+ fetch-depth: 0 # full history for hatch-vcs
24
+
25
+ - name: Install uv
26
+ uses: astral-sh/setup-uv@v5
27
+
28
+ - name: Setup Python
29
+ uses: actions/setup-python@v5
30
+ with:
31
+ python-version: ${{ matrix.python-version }}
32
+
33
+ - name: Install dependencies
34
+ run: uv sync --dev --extra numba
35
+
36
+ - name: Run tests
37
+ run: uv run pytest tests/ -v --cov=src/pymgarch --cov-report=xml
38
+
39
+ - name: Upload coverage to Codecov
40
+ uses: codecov/codecov-action@v5
41
+ with:
42
+ token: ${{ secrets.CODECOV_TOKEN }}
43
+ files: coverage.xml
44
+ fail_ci_if_error: false
45
+
46
+ release:
47
+ if: startsWith(github.ref, 'refs/tags/v')
48
+ needs: test
49
+ runs-on: ubuntu-latest
50
+ permissions:
51
+ contents: write
52
+ steps:
53
+ - uses: actions/checkout@v4
54
+
55
+ - name: Create GitHub Release
56
+ # --notes-from-tag publishes the annotated tag message as the release
57
+ # notes (--generate-notes only summarises PRs, which direct pushes lack);
58
+ # explicit --title keeps the release title to the bare tag name
59
+ run: gh release create "${{ github.ref_name }}" --notes-from-tag --title "${{ github.ref_name }}"
60
+ env:
61
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
62
+
63
+ deploy:
64
+ if: startsWith(github.ref, 'refs/tags/v')
65
+ needs: [test, release]
66
+ runs-on: ubuntu-latest
67
+ environment: pypi
68
+ permissions:
69
+ id-token: write
70
+ steps:
71
+ - uses: actions/checkout@v4
72
+ with:
73
+ fetch-depth: 0 # full history for hatch-vcs
74
+
75
+ - name: Setup Python
76
+ uses: actions/setup-python@v5
77
+ with:
78
+ python-version: "3.13"
79
+
80
+ - name: Build
81
+ run: |
82
+ pip install build hatch-vcs
83
+ python -m build
84
+
85
+ - name: Publish to PyPI
86
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,30 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ .venv/
8
+ .python-version
9
+
10
+ # Generated version file
11
+ src/pymgarch/_version.py
12
+
13
+ # Tooling caches
14
+ .pytest_cache/
15
+ .ruff_cache/
16
+ .mypy_cache/
17
+ .hypothesis/
18
+ .coverage
19
+ coverage.xml
20
+
21
+ # Docs build
22
+ docs/_build/
23
+
24
+ # IDE
25
+ .idea/
26
+ .vscode/
27
+
28
+ # Local project settings
29
+ .claude/settings.local.json
30
+ uv.lock.orig
@@ -0,0 +1,15 @@
1
+ version: 2
2
+
3
+ build:
4
+ os: ubuntu-24.04
5
+ tools:
6
+ python: "3.13"
7
+
8
+ sphinx:
9
+ configuration: docs/conf.py
10
+
11
+ python:
12
+ install:
13
+ - requirements: docs/requirements.txt
14
+ - method: pip
15
+ path: .
pymgarch-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Marwin Steiner
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,107 @@
1
+ Metadata-Version: 2.5
2
+ Name: pymgarch
3
+ Version: 0.1.0
4
+ Summary: Multivariate GARCH for Python: DCC, ADCC, CCC on top of arch marginals, validated against rmgarch/tsmarch.
5
+ Project-URL: Documentation, https://pymgarch.readthedocs.io
6
+ Project-URL: Repository, https://github.com/marwinsteiner/pymgarch
7
+ Project-URL: Issues, https://github.com/marwinsteiner/pymgarch/issues
8
+ Author: Marwin Steiner
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Requires-Python: >=3.11
12
+ Requires-Dist: arch>=7.0
13
+ Requires-Dist: numpy>=1.26
14
+ Requires-Dist: pandas>=2.0
15
+ Requires-Dist: scipy>=1.11
16
+ Provides-Extra: numba
17
+ Requires-Dist: numba>=0.59; extra == 'numba'
18
+ Description-Content-Type: text/markdown
19
+
20
+ # pymgarch
21
+
22
+ [![CI/CD](https://github.com/marwinsteiner/pymgarch/actions/workflows/python-publish.yml/badge.svg)](https://github.com/marwinsteiner/pymgarch/actions/workflows/python-publish.yml)
23
+ [![PyPI](https://img.shields.io/pypi/v/pymgarch)](https://pypi.org/project/pymgarch/)
24
+ [![Python](https://img.shields.io/pypi/pyversions/pymgarch)](https://pypi.org/project/pymgarch/)
25
+ [![Downloads](https://static.pepy.tech/badge/pymgarch)](https://pepy.tech/project/pymgarch)
26
+ [![codecov](https://codecov.io/gh/marwinsteiner/pymgarch/branch/main/graph/badge.svg)](https://codecov.io/gh/marwinsteiner/pymgarch)
27
+ [![Docs](https://readthedocs.org/projects/pymgarch/badge/?version=latest)](https://pymgarch.readthedocs.io)
28
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
29
+
30
+ Multivariate GARCH for Python: DCC, ADCC, and CCC correlation dynamics built
31
+ on top of [arch](https://github.com/bashtage/arch) univariate marginals,
32
+ validated against R's rmgarch/tsmarch.
33
+
34
+ ## Why
35
+
36
+ Python has no maintained general-purpose multivariate GARCH framework. The
37
+ existing packages cover Gaussian DCC(1,1) at most, while R users have had
38
+ DCC, ADCC, GO-GARCH and copula-GARCH in rmgarch (now tsmarch) for a decade.
39
+ pymgarch closes that gap incrementally, starting with the correlation layer:
40
+
41
+ - stage 1 (univariate volatility) is delegated to `arch`, the ecosystem's
42
+ dominant, battle-tested GARCH package;
43
+ - stage 2 (correlation dynamics) is what this library implements, with
44
+ correct two-stage Engle-Sheppard standard errors and replication tests
45
+ against rmgarch's fitted parameters and likelihoods.
46
+
47
+ ## Install
48
+
49
+ ```
50
+ pip install pymgarch # or: pip install pymgarch[numba]
51
+ ```
52
+
53
+ The optional `numba` extra JIT-compiles the correlation recursions; without
54
+ it everything runs in pure NumPy.
55
+
56
+ ## Quickstart
57
+
58
+ ```python
59
+ import pymgarch as mg
60
+
61
+ # returns: (T, N) DataFrame, percent scale recommended
62
+ res = mg.DCC(dist="t").fit(returns)
63
+ print(res.summary())
64
+
65
+ res.conditional_correlations # (T, N, N)
66
+ res.conditional_covariances # (T, N, N)
67
+
68
+ fc = res.forecast(horizon=10) # analytic
69
+ fc = res.forecast(horizon=10, method="simulation", n_paths=2000)
70
+ flt = res.filter(new_returns) # fixed params, new data
71
+ ```
72
+
73
+ Marginals default to constant-mean GARCH(1,1). Customize per-column via a
74
+ spec, or bring your own fitted arch results:
75
+
76
+ ```python
77
+ spec = mg.UnivariateSpec(vol="GARCH", p=1, o=1, q=1, dist="t") # GJR-t
78
+ res = mg.ADCC().fit(returns, marginals=spec)
79
+
80
+ from arch import arch_model
81
+ fitted = [arch_model(returns[c], rescale=False).fit(disp="off") for c in returns]
82
+ res = mg.DCC().fit(returns, marginals=fitted)
83
+ ```
84
+
85
+ ## Models (v0.1)
86
+
87
+ | Model | Distribution | Estimation |
88
+ | ----- | ------------ | ---------- |
89
+ | CCC (Bollerslev 1990) | Gaussian | closed form given marginals |
90
+ | DCC(1,1) (Engle 2002) | Gaussian, Student-t | two-stage QML, correlation targeting |
91
+ | ADCC (Cappiello-Engle-Sheppard 2006) | Gaussian, Student-t | two-stage QML, PSD-constrained targeting |
92
+
93
+ Standard errors are Engle-Sheppard (2001) two-stage sandwich estimates: the
94
+ marginal and correlation scores are stacked so stage-2 uncertainty reflects
95
+ stage-1 estimation error. Correlation targets are held fixed (same
96
+ approximation rmgarch makes). If the stacked system is singular the library
97
+ falls back to a stage-2-only sandwich and says so in `summary()`.
98
+
99
+ ## Roadmap
100
+
101
+ - v0.2: GO-GARCH via ICA
102
+ - v0.3: copula-GARCH (Gaussian and Student-t copulas)
103
+ - v0.4: composite likelihood for large cross-sections, scalar/diagonal BEKK
104
+
105
+ ## License
106
+
107
+ MIT
@@ -0,0 +1,88 @@
1
+ # pymgarch
2
+
3
+ [![CI/CD](https://github.com/marwinsteiner/pymgarch/actions/workflows/python-publish.yml/badge.svg)](https://github.com/marwinsteiner/pymgarch/actions/workflows/python-publish.yml)
4
+ [![PyPI](https://img.shields.io/pypi/v/pymgarch)](https://pypi.org/project/pymgarch/)
5
+ [![Python](https://img.shields.io/pypi/pyversions/pymgarch)](https://pypi.org/project/pymgarch/)
6
+ [![Downloads](https://static.pepy.tech/badge/pymgarch)](https://pepy.tech/project/pymgarch)
7
+ [![codecov](https://codecov.io/gh/marwinsteiner/pymgarch/branch/main/graph/badge.svg)](https://codecov.io/gh/marwinsteiner/pymgarch)
8
+ [![Docs](https://readthedocs.org/projects/pymgarch/badge/?version=latest)](https://pymgarch.readthedocs.io)
9
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
10
+
11
+ Multivariate GARCH for Python: DCC, ADCC, and CCC correlation dynamics built
12
+ on top of [arch](https://github.com/bashtage/arch) univariate marginals,
13
+ validated against R's rmgarch/tsmarch.
14
+
15
+ ## Why
16
+
17
+ Python has no maintained general-purpose multivariate GARCH framework. The
18
+ existing packages cover Gaussian DCC(1,1) at most, while R users have had
19
+ DCC, ADCC, GO-GARCH and copula-GARCH in rmgarch (now tsmarch) for a decade.
20
+ pymgarch closes that gap incrementally, starting with the correlation layer:
21
+
22
+ - stage 1 (univariate volatility) is delegated to `arch`, the ecosystem's
23
+ dominant, battle-tested GARCH package;
24
+ - stage 2 (correlation dynamics) is what this library implements, with
25
+ correct two-stage Engle-Sheppard standard errors and replication tests
26
+ against rmgarch's fitted parameters and likelihoods.
27
+
28
+ ## Install
29
+
30
+ ```
31
+ pip install pymgarch # or: pip install pymgarch[numba]
32
+ ```
33
+
34
+ The optional `numba` extra JIT-compiles the correlation recursions; without
35
+ it everything runs in pure NumPy.
36
+
37
+ ## Quickstart
38
+
39
+ ```python
40
+ import pymgarch as mg
41
+
42
+ # returns: (T, N) DataFrame, percent scale recommended
43
+ res = mg.DCC(dist="t").fit(returns)
44
+ print(res.summary())
45
+
46
+ res.conditional_correlations # (T, N, N)
47
+ res.conditional_covariances # (T, N, N)
48
+
49
+ fc = res.forecast(horizon=10) # analytic
50
+ fc = res.forecast(horizon=10, method="simulation", n_paths=2000)
51
+ flt = res.filter(new_returns) # fixed params, new data
52
+ ```
53
+
54
+ Marginals default to constant-mean GARCH(1,1). Customize per-column via a
55
+ spec, or bring your own fitted arch results:
56
+
57
+ ```python
58
+ spec = mg.UnivariateSpec(vol="GARCH", p=1, o=1, q=1, dist="t") # GJR-t
59
+ res = mg.ADCC().fit(returns, marginals=spec)
60
+
61
+ from arch import arch_model
62
+ fitted = [arch_model(returns[c], rescale=False).fit(disp="off") for c in returns]
63
+ res = mg.DCC().fit(returns, marginals=fitted)
64
+ ```
65
+
66
+ ## Models (v0.1)
67
+
68
+ | Model | Distribution | Estimation |
69
+ | ----- | ------------ | ---------- |
70
+ | CCC (Bollerslev 1990) | Gaussian | closed form given marginals |
71
+ | DCC(1,1) (Engle 2002) | Gaussian, Student-t | two-stage QML, correlation targeting |
72
+ | ADCC (Cappiello-Engle-Sheppard 2006) | Gaussian, Student-t | two-stage QML, PSD-constrained targeting |
73
+
74
+ Standard errors are Engle-Sheppard (2001) two-stage sandwich estimates: the
75
+ marginal and correlation scores are stacked so stage-2 uncertainty reflects
76
+ stage-1 estimation error. Correlation targets are held fixed (same
77
+ approximation rmgarch makes). If the stacked system is singular the library
78
+ falls back to a stage-2-only sandwich and says so in `summary()`.
79
+
80
+ ## Roadmap
81
+
82
+ - v0.2: GO-GARCH via ICA
83
+ - v0.3: copula-GARCH (Gaussian and Student-t copulas)
84
+ - v0.4: composite likelihood for large cross-sections, scalar/diagonal BEKK
85
+
86
+ ## License
87
+
88
+ MIT
@@ -0,0 +1,40 @@
1
+ # API reference
2
+
3
+ ## Models
4
+
5
+ ```{eval-rst}
6
+ .. autoclass:: pymgarch.DCC
7
+ :members:
8
+
9
+ .. autoclass:: pymgarch.ADCC
10
+ :members:
11
+
12
+ .. autoclass:: pymgarch.CCC
13
+ :members:
14
+ ```
15
+
16
+ ## Marginals
17
+
18
+ ```{eval-rst}
19
+ .. autoclass:: pymgarch.UnivariateSpec
20
+ :members:
21
+
22
+ .. autoclass:: pymgarch.MarginalSet
23
+ :members:
24
+ ```
25
+
26
+ ## Results
27
+
28
+ ```{eval-rst}
29
+ .. autoclass:: pymgarch.MGARCHResult
30
+ :members:
31
+
32
+ .. autoclass:: pymgarch.MGARCHForecast
33
+ :members:
34
+ ```
35
+
36
+ ## Simulation
37
+
38
+ ```{eval-rst}
39
+ .. autofunction:: pymgarch.simulate_dcc
40
+ ```
@@ -0,0 +1,26 @@
1
+ project = "pymgarch"
2
+ author = "Marwin Steiner"
3
+ copyright = "2026, Marwin Steiner"
4
+
5
+ extensions = [
6
+ "myst_parser",
7
+ "sphinx.ext.autodoc",
8
+ "sphinx.ext.napoleon",
9
+ "sphinx.ext.intersphinx",
10
+ "sphinx.ext.viewcode",
11
+ ]
12
+
13
+ myst_enable_extensions = ["dollarmath", "amsmath"]
14
+
15
+ intersphinx_mapping = {
16
+ "python": ("https://docs.python.org/3", None),
17
+ "numpy": ("https://numpy.org/doc/stable/", None),
18
+ "pandas": ("https://pandas.pydata.org/docs/", None),
19
+ "scipy": ("https://docs.scipy.org/doc/scipy/", None),
20
+ }
21
+
22
+ html_theme = "furo"
23
+ html_title = "pymgarch"
24
+
25
+ source_suffix = {".rst": "restructuredtext", ".md": "markdown"}
26
+ exclude_patterns = ["_build"]
@@ -0,0 +1,27 @@
1
+ # pymgarch
2
+
3
+ Multivariate GARCH for Python: DCC, ADCC, and CCC correlation dynamics on top
4
+ of `arch` univariate marginals, validated against R's rmgarch.
5
+
6
+ Python has had no maintained general-purpose multivariate GARCH framework:
7
+ the existing packages stop at Gaussian DCC(1,1), while R users have had a
8
+ full model stack in rmgarch (now tsmarch) for a decade. pymgarch closes that
9
+ gap incrementally. Stage 1 (univariate volatility) is delegated to `arch`;
10
+ stage 2 (correlation dynamics) is what this library implements, with
11
+ Engle-Sheppard two-stage standard errors and replication tests against
12
+ rmgarch's fitted parameters and likelihoods.
13
+
14
+ ```{toctree}
15
+ :maxdepth: 2
16
+
17
+ quickstart
18
+ models
19
+ inference
20
+ api
21
+ ```
22
+
23
+ ## Install
24
+
25
+ ```
26
+ pip install pymgarch # or: pip install pymgarch[numba]
27
+ ```
@@ -0,0 +1,53 @@
1
+ # Inference
2
+
3
+ ## Two-stage standard errors
4
+
5
+ Two-stage QML is consistent but the stage-2 information matrix alone
6
+ understates uncertainty: the correlation parameters are estimated on
7
+ residuals that were themselves standardized by estimated marginals. pymgarch
8
+ implements the Engle and Sheppard (2001) correction by stacking the
9
+ per-observation scores of every marginal likelihood and the correlation
10
+ likelihood into one M-estimator moment vector
11
+ $g_t(\theta)$, $\theta = (\phi_1, \dots, \phi_N, \psi)$, and computing
12
+
13
+ $$
14
+ \widehat{\mathrm{Avar}}(\hat\theta) = \hat A^{-1} \hat B \hat A^{-\top}/T,
15
+ \qquad
16
+ \hat A = \frac{1}{T}\sum_t \frac{\partial g_t}{\partial \theta'},
17
+ \qquad
18
+ \hat B = \frac{1}{T}\sum_t g_t g_t'.
19
+ $$
20
+
21
+ $\hat A$ is block lower-triangular because marginal scores do not depend on
22
+ $\psi$. All derivatives are central finite differences; marginal likelihoods
23
+ are re-evaluated through arch's own variance recursions with the backcast and
24
+ variance bounds arch used during fitting held fixed, so the perturbed
25
+ evaluations are consistent with the objective arch actually maximized.
26
+
27
+ `summary()` labels the estimates `two-stage-robust`. If the stacked bread
28
+ matrix is numerically singular, the library falls back to a stage-2-only
29
+ sandwich (labelled `stage2-robust`) and warns; those standard errors ignore
30
+ marginal estimation error.
31
+
32
+ ## Known approximations
33
+
34
+ - Correlation targets $\bar S$ and $\bar N$ are held fixed at their point
35
+ estimates, so targeting uncertainty is ignored. rmgarch makes the same
36
+ approximation.
37
+ - Set `compute_se=False` on `fit()` to skip the sandwich entirely (useful in
38
+ simulation studies where only point estimates matter).
39
+
40
+ ## Replication against rmgarch
41
+
42
+ `scripts/make_fixtures.R` fits rmgarch on a pinned dataset (percent returns
43
+ of five dji30ret constituents) and exports parameters, likelihoods, sigma and
44
+ residual paths, correlation targets, and one-step forecasts to JSON. The
45
+ test suite then:
46
+
47
+ 1. evaluates pymgarch's likelihood at R's fitted parameters on R's own
48
+ volatility paths and correlation targets, isolating the correlation math
49
+ from optimizer and univariate-initialization differences; and
50
+ 2. runs the full pipeline on the same CSV and requires parameter agreement
51
+ and a log-likelihood no worse than R's optimum.
52
+
53
+ The tests skip automatically when the fixture file is absent.
@@ -0,0 +1,62 @@
1
+ # Models
2
+
3
+ All stage-2 models operate on standardized residuals $\varepsilon_t = D_t^{-1}
4
+ (r_t - \mu_t)$, where $D_t = \mathrm{diag}(\sigma_{1t}, \dots, \sigma_{Nt})$
5
+ comes from the fitted arch marginals. The conditional covariance is
6
+ $H_t = D_t R_t D_t$.
7
+
8
+ ## CCC (Bollerslev 1990)
9
+
10
+ Constant correlation $R = \mathrm{cov2cor}(E'E/T)$. No stage-2 parameters;
11
+ closed form given the marginals. Gaussian likelihood only in v0.1.
12
+
13
+ ## DCC(1,1) (Engle 2002)
14
+
15
+ With correlation targeting $\bar S = \mathrm{cov2cor}(E'E/T)$:
16
+
17
+ $$
18
+ Q_t = (1 - a - b)\bar S + a\,\varepsilon_{t-1}\varepsilon_{t-1}' + b\,Q_{t-1},
19
+ \qquad
20
+ R_t = \mathrm{diag}(Q_t)^{-1/2} Q_t \,\mathrm{diag}(Q_t)^{-1/2},
21
+ $$
22
+
23
+ with $a, b \ge 0$, $a + b < 1$, $Q_1 = \bar S$. Estimated by two-stage QML
24
+ (SLSQP, multiple starts). Distributions: Gaussian and covariance-standardized
25
+ multivariate Student-t (degrees of freedom estimated jointly with $a, b$).
26
+
27
+ ## ADCC (Cappiello, Engle and Sheppard 2006)
28
+
29
+ Scalar asymmetric DCC with $n_t = \min(\varepsilon_t, 0)$ elementwise and
30
+ $\bar N = T^{-1}\sum_t n_t n_t'$:
31
+
32
+ $$
33
+ Q_t = \left[(1-a-b)\bar S - g\bar N\right]
34
+ + a\,\varepsilon_{t-1}\varepsilon_{t-1}'
35
+ + g\,n_{t-1}n_{t-1}'
36
+ + b\,Q_{t-1}.
37
+ $$
38
+
39
+ The intercept is positive semi-definite iff $a + b + \delta g \le 1$ with
40
+ $\delta = \lambda_{\max}(\bar S^{-1/2} \bar N \bar S^{-1/2})$, which is a
41
+ linear constraint in $(a, b, g)$ and is imposed exactly during estimation.
42
+
43
+ ## Forecasting
44
+
45
+ Marginal variance forecasts are delegated to arch. One-step correlations are
46
+ deterministic. For $h \ge 2$, DCC uses the Engle-Sheppard approximation
47
+
48
+ $$
49
+ E[R_{T+h}] \approx \left(1 - (a+b)^{h-1}\right)\bar S + (a+b)^{h-1} R_{T+1},
50
+ $$
51
+
52
+ and every model supports Monte Carlo forecasts (`method="simulation"`) that
53
+ propagate the exact recursions; ADCC requires them. The analytic covariance
54
+ assembly $\hat H = \hat D \hat R \hat D$ ignores a Jensen gap that the
55
+ simulation method does not.
56
+
57
+ ## Reported likelihood
58
+
59
+ `loglikelihood` is the joint likelihood of the returns under the stage-2
60
+ distribution (the same quantity rmgarch's `likelihood()` reports): the
61
+ multivariate density of $\varepsilon_t$ at $R_t$ plus the Jacobian
62
+ $-\sum_i \log \sigma_{it}$, summed over $t$.
@@ -0,0 +1,61 @@
1
+ # Quickstart
2
+
3
+ Fit a Gaussian DCC(1,1) with default constant-mean GARCH(1,1) marginals:
4
+
5
+ ```python
6
+ import pymgarch as mg
7
+
8
+ res = mg.DCC().fit(returns) # (T, N) DataFrame, percent scale
9
+ print(res.summary())
10
+
11
+ res.params # {"alpha": ..., "beta": ...}
12
+ res.std_errors # two-stage robust standard errors
13
+ res.conditional_correlations # (T, N, N)
14
+ res.conditional_covariances # (T, N, N)
15
+ ```
16
+
17
+ ## Distributions and asymmetry
18
+
19
+ ```python
20
+ mg.DCC(dist="t").fit(returns) # multivariate Student-t stage 2
21
+ mg.ADCC().fit(returns) # asymmetric (Cappiello-Engle-Sheppard)
22
+ mg.CCC().fit(returns) # constant-correlation baseline
23
+ ```
24
+
25
+ ## Custom marginals
26
+
27
+ Apply one spec to every column, or bring fitted arch results:
28
+
29
+ ```python
30
+ spec = mg.UnivariateSpec(vol="GARCH", p=1, o=1, q=1, dist="t") # GJR-t
31
+ res = mg.DCC().fit(returns, marginals=spec)
32
+
33
+ from arch import arch_model
34
+ fitted = [
35
+ arch_model(returns[c], rescale=False).fit(disp="off")
36
+ for c in returns.columns
37
+ ]
38
+ res = mg.DCC().fit(returns, marginals=fitted)
39
+ ```
40
+
41
+ ## Forecasting and filtering
42
+
43
+ ```python
44
+ fc = res.forecast(horizon=10) # analytic
45
+ fc = res.forecast(horizon=10, method="simulation", n_paths=2000)
46
+ fc.variances # (h, N)
47
+ fc.correlations # (h, N, N)
48
+ fc.covariances # (h, N, N)
49
+
50
+ flt = res.filter(new_returns) # apply fitted params to new data
51
+ ```
52
+
53
+ ADCC has no standard analytic multi-step correlation forecast; use
54
+ `method="simulation"` there.
55
+
56
+ ## Scaling note
57
+
58
+ Like `arch`, the optimizers behave best when returns are on a percent scale
59
+ (roughly unit variance). pymgarch fits marginals with `rescale=False` so
60
+ parameters stay comparable with R fits on the same series; multiply decimal
61
+ returns by 100 before fitting.
@@ -0,0 +1,7 @@
1
+ sphinx>=8.0
2
+ furo>=2024.8.6
3
+ myst-parser>=4.0
4
+ arch>=7.0
5
+ numpy>=1.26
6
+ pandas>=2.0
7
+ scipy>=1.11