darm-vol 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 (55) hide show
  1. darm_vol-0.1.0/.github/workflows/publish.yml +62 -0
  2. darm_vol-0.1.0/.github/workflows/tests.yml +32 -0
  3. darm_vol-0.1.0/CHANGELOG.md +10 -0
  4. darm_vol-0.1.0/CITATION.cff +8 -0
  5. darm_vol-0.1.0/CONTRIBUTING.md +19 -0
  6. darm_vol-0.1.0/LICENSE +21 -0
  7. darm_vol-0.1.0/MANIFEST.in +11 -0
  8. darm_vol-0.1.0/PKG-INFO +208 -0
  9. darm_vol-0.1.0/README.md +173 -0
  10. darm_vol-0.1.0/RELEASE_BLOCKERS.md +12 -0
  11. darm_vol-0.1.0/VALIDATION_REPORT.md +71 -0
  12. darm_vol-0.1.0/benchmarks/benchmark_filter.py +30 -0
  13. darm_vol-0.1.0/docs/api_reference.md +66 -0
  14. darm_vol-0.1.0/docs/examples.md +19 -0
  15. darm_vol-0.1.0/docs/index.md +8 -0
  16. darm_vol-0.1.0/docs/installation.md +15 -0
  17. darm_vol-0.1.0/docs/limitations.md +33 -0
  18. darm_vol-0.1.0/docs/mathematical_background.md +36 -0
  19. darm_vol-0.1.0/docs/publishing.md +37 -0
  20. darm_vol-0.1.0/examples/asymmetric_darm.py +8 -0
  21. darm_vol-0.1.0/examples/basic_usage.py +11 -0
  22. darm_vol-0.1.0/examples/compare_kernels.py +9 -0
  23. darm_vol-0.1.0/examples/fit_equity_returns.py +12 -0
  24. darm_vol-0.1.0/examples/volatility_forecasting.py +10 -0
  25. darm_vol-0.1.0/pyproject.toml +48 -0
  26. darm_vol-0.1.0/setup.cfg +4 -0
  27. darm_vol-0.1.0/src/darm_vol/__init__.py +9 -0
  28. darm_vol-0.1.0/src/darm_vol/diagnostics.py +31 -0
  29. darm_vol-0.1.0/src/darm_vol/distributions.py +32 -0
  30. darm_vol-0.1.0/src/darm_vol/estimation.py +128 -0
  31. darm_vol-0.1.0/src/darm_vol/forecasting.py +50 -0
  32. darm_vol-0.1.0/src/darm_vol/kernels.py +62 -0
  33. darm_vol-0.1.0/src/darm_vol/likelihood.py +45 -0
  34. darm_vol-0.1.0/src/darm_vol/model.py +108 -0
  35. darm_vol-0.1.0/src/darm_vol/plotting.py +58 -0
  36. darm_vol-0.1.0/src/darm_vol/recursion.py +49 -0
  37. darm_vol-0.1.0/src/darm_vol/results.py +91 -0
  38. darm_vol-0.1.0/src/darm_vol/simulation.py +59 -0
  39. darm_vol-0.1.0/src/darm_vol/validation.py +51 -0
  40. darm_vol-0.1.0/src/darm_vol.egg-info/PKG-INFO +208 -0
  41. darm_vol-0.1.0/src/darm_vol.egg-info/SOURCES.txt +53 -0
  42. darm_vol-0.1.0/src/darm_vol.egg-info/dependency_links.txt +1 -0
  43. darm_vol-0.1.0/src/darm_vol.egg-info/requires.txt +19 -0
  44. darm_vol-0.1.0/src/darm_vol.egg-info/top_level.txt +1 -0
  45. darm_vol-0.1.0/tests/test_diagnostics.py +11 -0
  46. darm_vol-0.1.0/tests/test_estimation.py +31 -0
  47. darm_vol-0.1.0/tests/test_forecast_monte_carlo.py +27 -0
  48. darm_vol-0.1.0/tests/test_forecasting.py +43 -0
  49. darm_vol-0.1.0/tests/test_kernels.py +40 -0
  50. darm_vol-0.1.0/tests/test_likelihood.py +32 -0
  51. darm_vol-0.1.0/tests/test_model.py +49 -0
  52. darm_vol-0.1.0/tests/test_optional.py +25 -0
  53. darm_vol-0.1.0/tests/test_regression.py +15 -0
  54. darm_vol-0.1.0/tests/test_simulation.py +24 -0
  55. darm_vol-0.1.0/tests/test_student_asymmetric_fit.py +21 -0
@@ -0,0 +1,62 @@
1
+ name: Controlled PyPI publishing
2
+ on:
3
+ release:
4
+ types: [published]
5
+ workflow_dispatch:
6
+ inputs:
7
+ destination:
8
+ description: 'Manual preview channel only'
9
+ required: true
10
+ type: choice
11
+ options: [testpypi]
12
+
13
+ permissions:
14
+ contents: read
15
+
16
+ jobs:
17
+ build:
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - uses: actions/setup-python@v5
22
+ with:
23
+ python-version: '3.11'
24
+ - run: |
25
+ test -f LICENSE || (echo 'Licence required before public release' && exit 1)
26
+ python -m pip install -e '.[dev]'
27
+ python -m pytest -q
28
+ python -m ruff check src tests examples
29
+ python -m build
30
+ python -m twine check dist/*
31
+ - uses: actions/upload-artifact@v4
32
+ with:
33
+ name: python-packages
34
+ path: dist/
35
+ testpypi:
36
+ if: github.event_name == 'workflow_dispatch' && inputs.destination == 'testpypi'
37
+ needs: build
38
+ runs-on: ubuntu-latest
39
+ environment: testpypi
40
+ permissions:
41
+ id-token: write
42
+ steps:
43
+ - uses: actions/download-artifact@v4
44
+ with:
45
+ name: python-packages
46
+ path: dist/
47
+ - uses: pypa/gh-action-pypi-publish@release/v1
48
+ with:
49
+ repository-url: https://test.pypi.org/legacy/
50
+ pypi:
51
+ if: github.event_name == 'release' && github.event.action == 'published' && startsWith(github.ref, 'refs/tags/v')
52
+ needs: build
53
+ runs-on: ubuntu-latest
54
+ environment: pypi
55
+ permissions:
56
+ id-token: write
57
+ steps:
58
+ - uses: actions/download-artifact@v4
59
+ with:
60
+ name: python-packages
61
+ path: dist/
62
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,32 @@
1
+ name: Test and build
2
+ on:
3
+ push:
4
+ branches: [main]
5
+ pull_request:
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ tests:
13
+ runs-on: ubuntu-latest
14
+ strategy:
15
+ fail-fast: false
16
+ matrix:
17
+ python-version: ['3.10', '3.11', '3.12', '3.13']
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+ - uses: actions/setup-python@v5
21
+ with:
22
+ python-version: ${{ matrix.python-version }}
23
+ - run: python -m pip install -e '.[dev]'
24
+ - run: python -m pytest -q
25
+ - run: python -m ruff check src tests examples
26
+ - run: python -m build
27
+ - run: python -m twine check dist/*
28
+ - name: Wheel smoke test in clean environment
29
+ run: |
30
+ python -m venv /tmp/darm-wheel-smoke
31
+ /tmp/darm-wheel-smoke/bin/python -m pip install dist/*.whl
32
+ (cd /tmp && /tmp/darm-wheel-smoke/bin/python -c 'from darm_vol import DARM; print(DARM(lags=5))')
@@ -0,0 +1,10 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 — pre-release candidate
4
+
5
+ - Finite-K normalized exponential, power and hyperbolic ARCH kernels.
6
+ - Symmetric and asymmetric news impact, Gaussian and unit-variance Student-t.
7
+ - Bounded multi-start conditional MLE, exact finite-memory forecasts, simulation.
8
+ - Diagnostics and optional Matplotlib visualisation.
9
+
10
+ Publication date is not assigned: this version has **not** been released on PyPI.
@@ -0,0 +1,8 @@
1
+ cff-version: 1.2.0
2
+ message: "Please cite the software and its underlying research preprint."
3
+ title: "darm-vol: Decaying AutoRegressive Memory for Conditional Volatility"
4
+ type: software
5
+ authors:
6
+ - family-names: Connell
7
+ given-names: Callum
8
+ version: 0.1.0
@@ -0,0 +1,19 @@
1
+ # Contributing
2
+
3
+ Please open a GitHub issue to discuss substantial numerical or public API changes.
4
+ Submit tests verifying mathematical identities independently from the implementation.
5
+ Do not alter kernel definitions or sample conditioning silently. Document version,
6
+ seed, data construction and optimization tolerances of all numeric comparisons.
7
+
8
+ Locally:
9
+
10
+ ```bash
11
+ python -m pip install -e '.[dev]'
12
+ python -m pytest -q
13
+ ruff check src tests examples
14
+ python -m build
15
+ python -m twine check dist/*
16
+ ```
17
+
18
+ **Licence selection is pending.** Obtain author approval before accepting
19
+ third-party contributions or publicly redistributing the source.
darm_vol-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Callum Connell
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,11 @@
1
+ include README.md
2
+ include CHANGELOG.md
3
+ include CONTRIBUTING.md
4
+ include CITATION.cff
5
+ include RELEASE_BLOCKERS.md
6
+ recursive-include docs *.md
7
+ recursive-include examples *.py
8
+ recursive-include tests *.py
9
+ recursive-include .github *.yml
10
+ include VALIDATION_REPORT.md
11
+ recursive-include benchmarks *.py
@@ -0,0 +1,208 @@
1
+ Metadata-Version: 2.4
2
+ Name: darm-vol
3
+ Version: 0.1.0
4
+ Summary: Decaying AutoRegressive Memory models for finite-memory conditional volatility
5
+ Author: Callum Connell
6
+ License-Expression: MIT
7
+ Keywords: volatility,ARCH,conditional variance,financial econometrics
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Science/Research
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
16
+ Requires-Python: >=3.10
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Requires-Dist: numpy>=1.24
20
+ Requires-Dist: scipy>=1.10
21
+ Provides-Extra: pandas
22
+ Requires-Dist: pandas>=1.5; extra == "pandas"
23
+ Provides-Extra: plot
24
+ Requires-Dist: matplotlib>=3.6; extra == "plot"
25
+ Provides-Extra: performance
26
+ Requires-Dist: numba>=0.58; extra == "performance"
27
+ Provides-Extra: dev
28
+ Requires-Dist: pytest>=7; extra == "dev"
29
+ Requires-Dist: ruff>=0.6; extra == "dev"
30
+ Requires-Dist: build>=1; extra == "dev"
31
+ Requires-Dist: twine>=5; extra == "dev"
32
+ Requires-Dist: pandas>=1.5; extra == "dev"
33
+ Requires-Dist: matplotlib>=3.6; extra == "dev"
34
+ Dynamic: license-file
35
+
36
+ # darm-vol
37
+
38
+ **Decaying AutoRegressive Memory (DARM) conditional-volatility models**
39
+ Author: **Callum Connell** · Version: **0.1.0 pre-release candidate**
40
+
41
+ A Python library for the finite-lag, normalized-kernel ARCH specifications developed in
42
+ *Decaying Autoregressive Memory Models for Conditional Volatility: Mathematical Foundations,
43
+ Finite-Sample Identification and Out-of-Sample Evidence* (preprint v1.0, 19 October 2026).
44
+
45
+ > **Not published.** `pip install darm-vol` will only work after a PyPI release.
46
+ > Source installation works now. The package has no selected software licence;
47
+ > author approval is required **before** any public distribution.
48
+
49
+ ## Model
50
+
51
+ For zero conditional-mean innovations `epsilon_t = sqrt(h_t) z_t`, where independent,
52
+ standardized, symmetric `z_t` have mean zero and variance one, symmetric DARM is
53
+
54
+ ```text
55
+ h_t = omega + rho * sum_{k=1}^K w_k(theta) * epsilon_(t-k)^2
56
+ ```
57
+
58
+ with `omega > 0`, `0 <= rho < 1`, `w_k >= 0`, `sum w_k = 1`.
59
+ For asymmetric DARM, replace each squared innovation with
60
+
61
+ ```text
62
+ u_t = epsilon_t^2 * [1 - kappa + 2*kappa*1{epsilon_t<0}]
63
+ ```
64
+
65
+ where `0 <= kappa < 1`. Here `u_t` denotes the transformed shock; **`nu` in
66
+ parameter dictionaries denotes Student-t degrees of freedom, not `u_t`**.
67
+
68
+ Finite-lag kernels use `k=1..K`:
69
+
70
+ | Kernel | Unnormalized weight | Parameters |
71
+ |---|---|---|
72
+ | Exponential | `beta^(k-1)` | `0 < beta < 1` |
73
+ | Power | `(k-1+delta)^(-alpha)` | `alpha, delta > 0` |
74
+ | Hyperbolic | `(1+s*k)^(-p)` | `s, p > 0` |
75
+
76
+ Every family is normalized over exactly **K** lags. Hyperbolic coincides with
77
+ a subset of shifted power weights (`alpha=p`, `delta=1+1/s`) rather than an
78
+ independent stochastic-process class. The infinite-lag counterpart is a
79
+ **different specification**; finite exponential DARM is not exactly GARCH(1,1).
80
+ The infinite power kernel has a finite normalizing constant only when `alpha>1`.
81
+
82
+ DARM is a low-dimensional parametrization of ARCH(K), not a new stochastic
83
+ process outside ARCH theory. A finite-K DARM can show persistent squared returns
84
+ but is **not** strictly long-memory in the covariance non-summability sense under
85
+ the manuscript's finite-moment conditions.
86
+
87
+ ## Installation
88
+
89
+ In a checked-out source directory:
90
+
91
+ ```bash
92
+ python -m pip install .
93
+ python -m pip install -e '.[dev]'
94
+ ```
95
+
96
+ Python >=3.10; runtime: NumPy and SciPy. pandas Series are accepted as inputs
97
+ without requiring pandas at runtime. Plotting and optional acceleration:
98
+
99
+ ```bash
100
+ python -m pip install '.[plot]'
101
+ python -m pip install '.[performance]'
102
+ ```
103
+
104
+ ## Quick start — fit, forecast, simulate
105
+
106
+ ```python
107
+ import numpy as np
108
+ from darm_vol import DARM
109
+
110
+ model = DARM(kernel="power", distribution="student-t", lags=30,
111
+ asymmetric=True)
112
+ true = {"omega": 0.00002, "rho": 0.70, "alpha": 1.8,
113
+ "delta": 5.0, "kappa": 0.4, "nu": 8.0}
114
+
115
+ sample = model.simulate(true, nobs=1200, burn=1000, random_state=42)
116
+ fit = model.fit(sample.returns, n_starts=2, random_state=42)
117
+ print(fit.summary())
118
+ print(fit.params, fit.loglikelihood, fit.aic, fit.bic)
119
+
120
+ fc = fit.forecast(horizon=5)
121
+ print(fc.daily_variance, fc.daily_volatility)
122
+ print(fc.integrated_variance)
123
+
124
+ new_data = fit.simulate(nobs=1000, burn=1000, random_state=99)
125
+ print(new_data.returns.shape, new_data.conditional_volatility.shape)
126
+
127
+ # Optional: pip install '.[plot]'
128
+ # fig, ax = fit.plot_volatility()
129
+ ```
130
+
131
+ For live equity data see [`examples/fit_equity_returns.py`](examples/fit_equity_returns.py).
132
+ **Inputs are always in their original units**: e.g., a 1% decimal log return
133
+ is `0.01`, not `1.0`. No automatic scaling or demeaning occurs.
134
+
135
+ The **first K observations initialize the observed lag state** and are excluded
136
+ from the fitted conditional likelihood. Conditional variance arrays have `NaN`
137
+ in the first K positions. Therefore AIC/BIC use `T-K` observations and the
138
+ estimated number of free parameters. `omega` is internally reparameterized
139
+ by a sample-variance scale during optimization, then returned in the original
140
+ input units.
141
+
142
+ ## Forecasting
143
+
144
+ For future times, unknown transformed shocks are replaced by their conditional
145
+ expectations. Both Gaussian and standardized Student-t innovations are
146
+ symmetric, giving `E[A_t]=1` with the stated asymmetric transformation.
147
+ `forecast(horizon=H).daily_variance` computes `E_T[h_(T+j)]` for `j=1,...,H`.
148
+ `integrated_variance` sums them. `daily_volatility` is `sqrt(E_T[h])`, **not**
149
+ `E_T[sqrt(h)]`.
150
+
151
+ With zero-mean martingale-difference returns, the sum of future conditional
152
+ variances also equals the conditional variance of their cumulative sum;
153
+ that equivalence should not be applied if separate serially dependent mean
154
+ dynamics are introduced. No interval coverage claim is implied.
155
+
156
+ ## Simulation and diagnostics
157
+
158
+ Simulation uses independent standardized Gaussian or Student-t shocks and
159
+ exact finite-K transformed-shock recursion with K presample transformed shocks
160
+ fixed at `omega/(1-rho)` (valid due to the symmetric innovation laws). A burn-in
161
+ period reduces the effect of initialization. For infinite fourth-moment
162
+ Student-t laws with `2<nu<=4`, squared-return variance diagnostics do not
163
+ have the usual finite-moment theoretical justification.
164
+
165
+ `fit.diagnostics(lags=10)` returns residual mean, variance, excess kurtosis,
166
+ and Ljung-Box tests on residuals and residual squares (raw asymptotic p-values;
167
+ no automatic degrees-of-freedom correction for fitted parameters).
168
+ `fit.plot_volatility()`, `fit.plot_residuals()`, `fit.plot_kernel()`,
169
+ `fit.plot_forecast(10)` return Matplotlib `(Figure, Axes)` objects.
170
+
171
+ ## Scientific limitations
172
+
173
+ - **Identification:** high kernel-shape uncertainty, flat likelihood ridges,
174
+ and boundary estimates can arise even when point forecasts are accurate.
175
+ No default Wald standard errors are provided; use careful profile inference.
176
+ - **Conditional MLE:** the first K returns are treated as conditioning
177
+ observations, rather than integrating out a stationary presample.
178
+ - **Finite K:** neither finite geometric kernel GARCH equivalence nor genuine
179
+ covariance non-summable long memory is claimed.
180
+ - **Forecast calibration:** prediction intervals for future squared returns
181
+ are not interchangeable with intervals for latent integrated variance.
182
+ - **Performance:** source supplied for this build includes the papers, but
183
+ **not original research implementation or raw experiment inputs**. Our
184
+ independent numerical unit tests do *not* establish full paper replication.
185
+ - **Inference:** fitted Student-t nu can be weakly identified; numerical boxes
186
+ are implementation limits, not the unrestricted theoretical parameter domain.
187
+ - **Empirical superiority:** the paper's primary 10-day comparison against
188
+ GJR-GARCH is inconclusive (HAC p=0.146291); no universal model superiority
189
+ or economic trading benefit is claimed.
190
+
191
+ ## Research, attribution and citation
192
+
193
+ Callum Connell (2026), *Decaying Autoregressive Memory Models for Conditional
194
+ Volatility: Mathematical Foundations, Finite-Sample Identification and
195
+ Out-of-Sample Evidence*, preprint v1.0, 19 October 2026. See
196
+ [`research/`](research/) for the documents used to implement this package,
197
+ including the technical supplement and mathematical correction report.
198
+ See [`CITATION.cff`](CITATION.cff) for software citation metadata.
199
+ No DOI or public external paper URL has been supplied, so none is fabricated.
200
+
201
+ ## Development status
202
+
203
+ This repository is a **0.1.0 pre-release source candidate**, not a published
204
+ PyPI release or independent replication of Experiments 13–18. See
205
+ [`docs/limitations.md`](docs/limitations.md) and
206
+ [`docs/publishing.md`](docs/publishing.md) before releasing.
207
+
208
+ Contributions: see [`CONTRIBUTING.md`](CONTRIBUTING.md).
@@ -0,0 +1,173 @@
1
+ # darm-vol
2
+
3
+ **Decaying AutoRegressive Memory (DARM) conditional-volatility models**
4
+ Author: **Callum Connell** · Version: **0.1.0 pre-release candidate**
5
+
6
+ A Python library for the finite-lag, normalized-kernel ARCH specifications developed in
7
+ *Decaying Autoregressive Memory Models for Conditional Volatility: Mathematical Foundations,
8
+ Finite-Sample Identification and Out-of-Sample Evidence* (preprint v1.0, 19 October 2026).
9
+
10
+ > **Not published.** `pip install darm-vol` will only work after a PyPI release.
11
+ > Source installation works now. The package has no selected software licence;
12
+ > author approval is required **before** any public distribution.
13
+
14
+ ## Model
15
+
16
+ For zero conditional-mean innovations `epsilon_t = sqrt(h_t) z_t`, where independent,
17
+ standardized, symmetric `z_t` have mean zero and variance one, symmetric DARM is
18
+
19
+ ```text
20
+ h_t = omega + rho * sum_{k=1}^K w_k(theta) * epsilon_(t-k)^2
21
+ ```
22
+
23
+ with `omega > 0`, `0 <= rho < 1`, `w_k >= 0`, `sum w_k = 1`.
24
+ For asymmetric DARM, replace each squared innovation with
25
+
26
+ ```text
27
+ u_t = epsilon_t^2 * [1 - kappa + 2*kappa*1{epsilon_t<0}]
28
+ ```
29
+
30
+ where `0 <= kappa < 1`. Here `u_t` denotes the transformed shock; **`nu` in
31
+ parameter dictionaries denotes Student-t degrees of freedom, not `u_t`**.
32
+
33
+ Finite-lag kernels use `k=1..K`:
34
+
35
+ | Kernel | Unnormalized weight | Parameters |
36
+ |---|---|---|
37
+ | Exponential | `beta^(k-1)` | `0 < beta < 1` |
38
+ | Power | `(k-1+delta)^(-alpha)` | `alpha, delta > 0` |
39
+ | Hyperbolic | `(1+s*k)^(-p)` | `s, p > 0` |
40
+
41
+ Every family is normalized over exactly **K** lags. Hyperbolic coincides with
42
+ a subset of shifted power weights (`alpha=p`, `delta=1+1/s`) rather than an
43
+ independent stochastic-process class. The infinite-lag counterpart is a
44
+ **different specification**; finite exponential DARM is not exactly GARCH(1,1).
45
+ The infinite power kernel has a finite normalizing constant only when `alpha>1`.
46
+
47
+ DARM is a low-dimensional parametrization of ARCH(K), not a new stochastic
48
+ process outside ARCH theory. A finite-K DARM can show persistent squared returns
49
+ but is **not** strictly long-memory in the covariance non-summability sense under
50
+ the manuscript's finite-moment conditions.
51
+
52
+ ## Installation
53
+
54
+ In a checked-out source directory:
55
+
56
+ ```bash
57
+ python -m pip install .
58
+ python -m pip install -e '.[dev]'
59
+ ```
60
+
61
+ Python >=3.10; runtime: NumPy and SciPy. pandas Series are accepted as inputs
62
+ without requiring pandas at runtime. Plotting and optional acceleration:
63
+
64
+ ```bash
65
+ python -m pip install '.[plot]'
66
+ python -m pip install '.[performance]'
67
+ ```
68
+
69
+ ## Quick start — fit, forecast, simulate
70
+
71
+ ```python
72
+ import numpy as np
73
+ from darm_vol import DARM
74
+
75
+ model = DARM(kernel="power", distribution="student-t", lags=30,
76
+ asymmetric=True)
77
+ true = {"omega": 0.00002, "rho": 0.70, "alpha": 1.8,
78
+ "delta": 5.0, "kappa": 0.4, "nu": 8.0}
79
+
80
+ sample = model.simulate(true, nobs=1200, burn=1000, random_state=42)
81
+ fit = model.fit(sample.returns, n_starts=2, random_state=42)
82
+ print(fit.summary())
83
+ print(fit.params, fit.loglikelihood, fit.aic, fit.bic)
84
+
85
+ fc = fit.forecast(horizon=5)
86
+ print(fc.daily_variance, fc.daily_volatility)
87
+ print(fc.integrated_variance)
88
+
89
+ new_data = fit.simulate(nobs=1000, burn=1000, random_state=99)
90
+ print(new_data.returns.shape, new_data.conditional_volatility.shape)
91
+
92
+ # Optional: pip install '.[plot]'
93
+ # fig, ax = fit.plot_volatility()
94
+ ```
95
+
96
+ For live equity data see [`examples/fit_equity_returns.py`](examples/fit_equity_returns.py).
97
+ **Inputs are always in their original units**: e.g., a 1% decimal log return
98
+ is `0.01`, not `1.0`. No automatic scaling or demeaning occurs.
99
+
100
+ The **first K observations initialize the observed lag state** and are excluded
101
+ from the fitted conditional likelihood. Conditional variance arrays have `NaN`
102
+ in the first K positions. Therefore AIC/BIC use `T-K` observations and the
103
+ estimated number of free parameters. `omega` is internally reparameterized
104
+ by a sample-variance scale during optimization, then returned in the original
105
+ input units.
106
+
107
+ ## Forecasting
108
+
109
+ For future times, unknown transformed shocks are replaced by their conditional
110
+ expectations. Both Gaussian and standardized Student-t innovations are
111
+ symmetric, giving `E[A_t]=1` with the stated asymmetric transformation.
112
+ `forecast(horizon=H).daily_variance` computes `E_T[h_(T+j)]` for `j=1,...,H`.
113
+ `integrated_variance` sums them. `daily_volatility` is `sqrt(E_T[h])`, **not**
114
+ `E_T[sqrt(h)]`.
115
+
116
+ With zero-mean martingale-difference returns, the sum of future conditional
117
+ variances also equals the conditional variance of their cumulative sum;
118
+ that equivalence should not be applied if separate serially dependent mean
119
+ dynamics are introduced. No interval coverage claim is implied.
120
+
121
+ ## Simulation and diagnostics
122
+
123
+ Simulation uses independent standardized Gaussian or Student-t shocks and
124
+ exact finite-K transformed-shock recursion with K presample transformed shocks
125
+ fixed at `omega/(1-rho)` (valid due to the symmetric innovation laws). A burn-in
126
+ period reduces the effect of initialization. For infinite fourth-moment
127
+ Student-t laws with `2<nu<=4`, squared-return variance diagnostics do not
128
+ have the usual finite-moment theoretical justification.
129
+
130
+ `fit.diagnostics(lags=10)` returns residual mean, variance, excess kurtosis,
131
+ and Ljung-Box tests on residuals and residual squares (raw asymptotic p-values;
132
+ no automatic degrees-of-freedom correction for fitted parameters).
133
+ `fit.plot_volatility()`, `fit.plot_residuals()`, `fit.plot_kernel()`,
134
+ `fit.plot_forecast(10)` return Matplotlib `(Figure, Axes)` objects.
135
+
136
+ ## Scientific limitations
137
+
138
+ - **Identification:** high kernel-shape uncertainty, flat likelihood ridges,
139
+ and boundary estimates can arise even when point forecasts are accurate.
140
+ No default Wald standard errors are provided; use careful profile inference.
141
+ - **Conditional MLE:** the first K returns are treated as conditioning
142
+ observations, rather than integrating out a stationary presample.
143
+ - **Finite K:** neither finite geometric kernel GARCH equivalence nor genuine
144
+ covariance non-summable long memory is claimed.
145
+ - **Forecast calibration:** prediction intervals for future squared returns
146
+ are not interchangeable with intervals for latent integrated variance.
147
+ - **Performance:** source supplied for this build includes the papers, but
148
+ **not original research implementation or raw experiment inputs**. Our
149
+ independent numerical unit tests do *not* establish full paper replication.
150
+ - **Inference:** fitted Student-t nu can be weakly identified; numerical boxes
151
+ are implementation limits, not the unrestricted theoretical parameter domain.
152
+ - **Empirical superiority:** the paper's primary 10-day comparison against
153
+ GJR-GARCH is inconclusive (HAC p=0.146291); no universal model superiority
154
+ or economic trading benefit is claimed.
155
+
156
+ ## Research, attribution and citation
157
+
158
+ Callum Connell (2026), *Decaying Autoregressive Memory Models for Conditional
159
+ Volatility: Mathematical Foundations, Finite-Sample Identification and
160
+ Out-of-Sample Evidence*, preprint v1.0, 19 October 2026. See
161
+ [`research/`](research/) for the documents used to implement this package,
162
+ including the technical supplement and mathematical correction report.
163
+ See [`CITATION.cff`](CITATION.cff) for software citation metadata.
164
+ No DOI or public external paper URL has been supplied, so none is fabricated.
165
+
166
+ ## Development status
167
+
168
+ This repository is a **0.1.0 pre-release source candidate**, not a published
169
+ PyPI release or independent replication of Experiments 13–18. See
170
+ [`docs/limitations.md`](docs/limitations.md) and
171
+ [`docs/publishing.md`](docs/publishing.md) before releasing.
172
+
173
+ Contributions: see [`CONTRIBUTING.md`](CONTRIBUTING.md).
@@ -0,0 +1,12 @@
1
+ # Software licence decision required before publication
2
+
3
+ The author has not yet selected a software licence. No licence grant is
4
+ implied. Do **not** publish or redistribute the package publicly on PyPI
5
+ until Callum Connell has approved the licence and provided its full text in
6
+ a `LICENSE` file.
7
+
8
+ The most common permissive options are MIT, BSD-3-Clause and Apache-2.0,
9
+ but no option has been selected automatically. Confirm rights in any
10
+ incorporated third-party materials before choosing.
11
+
12
+ The release workflow intentionally fails while `LICENSE` is absent.
@@ -0,0 +1,71 @@
1
+ # DARM v0.1.0 candidate — build & validation report
2
+
3
+ Date: 28 October 2026. Package has **not** been uploaded to PyPI or
4
+ published on GitHub. Software licence remains undecided and is a **release
5
+ blocker** requiring explicit author approval.
6
+
7
+ ## Source inspection and mathematical design
8
+
9
+ - Supplied: preprint v1.0, technical supplement v1.0, mathematical
10
+ correction report v1.0, package implementation requirements.
11
+ - Not supplied: original research Python sources, Monte Carlo notebook
12
+ implementation archive, numerical model-fit regression fixtures,
13
+ original equity market data, exact run environment.
14
+ - Implemented kernel equations 10–12 from preprint, finite K normalization.
15
+ - Implemented finite-K symmetric/asymmetric transformed-shock recursion
16
+ and Gaussian / unit-variance Student-t conditional log-likelihood.
17
+ - Adopted the supplement's conditional likelihood convention: first K
18
+ observed returns initialize the state; effective n=T-K.
19
+ - Multi-step forecasts use future conditional expected transformed shocks,
20
+ not unavailable realized future returns, under symmetric innovation laws.
21
+ - Source code is newly implemented from papers; no claim that it recreates
22
+ original research Python code line-for-line.
23
+
24
+ ## Checks executed (current candidate)
25
+
26
+ | Check | Command | Result |
27
+ | --- | --- | --- |
28
+ | Unit and Monte Carlo tests | `PYTHONPATH=src python -m pytest -q` | 26 passed |
29
+ | Bytecode syntax check | `python -m compileall -q src tests examples` | Passed |
30
+ | Wheel build | `python -m pip wheel --no-build-isolation --no-deps . -w dist` | Passed |
31
+ | Source distribution | `python -c 'import setuptools; setuptools.setup()' sdist --dist-dir dist` | Passed |
32
+ | Built-wheel smoke test | Install wheel with `pip --no-index --no-deps` into new venv; inject existing environment's NumPy/SciPy paths; import + ML fit + 5-day forecast from `/tmp` | Passed (dependencies NOT isolated) |
33
+ | Time benchmark | `PYTHONPATH=src python benchmarks/benchmark_filter.py` | Success; approximately 0.014 seconds for T=10,000 K=252 (best of 3) |
34
+ | `python -m build` | Attempted tool availability | Not run: `build` not installed and network unavailable |
35
+ | `twine check dist/*` | Attempted tool availability | Not run: `twine` not installed and network unavailable |
36
+ | `ruff check` | Attempted tool availability | Not run: `ruff` not installed and network unavailable |
37
+ | Base `pip check` | `python -m pip check` | Failed due unrelated existing moviepy/pillow version mismatch |
38
+ | Research code numerical parity | Compare original likelihood/forecasts | Not possible: original implementation absent |
39
+ | Multi-Python matrix | GitHub Actions configured for Python 3.10–3.13 | Not executed locally; Python 3.13 tested |
40
+ | PyPI TestPyPI publishing | Manual upload | NOT attempted; approval and licence required |
41
+
42
+ ### Representative filter benchmarks
43
+
44
+ Environment: current Python 3.13 session, NumPy/SciPy, single-threaded
45
+ Python loop around NumPy dot operations. The figures are local wall times;
46
+ not a comparison against original DARM research software or GARCH models.
47
+
48
+ | T | K | best of 3 |
49
+ | ---: | ---: | ---: |
50
+ | 1,000 | 30 | 0.0013 s |
51
+ | 5,000 | 30 | 0.0062 s |
52
+ | 10,000 | 30 | 0.0129 s |
53
+ | 1,000 | 252 | 0.0011 s |
54
+ | 5,000 | 252 | 0.0070 s |
55
+ | 10,000 | 252 | 0.0138 s |
56
+ | 5,000 | 1,000 | 0.0075 s |
57
+ | 10,000 | 1,000 | 0.0162 s |
58
+
59
+ ## Release blockers
60
+
61
+ 1. Ask Callum Connell to choose and approve a software licence.
62
+ 2. Have the author review public project metadata / legal data rights.
63
+ 3. Run Ruff, `python -m build`, `twine check`, clean dependency-isolated
64
+ wheel install, and CI matrix in an online development environment.
65
+ 4. Acquire old research implementation and numeric fixtures for
66
+ independent regression comparisons and original research parity checks.
67
+ 5. Register GitHub Trusted Publishers with matching protected environments.
68
+ 6. Authorize a deliberate TestPyPI dispatch and subsequent GitHub Release.
69
+ 7. Confirm at publication time that the `darm-vol` distribution is available.
70
+
71
+ See `docs/publishing.md` for step-by-step instructions.
@@ -0,0 +1,30 @@
1
+ """Repeatable wall-clock microbenchmark of the finite-K variance recursion.
2
+
3
+ No claims are made about the original research implementations.
4
+ Run: python benchmarks/benchmark_filter.py
5
+ """
6
+ from __future__ import annotations
7
+
8
+ import time
9
+ import numpy as np
10
+ from darm_vol import DARM
11
+
12
+
13
+ def benchmark(n: int, k: int, repeats: int = 3) -> float:
14
+ rng = np.random.default_rng(20261028)
15
+ returns = rng.normal(0, .01, n)
16
+ p = {"omega": .00001, "rho": .8, "alpha": 2., "delta": 5.}
17
+ model = DARM(kernel="power", distribution="normal", lags=k)
18
+ times = []
19
+ for _ in range(repeats):
20
+ start = time.perf_counter()
21
+ model.conditional_variance(returns, p)
22
+ times.append(time.perf_counter()-start)
23
+ return min(times)
24
+
25
+
26
+ if __name__ == "__main__":
27
+ for k in (30, 252, 1000):
28
+ for n in (1000, 5000, 10000):
29
+ if n > k:
30
+ print(f"T={n:5d} K={k:4d}: {benchmark(n,k):.6f} sec (best of three)")