mfe-toolbox 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.
- mfe_toolbox-0.1.0/.github/workflows/docs.yml +18 -0
- mfe_toolbox-0.1.0/.github/workflows/publish.yml +55 -0
- mfe_toolbox-0.1.0/.gitignore +75 -0
- mfe_toolbox-0.1.0/PKG-INFO +84 -0
- mfe_toolbox-0.1.0/README.md +70 -0
- mfe_toolbox-0.1.0/dev/benchmarks/bench_realized.py +78 -0
- mfe_toolbox-0.1.0/docs/api/bootstrap.md +5 -0
- mfe_toolbox-0.1.0/docs/api/crosssection.md +5 -0
- mfe_toolbox-0.1.0/docs/api/distributions.md +5 -0
- mfe_toolbox-0.1.0/docs/api/multivariate.md +5 -0
- mfe_toolbox-0.1.0/docs/api/realized.md +5 -0
- mfe_toolbox-0.1.0/docs/api/tests_stat.md +5 -0
- mfe_toolbox-0.1.0/docs/api/timeseries.md +5 -0
- mfe_toolbox-0.1.0/docs/api/univariate.md +5 -0
- mfe_toolbox-0.1.0/docs/api/utils.md +5 -0
- mfe_toolbox-0.1.0/docs/changelog.md +74 -0
- mfe_toolbox-0.1.0/docs/guide/bootstrap.md +34 -0
- mfe_toolbox-0.1.0/docs/guide/comparison.md +77 -0
- mfe_toolbox-0.1.0/docs/guide/crosssection.md +41 -0
- mfe_toolbox-0.1.0/docs/guide/distributions.md +40 -0
- mfe_toolbox-0.1.0/docs/guide/installation.md +62 -0
- mfe_toolbox-0.1.0/docs/guide/multivariate.md +57 -0
- mfe_toolbox-0.1.0/docs/guide/quickstart.md +161 -0
- mfe_toolbox-0.1.0/docs/guide/realized.md +75 -0
- mfe_toolbox-0.1.0/docs/guide/timeseries.md +40 -0
- mfe_toolbox-0.1.0/docs/guide/univariate.md +38 -0
- mfe_toolbox-0.1.0/docs/index.md +141 -0
- mfe_toolbox-0.1.0/mkdocs.yml +98 -0
- mfe_toolbox-0.1.0/pyproject.toml +57 -0
- mfe_toolbox-0.1.0/setup_cython.py +61 -0
- mfe_toolbox-0.1.0/src/mfe/__init__.py +18 -0
- mfe_toolbox-0.1.0/src/mfe/bootstrap/__init__.py +18 -0
- mfe_toolbox-0.1.0/src/mfe/bootstrap/spa.py +217 -0
- mfe_toolbox-0.1.0/src/mfe/bootstrap/stepM.py +210 -0
- mfe_toolbox-0.1.0/src/mfe/bootstrap/wild.py +169 -0
- mfe_toolbox-0.1.0/src/mfe/crosssection/__init__.py +15 -0
- mfe_toolbox-0.1.0/src/mfe/crosssection/fm.py +171 -0
- mfe_toolbox-0.1.0/src/mfe/crosssection/ols.py +176 -0
- mfe_toolbox-0.1.0/src/mfe/crosssection/pca.py +143 -0
- mfe_toolbox-0.1.0/src/mfe/distributions/__init__.py +21 -0
- mfe_toolbox-0.1.0/src/mfe/distributions/ged.py +85 -0
- mfe_toolbox-0.1.0/src/mfe/distributions/mvnorm.py +166 -0
- mfe_toolbox-0.1.0/src/mfe/distributions/skewt.py +140 -0
- mfe_toolbox-0.1.0/src/mfe/multivariate/__init__.py +22 -0
- mfe_toolbox-0.1.0/src/mfe/multivariate/_core.html +2944 -0
- mfe_toolbox-0.1.0/src/mfe/multivariate/_core.pyx +303 -0
- mfe_toolbox-0.1.0/src/mfe/multivariate/base.py +193 -0
- mfe_toolbox-0.1.0/src/mfe/multivariate/bekk.py +415 -0
- mfe_toolbox-0.1.0/src/mfe/multivariate/ccc.py +84 -0
- mfe_toolbox-0.1.0/src/mfe/multivariate/dcc.py +244 -0
- mfe_toolbox-0.1.0/src/mfe/multivariate/gogarch.py +581 -0
- mfe_toolbox-0.1.0/src/mfe/multivariate/rcc.py +330 -0
- mfe_toolbox-0.1.0/src/mfe/realized/__init__.py +39 -0
- mfe_toolbox-0.1.0/src/mfe/realized/_core.html +3075 -0
- mfe_toolbox-0.1.0/src/mfe/realized/_core.pyx +225 -0
- mfe_toolbox-0.1.0/src/mfe/realized/_core_fallback.py +26 -0
- mfe_toolbox-0.1.0/src/mfe/realized/_types.py +73 -0
- mfe_toolbox-0.1.0/src/mfe/realized/covariance.py +217 -0
- mfe_toolbox-0.1.0/src/mfe/realized/jumps.py +76 -0
- mfe_toolbox-0.1.0/src/mfe/realized/kernel.py +208 -0
- mfe_toolbox-0.1.0/src/mfe/realized/multivariate_kernel.py +133 -0
- mfe_toolbox-0.1.0/src/mfe/realized/noise.py +67 -0
- mfe_toolbox-0.1.0/src/mfe/realized/quantile_var.py +123 -0
- mfe_toolbox-0.1.0/src/mfe/realized/quarticity.py +44 -0
- mfe_toolbox-0.1.0/src/mfe/realized/range_.py +131 -0
- mfe_toolbox-0.1.0/src/mfe/realized/sampling.py +205 -0
- mfe_toolbox-0.1.0/src/mfe/realized/tsrv.py +178 -0
- mfe_toolbox-0.1.0/src/mfe/realized/variance.py +256 -0
- mfe_toolbox-0.1.0/src/mfe/tests_stat/__init__.py +24 -0
- mfe_toolbox-0.1.0/src/mfe/tests_stat/arch_lm.py +95 -0
- mfe_toolbox-0.1.0/src/mfe/tests_stat/forecast_eval.py +186 -0
- mfe_toolbox-0.1.0/src/mfe/tests_stat/serial.py +150 -0
- mfe_toolbox-0.1.0/src/mfe/timeseries/__init__.py +18 -0
- mfe_toolbox-0.1.0/src/mfe/timeseries/beveridge_nelson.py +289 -0
- mfe_toolbox-0.1.0/src/mfe/timeseries/var.py +599 -0
- mfe_toolbox-0.1.0/src/mfe/univariate/__init__.py +15 -0
- mfe_toolbox-0.1.0/src/mfe/univariate/har.py +225 -0
- mfe_toolbox-0.1.0/src/mfe/univariate/heavy.py +332 -0
- mfe_toolbox-0.1.0/src/mfe/utils/__init__.py +16 -0
- mfe_toolbox-0.1.0/src/mfe/utils/lags.py +96 -0
- mfe_toolbox-0.1.0/src/mfe/utils/typing.py +27 -0
- mfe_toolbox-0.1.0/src/mfe/utils/vcv.py +73 -0
- mfe_toolbox-0.1.0/tests/__init__.py +0 -0
- mfe_toolbox-0.1.0/tests/conftest.py +62 -0
- mfe_toolbox-0.1.0/tests/test_bootstrap/__init__.py +0 -0
- mfe_toolbox-0.1.0/tests/test_bootstrap/test_spa.py +58 -0
- mfe_toolbox-0.1.0/tests/test_bootstrap/test_stepm.py +56 -0
- mfe_toolbox-0.1.0/tests/test_bootstrap/test_wild.py +49 -0
- mfe_toolbox-0.1.0/tests/test_crosssection/__init__.py +0 -0
- mfe_toolbox-0.1.0/tests/test_crosssection/test_fm.py +44 -0
- mfe_toolbox-0.1.0/tests/test_crosssection/test_ols.py +96 -0
- mfe_toolbox-0.1.0/tests/test_crosssection/test_pca.py +67 -0
- mfe_toolbox-0.1.0/tests/test_distributions/__init__.py +0 -0
- mfe_toolbox-0.1.0/tests/test_distributions/test_mvnorm.py +85 -0
- mfe_toolbox-0.1.0/tests/test_multivariate/__init__.py +0 -0
- mfe_toolbox-0.1.0/tests/test_multivariate/test_bekk.py +43 -0
- mfe_toolbox-0.1.0/tests/test_multivariate/test_gogarch.py +268 -0
- mfe_toolbox-0.1.0/tests/test_multivariate/test_rcc.py +112 -0
- mfe_toolbox-0.1.0/tests/test_realized/__init__.py +0 -0
- mfe_toolbox-0.1.0/tests/test_realized/test_covariance.py +80 -0
- mfe_toolbox-0.1.0/tests/test_realized/test_cython_parity.py +155 -0
- mfe_toolbox-0.1.0/tests/test_realized/test_kernel.py +62 -0
- mfe_toolbox-0.1.0/tests/test_realized/test_range.py +56 -0
- mfe_toolbox-0.1.0/tests/test_realized/test_tsrv_qrv_mk.py +152 -0
- mfe_toolbox-0.1.0/tests/test_realized/test_variance.py +80 -0
- mfe_toolbox-0.1.0/tests/test_tests_stat/__init__.py +0 -0
- mfe_toolbox-0.1.0/tests/test_tests_stat/test_arch_lm.py +43 -0
- mfe_toolbox-0.1.0/tests/test_tests_stat/test_serial.py +68 -0
- mfe_toolbox-0.1.0/tests/test_timeseries/__init__.py +0 -0
- mfe_toolbox-0.1.0/tests/test_timeseries/test_beveridge_nelson.py +85 -0
- mfe_toolbox-0.1.0/tests/test_timeseries/test_var.py +142 -0
- mfe_toolbox-0.1.0/tests/test_univariate/__init__.py +0 -0
- mfe_toolbox-0.1.0/tests/test_univariate/test_har.py +35 -0
- mfe_toolbox-0.1.0/tests/test_univariate/test_har_extended.py +86 -0
- mfe_toolbox-0.1.0/tests/test_univariate/test_heavy.py +63 -0
- mfe_toolbox-0.1.0/uv.lock +2671 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
name: Deploy docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
deploy:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
permissions:
|
|
11
|
+
contents: write
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
- uses: actions/setup-python@v5
|
|
15
|
+
with:
|
|
16
|
+
python-version: "3.12"
|
|
17
|
+
- run: pip install mkdocs-material mkdocstrings[python]
|
|
18
|
+
- run: mkdocs gh-deploy --force
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
|
|
14
|
+
- uses: actions/setup-python@v5
|
|
15
|
+
with:
|
|
16
|
+
python-version: "3.12"
|
|
17
|
+
|
|
18
|
+
- run: pip install uv
|
|
19
|
+
- run: uv sync --all-groups
|
|
20
|
+
- run: uv build
|
|
21
|
+
|
|
22
|
+
- uses: actions/upload-artifact@v4
|
|
23
|
+
with:
|
|
24
|
+
name: dist
|
|
25
|
+
path: dist/
|
|
26
|
+
|
|
27
|
+
publish-testpypi:
|
|
28
|
+
needs: build
|
|
29
|
+
runs-on: ubuntu-latest
|
|
30
|
+
environment: testpypi
|
|
31
|
+
permissions:
|
|
32
|
+
id-token: write
|
|
33
|
+
steps:
|
|
34
|
+
- uses: actions/download-artifact@v4
|
|
35
|
+
with:
|
|
36
|
+
name: dist
|
|
37
|
+
path: dist/
|
|
38
|
+
|
|
39
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
40
|
+
with:
|
|
41
|
+
repository-url: https://test.pypi.org/legacy/
|
|
42
|
+
|
|
43
|
+
publish-pypi:
|
|
44
|
+
needs: publish-testpypi
|
|
45
|
+
runs-on: ubuntu-latest
|
|
46
|
+
environment: pypi
|
|
47
|
+
permissions:
|
|
48
|
+
id-token: write
|
|
49
|
+
steps:
|
|
50
|
+
- uses: actions/download-artifact@v4
|
|
51
|
+
with:
|
|
52
|
+
name: dist
|
|
53
|
+
path: dist/
|
|
54
|
+
|
|
55
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.pyo
|
|
6
|
+
.Python
|
|
7
|
+
|
|
8
|
+
# Virtual environments
|
|
9
|
+
.venv/
|
|
10
|
+
venv/
|
|
11
|
+
env/
|
|
12
|
+
|
|
13
|
+
# uv
|
|
14
|
+
.uv/
|
|
15
|
+
|
|
16
|
+
# Distribution / packaging
|
|
17
|
+
dist/
|
|
18
|
+
build/
|
|
19
|
+
*.egg-info/
|
|
20
|
+
*.egg
|
|
21
|
+
MANIFEST
|
|
22
|
+
|
|
23
|
+
# Cython compiled files
|
|
24
|
+
*.c
|
|
25
|
+
*.cpp
|
|
26
|
+
*.so
|
|
27
|
+
*.pyd
|
|
28
|
+
*.html # Cython annotation files (from annotate=True)
|
|
29
|
+
|
|
30
|
+
# Cython build artifacts
|
|
31
|
+
src/mfe/realized/_core.cpython-*.so
|
|
32
|
+
src/mfe/multivariate/_core.cpython-*.so
|
|
33
|
+
|
|
34
|
+
# setuptools build directories
|
|
35
|
+
build/
|
|
36
|
+
lib.*/
|
|
37
|
+
temp.*/
|
|
38
|
+
|
|
39
|
+
# pytest
|
|
40
|
+
.pytest_cache/
|
|
41
|
+
.cache/
|
|
42
|
+
htmlcov/
|
|
43
|
+
.coverage
|
|
44
|
+
coverage.xml
|
|
45
|
+
*.cover
|
|
46
|
+
|
|
47
|
+
# mypy
|
|
48
|
+
.mypy_cache/
|
|
49
|
+
.dmypy.json
|
|
50
|
+
|
|
51
|
+
# ruff
|
|
52
|
+
.ruff_cache/
|
|
53
|
+
|
|
54
|
+
# MkDocs
|
|
55
|
+
site/
|
|
56
|
+
|
|
57
|
+
# Jupyter
|
|
58
|
+
.ipynb_checkpoints/
|
|
59
|
+
*.ipynb
|
|
60
|
+
|
|
61
|
+
# IDE
|
|
62
|
+
.idea/
|
|
63
|
+
.vscode/
|
|
64
|
+
*.swp
|
|
65
|
+
*.swo
|
|
66
|
+
*~
|
|
67
|
+
.DS_Store
|
|
68
|
+
|
|
69
|
+
# Profiling
|
|
70
|
+
*.prof
|
|
71
|
+
*.lprof
|
|
72
|
+
|
|
73
|
+
# Local dev
|
|
74
|
+
.env
|
|
75
|
+
*.local
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: mfe-toolbox
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python port of the MFE Toolbox — financial econometrics for HFT data
|
|
5
|
+
Author: Gabin Taibi
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Requires-Python: >=3.11
|
|
8
|
+
Requires-Dist: arch>=6.2
|
|
9
|
+
Requires-Dist: numpy>=1.26
|
|
10
|
+
Requires-Dist: pandas>=2.1
|
|
11
|
+
Requires-Dist: scipy>=1.11
|
|
12
|
+
Requires-Dist: statsmodels>=0.14
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
|
|
15
|
+
# mfe — Financial Econometrics for Python
|
|
16
|
+
|
|
17
|
+
Python port of Kevin Sheppard's Oxford MFE Toolbox, optimised for HFT data.
|
|
18
|
+
Complements [`arch`](https://arch.readthedocs.io) — covering everything `arch` is missing.
|
|
19
|
+
|
|
20
|
+
## What's inside
|
|
21
|
+
|
|
22
|
+
| Module | Contents |
|
|
23
|
+
|--------|----------|
|
|
24
|
+
| `mfe.realized` | RV, BPV, MedRV, realized kernel, TSRV, MSRV, Hayashi-Yoshida, multivariate kernel, BNS jump test |
|
|
25
|
+
| `mfe.multivariate` | DCC, CCC, BEKK, O-GARCH, GO-GARCH, RCC |
|
|
26
|
+
| `mfe.univariate` | HAR-RV (standard / MODIFIED / matrix intervals / HAR-J), HEAVY |
|
|
27
|
+
| `mfe.timeseries` | VAR (4 VCV options), Granger causality, IRF, Beveridge-Nelson |
|
|
28
|
+
| `mfe.bootstrap` | Wild bootstrap, SPA test (Hansen 2005), StepM (Romano-Wolf 2005) |
|
|
29
|
+
| `mfe.crosssection` | Fama-MacBeth, OLS/OLSNW, PCA |
|
|
30
|
+
| `mfe.tests_stat` | ARCH-LM, Ljung-Box, HAC LM, Diebold-Mariano, Mincer-Zarnowitz |
|
|
31
|
+
| `mfe.distributions` | Skew-t (analytic score), GED, multivariate normal log-likelihood |
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pip install mfe
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Cython extensions (optional, recommended for production)
|
|
40
|
+
|
|
41
|
+
Cython compilation gives 10–800× speedups on hot paths (realized kernel inner
|
|
42
|
+
loop, Hayashi-Yoshida sweep, DCC/BEKK recursions):
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install cython numpy setuptools
|
|
46
|
+
python setup_cython.py build_ext --inplace
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Quick start
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
from mfe.realized import price_filter, returns_from_prices, realized_kernel, bns_jump_test
|
|
53
|
+
from mfe.realized._types import SamplingType
|
|
54
|
+
|
|
55
|
+
prices_5m, times_5m = price_filter(
|
|
56
|
+
tick_prices, tick_times,
|
|
57
|
+
sampling_type=SamplingType.CALENDAR_TIME,
|
|
58
|
+
sampling_interval=300,
|
|
59
|
+
)
|
|
60
|
+
r = returns_from_prices(prices_5m)
|
|
61
|
+
rk = realized_kernel(r)
|
|
62
|
+
jmp = bns_jump_test(r)
|
|
63
|
+
|
|
64
|
+
from mfe.multivariate import DCC, RCC
|
|
65
|
+
dcc = DCC().fit(returns) # (T, K) → (T, K, K) sigma_t
|
|
66
|
+
rcc = RCC().fit(returns) # covariance targeting by construction
|
|
67
|
+
|
|
68
|
+
from mfe.univariate import HEAVY
|
|
69
|
+
heavy = HEAVY().fit(daily_returns, realized_variances)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Development
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
uv sync --all-groups
|
|
76
|
+
PYTHONPATH=src pytest tests/ # 246 tests
|
|
77
|
+
mkdocs serve # documentation
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Relationship to MATLAB MFE Toolbox
|
|
81
|
+
|
|
82
|
+
This package ports [bashtage/mfe-toolbox](https://github.com/bashtage/mfe-toolbox)
|
|
83
|
+
to Python, fixing several bugs present in the MATLAB source (memory leaks, silent
|
|
84
|
+
non-convergence, O(N²) algorithms replaced with O(N log N) Cython implementations).
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# mfe — Financial Econometrics for Python
|
|
2
|
+
|
|
3
|
+
Python port of Kevin Sheppard's Oxford MFE Toolbox, optimised for HFT data.
|
|
4
|
+
Complements [`arch`](https://arch.readthedocs.io) — covering everything `arch` is missing.
|
|
5
|
+
|
|
6
|
+
## What's inside
|
|
7
|
+
|
|
8
|
+
| Module | Contents |
|
|
9
|
+
|--------|----------|
|
|
10
|
+
| `mfe.realized` | RV, BPV, MedRV, realized kernel, TSRV, MSRV, Hayashi-Yoshida, multivariate kernel, BNS jump test |
|
|
11
|
+
| `mfe.multivariate` | DCC, CCC, BEKK, O-GARCH, GO-GARCH, RCC |
|
|
12
|
+
| `mfe.univariate` | HAR-RV (standard / MODIFIED / matrix intervals / HAR-J), HEAVY |
|
|
13
|
+
| `mfe.timeseries` | VAR (4 VCV options), Granger causality, IRF, Beveridge-Nelson |
|
|
14
|
+
| `mfe.bootstrap` | Wild bootstrap, SPA test (Hansen 2005), StepM (Romano-Wolf 2005) |
|
|
15
|
+
| `mfe.crosssection` | Fama-MacBeth, OLS/OLSNW, PCA |
|
|
16
|
+
| `mfe.tests_stat` | ARCH-LM, Ljung-Box, HAC LM, Diebold-Mariano, Mincer-Zarnowitz |
|
|
17
|
+
| `mfe.distributions` | Skew-t (analytic score), GED, multivariate normal log-likelihood |
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install mfe
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Cython extensions (optional, recommended for production)
|
|
26
|
+
|
|
27
|
+
Cython compilation gives 10–800× speedups on hot paths (realized kernel inner
|
|
28
|
+
loop, Hayashi-Yoshida sweep, DCC/BEKK recursions):
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pip install cython numpy setuptools
|
|
32
|
+
python setup_cython.py build_ext --inplace
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Quick start
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
from mfe.realized import price_filter, returns_from_prices, realized_kernel, bns_jump_test
|
|
39
|
+
from mfe.realized._types import SamplingType
|
|
40
|
+
|
|
41
|
+
prices_5m, times_5m = price_filter(
|
|
42
|
+
tick_prices, tick_times,
|
|
43
|
+
sampling_type=SamplingType.CALENDAR_TIME,
|
|
44
|
+
sampling_interval=300,
|
|
45
|
+
)
|
|
46
|
+
r = returns_from_prices(prices_5m)
|
|
47
|
+
rk = realized_kernel(r)
|
|
48
|
+
jmp = bns_jump_test(r)
|
|
49
|
+
|
|
50
|
+
from mfe.multivariate import DCC, RCC
|
|
51
|
+
dcc = DCC().fit(returns) # (T, K) → (T, K, K) sigma_t
|
|
52
|
+
rcc = RCC().fit(returns) # covariance targeting by construction
|
|
53
|
+
|
|
54
|
+
from mfe.univariate import HEAVY
|
|
55
|
+
heavy = HEAVY().fit(daily_returns, realized_variances)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Development
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
uv sync --all-groups
|
|
62
|
+
PYTHONPATH=src pytest tests/ # 246 tests
|
|
63
|
+
mkdocs serve # documentation
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Relationship to MATLAB MFE Toolbox
|
|
67
|
+
|
|
68
|
+
This package ports [bashtage/mfe-toolbox](https://github.com/bashtage/mfe-toolbox)
|
|
69
|
+
to Python, fixing several bugs present in the MATLAB source (memory leaks, silent
|
|
70
|
+
non-convergence, O(N²) algorithms replaced with O(N log N) Cython implementations).
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Performance benchmarks for mfe.realized on HFT-scale data.
|
|
3
|
+
|
|
4
|
+
Run with:
|
|
5
|
+
cd repo_root
|
|
6
|
+
PYTHONPATH=src python dev/benchmarks/bench_realized.py
|
|
7
|
+
|
|
8
|
+
Or with pytest-benchmark:
|
|
9
|
+
PYTHONPATH=src pytest dev/benchmarks/bench_realized.py --benchmark-only
|
|
10
|
+
|
|
11
|
+
Target: all operations on T=1_000_000 ticks should complete in < 5s
|
|
12
|
+
on a modern CPU without Cython (pure numpy). With Cython, kernel inner
|
|
13
|
+
loop should be ~10x faster.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import time
|
|
17
|
+
|
|
18
|
+
import numpy as np
|
|
19
|
+
|
|
20
|
+
from mfe.realized import (
|
|
21
|
+
realized_variance,
|
|
22
|
+
realized_bipower_variation,
|
|
23
|
+
realized_med_variance,
|
|
24
|
+
realized_kernel,
|
|
25
|
+
bns_jump_test,
|
|
26
|
+
)
|
|
27
|
+
from mfe.realized.covariance import realized_hayashi_yoshida
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _make_returns(T: int, seed: int = 0) -> np.ndarray:
|
|
31
|
+
rng = np.random.default_rng(seed)
|
|
32
|
+
return rng.standard_normal(T) * 0.001
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _make_tick_prices(T: int, seed: int = 0):
|
|
36
|
+
rng = np.random.default_rng(seed)
|
|
37
|
+
price = np.exp(np.cumsum(rng.standard_normal(T) * 0.001))
|
|
38
|
+
time_ = np.sort(rng.uniform(0, 23400, T))
|
|
39
|
+
return price, time_
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def bench(label: str, fn, *args, n_runs: int = 3):
|
|
43
|
+
times = []
|
|
44
|
+
for _ in range(n_runs):
|
|
45
|
+
t0 = time.perf_counter()
|
|
46
|
+
fn(*args)
|
|
47
|
+
times.append(time.perf_counter() - t0)
|
|
48
|
+
mean_ms = np.mean(times) * 1000
|
|
49
|
+
print(f" {label:<40s} {mean_ms:8.1f} ms (n={n_runs})")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
if __name__ == "__main__":
|
|
53
|
+
print("=" * 60)
|
|
54
|
+
print("mfe.realized benchmarks")
|
|
55
|
+
print("=" * 60)
|
|
56
|
+
|
|
57
|
+
for T in [10_000, 100_000, 500_000]:
|
|
58
|
+
print(f"\nT = {T:,} returns")
|
|
59
|
+
r = _make_returns(T)
|
|
60
|
+
|
|
61
|
+
bench("realized_variance", realized_variance, r)
|
|
62
|
+
bench("realized_bipower_variation (skip=0)", realized_bipower_variation, r, 0)
|
|
63
|
+
bench("realized_bipower_variation (skip=1)", realized_bipower_variation, r, 1)
|
|
64
|
+
bench("realized_med_variance", realized_med_variance, r)
|
|
65
|
+
bench("realized_kernel (auto bandwidth)", realized_kernel, r)
|
|
66
|
+
bench("bns_jump_test", bns_jump_test, r)
|
|
67
|
+
|
|
68
|
+
print(f"\nHayashi-Yoshida bivariate (non-synchronous)")
|
|
69
|
+
for T in [1_000, 5_000, 10_000]:
|
|
70
|
+
p1, t1 = _make_tick_prices(T, seed=0)
|
|
71
|
+
p2, t2 = _make_tick_prices(T, seed=1)
|
|
72
|
+
# HY is O(N1 * N2) in worst case with the current numpy impl
|
|
73
|
+
bench(f" HY T={T:,}", realized_hayashi_yoshida, [p1, p2], [t1, t2], n_runs=2)
|
|
74
|
+
|
|
75
|
+
print()
|
|
76
|
+
print("NOTE: Cython uses event-sweep with swap-remove open-list.")
|
|
77
|
+
print(" Complexity: O((N1+N2)*log(N1+N2)) sort + O((N1+N2)*k) sweep")
|
|
78
|
+
print(" where k = avg simultaneous open intervals (typically O(1) for HFT data).")
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 (2026-09)
|
|
4
|
+
|
|
5
|
+
Initial release — Python port of the Oxford MFE Toolbox.
|
|
6
|
+
|
|
7
|
+
### mfe.realized
|
|
8
|
+
- `realized_variance`, `realized_bipower_variation` (skip-k), `realized_med_variance`, `realized_min_variance`, `realized_preaveraged_variance`, `realized_semivariance`, `realized_quantile_variance`
|
|
9
|
+
- `realized_kernel` (Parzen/Bartlett/Tukey-Hanning/Cubic/Epanechnikov/FlatTop, auto-bandwidth)
|
|
10
|
+
- `tsrv`, `msrv` — Two-Scale and Multi-Scale Realized Variance
|
|
11
|
+
- `realized_covariance`, `realized_correlation`, `realized_hayashi_yoshida`, `realized_covariance_refresh_time`
|
|
12
|
+
- `realized_multivariate_kernel` — PSD-guaranteed (K,K) multivariate realized kernel
|
|
13
|
+
- `realized_range`, `realized_range_from_ticks`
|
|
14
|
+
- `bns_jump_test`, `estimate_noise_variance`, `realized_quarticity`, `realized_tripower_quarticity`
|
|
15
|
+
- `price_filter`, `returns_from_prices`, `refresh_time`
|
|
16
|
+
- Cython extensions: `_autocovariance_sum`, `_bpv_sum`, `_medvar_triplets`, `_hy_sweep`, `_refresh_time_indices`
|
|
17
|
+
|
|
18
|
+
### mfe.multivariate
|
|
19
|
+
- `DCC` (Engle 2002) with cDCC and DECO variants
|
|
20
|
+
- `CCC` (Bollerslev 1990)
|
|
21
|
+
- `BEKK` scalar and diagonal (Engle & Kroner 1995)
|
|
22
|
+
- `OGARCH` (Alexander 2001)
|
|
23
|
+
- `GOGARCH` ICA and moments rotation (van der Weide 2002)
|
|
24
|
+
- `RCC` symmetric and Cholesky rotation (Noureldin, Shephard & Sheppard 2014)
|
|
25
|
+
- Cython extensions: `_dcc_q_recursion`, `_dcc_corr_loglik`, `_bekk_scalar_recursion`, `_bekk_diagonal_recursion`
|
|
26
|
+
|
|
27
|
+
### mfe.univariate
|
|
28
|
+
- `har_rv` — standard, MODIFIED spec, matrix intervals
|
|
29
|
+
- `har_rv_j` — jump-augmented HAR
|
|
30
|
+
- `har_forecast` — multi-step forecasting
|
|
31
|
+
- `HEAVY` — joint model of returns + realized variance (Shephard & Sheppard 2010)
|
|
32
|
+
|
|
33
|
+
### mfe.timeseries
|
|
34
|
+
- `vectorar` — VAR(P) with 4 VCV options (homo/het × corr/uncorr)
|
|
35
|
+
- `grangercause` — Granger causality LR/LM/Wald with robust VCV
|
|
36
|
+
- `impulse_response` — IRF with delta-method standard errors
|
|
37
|
+
- `beveridge_nelson` — AR and state-space methods, auto order selection
|
|
38
|
+
|
|
39
|
+
### mfe.bootstrap
|
|
40
|
+
- `wild_bootstrap_rv`, `wild_bootstrap_test` — Rademacher/Mammen/Normal multipliers
|
|
41
|
+
- `spa_test` — Hansen (2005) SPA: consistent, upper (Reality Check), lower p-values
|
|
42
|
+
- `step_m` — Romano & Wolf (2005) stepdown FWER control
|
|
43
|
+
|
|
44
|
+
### mfe.crosssection
|
|
45
|
+
- `ols`, `olsnw` — OLS with White / Newey-West SEs
|
|
46
|
+
- `fama_macbeth` — Fama-MacBeth with Shanken correction
|
|
47
|
+
- `rolling_betas`, `pca`
|
|
48
|
+
|
|
49
|
+
### mfe.tests_stat
|
|
50
|
+
- `ljung_box` — Ljung-Box Q statistic
|
|
51
|
+
- `lm_test` — HAC-robust LM serial correlation test (MFE lmtest1.m)
|
|
52
|
+
- `arch_lm` — Engle (1982) ARCH-LM test (LM form + F form)
|
|
53
|
+
- `mincer_zarnowitz` — MZ regression forecast evaluation
|
|
54
|
+
- `diebold_mariano` — DM test (MSE/MAE/QLIKE loss)
|
|
55
|
+
|
|
56
|
+
### mfe.distributions
|
|
57
|
+
- `skewt_logpdf`, `skewt_ppf`, `skewt_score` — Hansen (1994) Skew-t with analytic gradient
|
|
58
|
+
- `ged_logpdf`, `ged_ppf`, `ged_score` — Generalized Error Distribution
|
|
59
|
+
- `mvnorm_loglik`, `mvnorm_loglik_t`, `mahalanobis`, `standardize_mvn`
|
|
60
|
+
|
|
61
|
+
### mfe.utils
|
|
62
|
+
- `lag_matrix`, `har_lag_matrix`
|
|
63
|
+
- `sandwich`, `newey_west`
|
|
64
|
+
- Type aliases: `FloatArray`, `IntArray`, etc.
|
|
65
|
+
|
|
66
|
+
### Bugs fixed vs. MATLAB source
|
|
67
|
+
- `gogarch.m`: memory leak via closure over `volData` inside `fmincon` loop → eliminated
|
|
68
|
+
- All univariate estimators: `MFEToolbox:Convergence` silently used bad params → `ConvergenceWarning`
|
|
69
|
+
- `realized_kernel.m`: parameter validation mixed into hot path → separated
|
|
70
|
+
- `realized_bipower_variation.m`: inconsistent `skip` default → standardised to 0
|
|
71
|
+
- `dcc.m`: `Q_bar` recomputed inside likelihood → pre-computed
|
|
72
|
+
- No sandwich VCV in MATLAB multivariate → standard in all `mfe` estimators
|
|
73
|
+
- `realized_hayashi_yoshida.m` TODO for K>2 → implemented for general K
|
|
74
|
+
- HY Cython: `sort_key = time * 4 + type` loses bits for large timestamps → `np.lexsort`
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Bootstrap & Multiple Testing
|
|
2
|
+
|
|
3
|
+
## Wild bootstrap (realized volatility)
|
|
4
|
+
|
|
5
|
+
```python
|
|
6
|
+
from mfe.bootstrap import wild_bootstrap_rv, wild_bootstrap_test
|
|
7
|
+
|
|
8
|
+
# 95% CI for a realized volatility statistic
|
|
9
|
+
result = wild_bootstrap_rv(r, n_replications=999, multiplier="rademacher")
|
|
10
|
+
print(f"Statistic: {result.statistic:.6f}")
|
|
11
|
+
print(f"95% CI: [{result.ci_lower:.6f}, {result.ci_upper:.6f}]")
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## SPA test (Superior Predictive Ability)
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
from mfe.bootstrap import spa_test
|
|
18
|
+
|
|
19
|
+
# loss_benchmark: (T,) loss for benchmark model
|
|
20
|
+
# loss_models: (T, M) losses for M alternatives (lower = better)
|
|
21
|
+
res = spa_test(loss_benchmark, loss_models, n_bootstrap=999)
|
|
22
|
+
print(f"SPA p-value (consistent): {res.p_value_consistent:.3f}")
|
|
23
|
+
print(f"Reality Check p-value: {res.p_value_upper:.3f}")
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## StepM (Romano-Wolf FWER control)
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from mfe.bootstrap import step_m
|
|
30
|
+
|
|
31
|
+
res = step_m(loss_benchmark, loss_models, alpha=0.05, n_bootstrap=999)
|
|
32
|
+
print(f"Models beating benchmark: {res.rejected}") # indices, 0-based
|
|
33
|
+
print(f"FWER-adjusted p-values: {res.p_values_adjusted.round(3)}")
|
|
34
|
+
```
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# mfe vs. arch vs. statsmodels
|
|
2
|
+
|
|
3
|
+
## Decision guide
|
|
4
|
+
|
|
5
|
+
| Task | Use |
|
|
6
|
+
|---|---|
|
|
7
|
+
| GARCH / EGARCH / TARCH / APARCH estimation | [`arch`](https://arch.readthedocs.io) |
|
|
8
|
+
| FIGARCH, HARCH, MIDAS-GARCH | `arch` |
|
|
9
|
+
| Unit root tests (ADF, PP, KPSS, DFGLS) | `arch.unitroot` |
|
|
10
|
+
| Cointegration (Johansen, Engle-Granger) | `statsmodels` |
|
|
11
|
+
| ARMA/ARMAX estimation | `statsmodels` |
|
|
12
|
+
| VAR with robust VCV options | **`mfe`** |
|
|
13
|
+
| Granger causality with heteroskedastic VCV | **`mfe`** |
|
|
14
|
+
| Impulse response functions under heteroskedasticity | **`mfe`** |
|
|
15
|
+
| Realized variance / BPV / MedRV | **`mfe`** |
|
|
16
|
+
| Realized kernel (noise-robust) | **`mfe`** |
|
|
17
|
+
| TSRV / MSRV (two-scale noise correction) | **`mfe`** |
|
|
18
|
+
| Hayashi-Yoshida non-synchronous covariance | **`mfe`** |
|
|
19
|
+
| Multivariate realized kernel (PSD guaranteed) | **`mfe`** |
|
|
20
|
+
| DCC-GARCH | **`mfe`** |
|
|
21
|
+
| BEKK-GARCH | **`mfe`** |
|
|
22
|
+
| CCC-GARCH | **`mfe`** |
|
|
23
|
+
| GO-GARCH / O-GARCH | **`mfe`** |
|
|
24
|
+
| RCC (Rotated Conditional Correlation) | **`mfe`** |
|
|
25
|
+
| HAR-RV model | **`mfe`** |
|
|
26
|
+
| HEAVY model (realized variance in mean equation) | **`mfe`** |
|
|
27
|
+
| Beveridge-Nelson decomposition | **`mfe`** |
|
|
28
|
+
| SPA test / StepM FWER | **`mfe`** |
|
|
29
|
+
| Wild bootstrap for realized volatility | **`mfe`** |
|
|
30
|
+
| Fama-MacBeth regression | **`mfe`** |
|
|
31
|
+
| OLS with White / Newey-West SEs | **`mfe`** (thin wrapper) or `statsmodels` |
|
|
32
|
+
| PCA with financial conventions | **`mfe`** |
|
|
33
|
+
| Hansen Skew-t / GED distributions (standalone) | **`mfe`** |
|
|
34
|
+
|
|
35
|
+
## Key API differences
|
|
36
|
+
|
|
37
|
+
### arch (univariate, correct home for GARCH)
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
from arch import arch_model
|
|
41
|
+
am = arch_model(returns, vol="Garch", p=1, q=1)
|
|
42
|
+
res = am.fit()
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### mfe (multivariate, realized, everything arch doesn't cover)
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
from mfe.multivariate import DCC
|
|
49
|
+
from mfe.realized import realized_kernel
|
|
50
|
+
|
|
51
|
+
dcc = DCC().fit(returns) # (T, K) → (T, K, K) sigma_t
|
|
52
|
+
rk = realized_kernel(r) # noise-robust RV
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### statsmodels (ARIMA, VAR basic, cointegration)
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from statsmodels.tsa.api import VAR
|
|
59
|
+
mod = VAR(data)
|
|
60
|
+
res = mod.fit(maxlags=2)
|
|
61
|
+
# → no robust VCV, no GC test with het-robust options
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from mfe.timeseries import vectorar, grangercause
|
|
66
|
+
res = vectorar(data, lags=2, het=True) # White-robust VCV
|
|
67
|
+
gc = grangercause(data, lags=2, method="wald") # Wald test with robust VCV
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## What mfe does NOT replace
|
|
71
|
+
|
|
72
|
+
- `arch` for any univariate GARCH estimation — we use `arch` internally for
|
|
73
|
+
the first step of DCC/RCC/CCC.
|
|
74
|
+
- `statsmodels` for ARIMA, SARIMA, SARIMAX estimation.
|
|
75
|
+
- `scipy.signal` for filtering.
|
|
76
|
+
- `sklearn.decomposition.PCA` for general-purpose PCA (our PCA is tailored to
|
|
77
|
+
financial returns with covariance convention and factor interpretation tools).
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Cross-Section
|
|
2
|
+
|
|
3
|
+
## OLS and OLSNW
|
|
4
|
+
|
|
5
|
+
```python
|
|
6
|
+
from mfe.crosssection import ols, olsnw
|
|
7
|
+
|
|
8
|
+
# Y = alpha + X beta + eps
|
|
9
|
+
res = ols(y, X) # White-robust SEs
|
|
10
|
+
res_nw = olsnw(y, X, nw_lags=6) # Newey-West HAC SEs
|
|
11
|
+
|
|
12
|
+
print(res.params, res.std_errors, res.r_squared)
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Fama-MacBeth
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
from mfe.crosssection import fama_macbeth, rolling_betas
|
|
19
|
+
|
|
20
|
+
# Pass 1: rolling betas
|
|
21
|
+
betas = rolling_betas(returns, factors, window=60) # (N, K)
|
|
22
|
+
|
|
23
|
+
# Pass 2: FM
|
|
24
|
+
fm = fama_macbeth(returns, betas, include_intercept=True, shanken_correction=True)
|
|
25
|
+
print(fm.lambda_mean) # (K+1,) mean risk premia
|
|
26
|
+
print(fm.t_stats_shanken) # Shanken-corrected t-stats
|
|
27
|
+
print(fm.r_squared_mean) # mean cross-sectional R²
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## PCA
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
from mfe.crosssection import pca
|
|
34
|
+
|
|
35
|
+
res = pca(returns, n_components=3)
|
|
36
|
+
print(res.explained_variance) # proportion per component
|
|
37
|
+
print(res.cumulative_variance) # cumulative
|
|
38
|
+
factors = res.factors # (T, 3) principal components
|
|
39
|
+
loadings = res.loadings # (K, 3) factor loadings
|
|
40
|
+
recon = res.reconstruct(k_c=3) # (T, K) reconstruction from 3 PCs
|
|
41
|
+
```
|