dscc 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.
@@ -0,0 +1 @@
1
+ * text=auto eol=lf
@@ -0,0 +1,23 @@
1
+ name: tests
2
+ on: [push, pull_request]
3
+ jobs:
4
+ test:
5
+ runs-on: ${{ matrix.os }}
6
+ strategy:
7
+ fail-fast: false
8
+ matrix:
9
+ os: [ubuntu-latest, windows-latest]
10
+ python-version: ["3.9", "3.11", "3.12"]
11
+ no_numba: ["0", "1"] # "1" = pure-NumPy code path
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+ - uses: actions/setup-python@v5
15
+ with:
16
+ python-version: ${{ matrix.python-version }}
17
+ - run: python -m pip install --upgrade pip
18
+ - run: pip install -e ".[test]"
19
+ - if: matrix.no_numba == '0'
20
+ run: pip install numba
21
+ - run: pytest -q
22
+ env:
23
+ DSCC_NO_NUMBA: ${{ matrix.no_numba }}
dscc-0.1.0/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ build/
5
+ dist/
6
+ .pytest_cache/
7
+ .venv/
8
+ venv/
9
+ .ipynb_checkpoints/
10
+ examples/results/
11
+ results/
12
+ *.nbi
13
+ *.nbc
14
+ .DS_Store
15
+ examples/results_log.txt
@@ -0,0 +1,11 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 — 2026-11-05
4
+ - Explicit minimal representation Σ = P^δ e^Υ Λ e^{−Υ} P^δ (Abadir 2023).
5
+ - DSCC with GARCH (2.5) and EGARCH (2.6)–(2.7) eigenvalue dynamics; ARMA(1,1) skew-symmetric dynamics (2.9).
6
+ - Maximum likelihood with greedy per-period δ_t, multi-start, best-point tracking and a Powell polish; profile-likelihood standard errors.
7
+ - Multistep forecasts (Section 4), in the paper's form and in the authors' replication form; the "-av" variant.
8
+ - Elliptope analytics: exact vol(E_k), slice coverage, exact slab-projection benchmark, DCC simulation (cDCC / Engle / iid).
9
+ - DCC(1,1) baseline; GMV portfolios; AV/SD/IR, TO/GL/PL, HAC pairwise tests, v/Δ/d/Δ′/κ; rolling backtest.
10
+ - Parula default colour scale; journal-style tables (text, LaTeX, Markdown) and figures.
11
+ - Optional numba kernels, with a pure-NumPy fallback that gives identical results.
@@ -0,0 +1,34 @@
1
+ cff-version: 1.2.0
2
+ message: "If you use this software, please cite both the package and the original articles."
3
+ title: "dscc: Dynamic Spectral Conditional Correlations in Python"
4
+ version: 0.1.0
5
+ date-released: 2026-11-05
6
+ license: MIT
7
+ authors:
8
+ - family-names: Roudane
9
+ given-names: Merwan
10
+ email: merwanroudane920@gmail.com
11
+ repository-code: "https://github.com/merwanroudane/dscc"
12
+ keywords: [DSCC, DCC, multivariate volatility, correlation, elliptope, portfolio]
13
+ references:
14
+ - type: article
15
+ title: "Dynamic Spectral Conditional Correlations"
16
+ authors:
17
+ - family-names: Abadir
18
+ given-names: Karim M.
19
+ - family-names: Rockinger
20
+ given-names: Michael
21
+ journal: "Econometrics Journal"
22
+ year: 2026
23
+ doi: "10.1093/ectj/utag017"
24
+ - type: article
25
+ title: "Explicit minimal representation of variance matrices, and its implication for dynamic volatility models"
26
+ authors:
27
+ - family-names: Abadir
28
+ given-names: Karim M.
29
+ journal: "Econometrics Journal"
30
+ volume: 26
31
+ start: 88
32
+ end: 104
33
+ year: 2023
34
+ doi: "10.1093/ectj/utac023"
dscc-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Merwan Roudane
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.
dscc-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,448 @@
1
+ Metadata-Version: 2.5
2
+ Name: dscc
3
+ Version: 0.1.0
4
+ Summary: Dynamic Spectral Conditional Correlations (DSCC) and dynamic spectral heteroskedasticity (DSH) models: estimation, forecasting, elliptope coverage and minimum-variance portfolios
5
+ Project-URL: Homepage, https://merwanroudane.github.io/dscc/
6
+ Project-URL: Documentation, https://merwanroudane.github.io/dscc/
7
+ Project-URL: Repository, https://github.com/merwanroudane/dscc
8
+ Project-URL: Issues, https://github.com/merwanroudane/dscc/issues
9
+ Project-URL: Paper, https://doi.org/10.1093/ectj/utag017
10
+ Author-email: Dr Merwan Roudane <merwanroudane920@gmail.com>
11
+ License: MIT
12
+ License-File: LICENSE
13
+ Keywords: DCC,DSCC,correlation,econometrics,elliptope,multivariate GARCH,portfolio,volatility
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Topic :: Office/Business :: Financial :: Investment
19
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
20
+ Requires-Python: >=3.9
21
+ Requires-Dist: matplotlib>=3.5
22
+ Requires-Dist: numpy>=1.22
23
+ Requires-Dist: pandas>=1.4
24
+ Requires-Dist: scipy>=1.9
25
+ Provides-Extra: fast
26
+ Requires-Dist: numba>=0.57; extra == 'fast'
27
+ Provides-Extra: interactive
28
+ Requires-Dist: plotly>=5; extra == 'interactive'
29
+ Provides-Extra: test
30
+ Requires-Dist: pytest>=7; extra == 'test'
31
+ Description-Content-Type: text/markdown
32
+
33
+ # dscc
34
+
35
+ [![PyPI](https://img.shields.io/pypi/v/dscc.svg)](https://pypi.org/project/dscc/)
36
+ [![Python](https://img.shields.io/pypi/pyversions/dscc.svg)](https://pypi.org/project/dscc/)
37
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
38
+ [![Docs](https://img.shields.io/badge/docs-GitHub%20Pages-blue)](https://merwanroudane.github.io/dscc/)
39
+
40
+ **dscc** implements the *Dynamic Spectral Conditional Correlation* (DSCC) model of
41
+ Abadir and Rockinger (2026, *Econometrics Journal*,
42
+ [doi:10.1093/ectj/utag017](https://doi.org/10.1093/ectj/utag017)), built on the explicit
43
+ minimal representation of variance matrices of Abadir (2023, *Econometrics Journal* 26,
44
+ 88–104, [doi:10.1093/ectj/utac023](https://doi.org/10.1093/ectj/utac023)). You get
45
+ estimation, multistep forecasts, the elliptope-coverage benchmark, a DCC baseline and a
46
+ complete minimum-variance portfolio evaluation, with tables and figures ready for a
47
+ journal.
48
+
49
+ 📖 **Documentation:** https://merwanroudane.github.io/dscc/
50
+ 📦 **PyPI:** https://pypi.org/project/dscc/
51
+ 🧑‍💻 **Author:** Dr Merwan Roudane · merwanroudane920@gmail.com · https://github.com/merwanroudane
52
+
53
+ ---
54
+
55
+ ## Table of contents
56
+ 1. [What this package does](#1-what-this-package-does)
57
+ 2. [Start from absolutely nothing](#2-start-from-absolutely-nothing)
58
+ 3. [Installation](#3-installation)
59
+ 4. [Your first analysis in 60 seconds](#4-your-first-analysis-in-60-seconds)
60
+ 5. [Complete example with real data](#5-complete-example-with-real-data)
61
+ 6. [Full syntax reference](#6-full-syntax-reference)
62
+ 7. [Interpreting the output](#7-interpreting-the-output)
63
+ 8. [Using your own Excel or CSV file](#8-using-your-own-excel-or-csv-file)
64
+ 9. [Exporting tables and figures](#9-exporting-tables-and-figures)
65
+ 10. [The method](#10-the-method)
66
+ 11. [Fidelity to the paper and to the authors' code](#11-fidelity-to-the-paper-and-to-the-authors-code)
67
+ 12. [Practical guidance and pitfalls](#12-practical-guidance-and-pitfalls)
68
+ 13. [Limitations](#13-limitations)
69
+ 14. [References](#14-references)
70
+ 15. [Citation](#15-citation)
71
+ 16. [Author and licence](#16-author-and-licence)
72
+
73
+ ---
74
+
75
+ ## 1. What this package does
76
+
77
+ Correlation matrices must stay positive definite, and most multivariate volatility models
78
+ pay for that by restricting the matrices they can reach. DSCC writes every conditional
79
+ variance matrix as
80
+
81
+ $$\Sigma_t = P^{\delta_t} e^{\Upsilon_t}\,\Lambda_t\,e^{-\Upsilon_t} P^{\delta_t},$$
82
+
83
+ with an unrestricted skew-symmetric $\Upsilon_t$, positive eigenvalues $\Lambda_t$ and a
84
+ binary $\delta_t$. Every parameter is free (up to $k$ simple sign conditions), the
85
+ representation is minimal, and it spans the whole space of correlation matrices.
86
+
87
+ You give the package a $(T\times k)$ table of returns. It gives you back:
88
+
89
+ - **Estimation** of DSCC-λ<sub>garch</sub> (eq. 2.5) and DSCC-λ<sub>egarch</sub> (eqs 2.6–2.7) by maximum likelihood (2.13), with in-sample $\hat\delta_t$, multi-start optimisation and standard errors.
90
+ - **Conditional variances and correlations** $\Sigma_t$, $\Omega_t$ (2.14), standardised residuals, eigenvalue paths.
91
+ - **Multistep forecasts** (Section 4), including the "-av" variant, in the paper's form or exactly as in the authors' MATLAB code.
92
+ - **The span benchmark** of Section 3: exact volume of the elliptope $E_k$, slice-by-slice convex-hull coverage, DCC simulation, Table 1 and Figures 1–3.
93
+ - **A DCC(1,1) baseline** (Engle 2002).
94
+ - **Portfolio evaluation** of Section 5: global minimum-variance weights, AV/SD/IR, turnover and leverage, HAC pairwise tests, the v/Δ/d/Δ′/κ diagnostics, and a rolling monthly backtest (Tables 2–6, Figures 4–5).
95
+ - **Journal-quality output**: aligned text tables with stars, LaTeX (booktabs) and Markdown export, figures in vector PDF and 300-dpi PNG, MATLAB's Parula as the default colour scale.
96
+
97
+ ## 2. Start from absolutely nothing
98
+
99
+ *If you have never used Python, do these four steps once. They take about fifteen minutes.*
100
+
101
+ ### Step 1 — install Python
102
+ Download **Anaconda** from https://www.anaconda.com/download. It is the recommended option for researchers: one installer gives you Python, Jupyter and Spyder. Alternatively, install plain Python from https://www.python.org/downloads/; on the first screen of that installer, **tick "Add Python to PATH"**.
103
+
104
+ ### Step 2 — open a terminal
105
+ - **Windows:** press `Win`, type `Anaconda Prompt` (or `cmd`), press Enter.
106
+ - **macOS:** press `Cmd+Space`, type `Terminal`, press Enter.
107
+
108
+ Check that Python works by typing this and pressing Enter:
109
+ ```bash
110
+ python --version
111
+ ```
112
+ You should see something like `Python 3.11.5`.
113
+
114
+ ### Step 3 — install this package
115
+ ```bash
116
+ pip install "dscc[fast]"
117
+ ```
118
+ (`[fast]` also installs `numba`, which makes the estimation about four times faster. Plain `pip install dscc` works too.)
119
+
120
+ ### Step 4 — run your first command
121
+ Type `python`, press Enter, then paste:
122
+ ```python
123
+ import dscc
124
+ print(dscc.__version__)
125
+ ```
126
+ Type `exit()` to leave.
127
+
128
+ ### Where do I write my code?
129
+ | Tool | Best for | How to open |
130
+ |---|---|---|
131
+ | **Jupyter Notebook** | step-by-step work with the figures shown inline | type `jupyter notebook` in the terminal |
132
+ | **Spyder** | a window like MATLAB or RStudio | type `spyder`, or open it from Anaconda Navigator |
133
+ | **A `.py` file** | a reproducible script | save `analysis.py`, then run `python analysis.py` |
134
+
135
+ ## 3. Installation
136
+
137
+ ```bash
138
+ pip install dscc # core: numpy, scipy, pandas, matplotlib
139
+ pip install "dscc[fast]" # + numba (about 4x faster likelihood)
140
+ pip install "dscc[interactive]" # + plotly
141
+ ```
142
+ Development version:
143
+ ```bash
144
+ pip install git+https://github.com/merwanroudane/dscc.git
145
+ ```
146
+ Requires Python ≥ 3.9.
147
+
148
+ ## 4. Your first analysis in 60 seconds
149
+
150
+ Two Fama–French daily factors, the last 1,000 days of the paper's sample (the data are downloaded once from the Kenneth R. French Data Library, then cached):
151
+
152
+ ```python
153
+ import dscc
154
+
155
+ ff = dscc.datasets.load_ff5_daily(end="2022-03-31")
156
+ data = ff[["Mkt-RF", "HML"]].iloc[-1000:]
157
+
158
+ res = dscc.DSCC(data, dynamics="egarch").fit(n_starts=3, seed=1)
159
+ print(res.summary())
160
+
161
+ fc = res.forecast(H=21, init="average") # one trading month ahead
162
+ print(dscc.correlation_from_cov(fc.mean_sigma)[0, 1])
163
+ print(dscc.gmv_weights(fc.mean_sigma))
164
+ ```
165
+
166
+ Output:
167
+
168
+ ```text
169
+ ==============================================================================
170
+ Dynamic Spectral Conditional Correlation -- ML estimates
171
+ ==============================================================================
172
+ Model: DSCC-egarch (2.6) Log-likelihood: -2508.149
173
+ Variables (k): 2 AIC: 5042.297
174
+ Observations (T): 1000 BIC: 5106.085
175
+ Q2t complement: householder Converged: yes
176
+ ------------------------------------------------------------------------------
177
+ coef std err t P>|t| [0.025 0.975]
178
+ ------------------------------------------------------------------------------
179
+ Eigenvalue dynamics, Lambda_t
180
+ D0[Mkt-RF] -0.2204 0.0562 -3.921 0.000 -0.331 -0.110 ***
181
+ D0[HML] -0.1563 0.0201 -7.793 0.000 -0.196 -0.117 ***
182
+ D11[Mkt-RF] 0.9609 0.0179 53.774 0.000 0.926 0.996 ***
183
+ D11[HML] 0.9786 0.0068 143.392 0.000 0.965 0.992 ***
184
+ D21[Mkt-RF] 0.2348 0.0512 4.586 0.000 0.134 0.335 ***
185
+ D21[HML] 0.1853 0.0237 7.813 0.000 0.139 0.232 ***
186
+ Skew-symmetric dynamics, Upsilon_t (2.9)
187
+ mu[Mkt-RF,HML] 1.6690 0.0134 124.989 0.000 1.643 1.695 ***
188
+ alpha[Mkt-RF,HML] 0.9293 0.0135 68.658 0.000 0.903 0.956 ***
189
+ beta[Mkt-RF,HML] -0.0201 0.0027 -7.441 0.000 -0.025 -0.015 ***
190
+ Asymmetry function g (2.7)
191
+ a[Mkt-RF] -0.2265 0.0959 -2.362 0.018 -0.414 -0.039 **
192
+ a[HML] 0.2479 0.1172 2.114 0.034 0.018 0.478 **
193
+ c[Mkt-RF] 0.0562 0.0321 1.751 0.080 -0.007 0.119 *
194
+ c[HML] 0.2140 0.1275 1.678 0.093 -0.036 0.464 *
195
+ ------------------------------------------------------------------------------
196
+ Permutation component delta_t (Proposition 2.1, eq. 2.13)
197
+ share of t with delta_t = 1: 0.5095 psi = Pr(delta = 0): 0.4905
198
+ ==============================================================================
199
+ Notes: *** p<0.01, ** p<0.05, * p<0.10. Standard errors from the numerical Hessian
200
+ of the profile log-likelihood with delta_t held at its MLE; '--' = not available
201
+ (parameter on a bound, or non-positive local curvature). Gaussian innovations.
202
+
203
+ Forecast correlation, average over the next 21 days: -0.471
204
+ Minimum-variance weights: [0.508 0.492]
205
+ ```
206
+
207
+ ## 5. Complete example with real data
208
+
209
+ `examples/ff5_dscc_example.py` runs the whole paper on public data: the Fama–French five daily factors (Mkt-RF, SMB, HML, RMW, CMA), 2 January 1980 to 31 March 2022, in percent. These are exactly the five factors whose covariance matrix Abadir and Rockinger model with DSCC in Section 5.
210
+
211
+ ```bash
212
+ python examples/ff5_dscc_example.py --months 60 --out results
213
+ ```
214
+
215
+ The script follows the paper section by section.
216
+
217
+ **Step 1 — estimate on the first five-year window (1,260 days), as in the paper:**
218
+ ```python
219
+ ff = dscc.datasets.load_ff5_daily(start="1980-01-02", end="2022-03-31")
220
+ factors = ff[["Mkt-RF", "SMB", "HML", "RMW", "CMA"]]
221
+ window = factors.iloc[:1260]
222
+ res = dscc.DSCC(window, dynamics="egarch").fit()
223
+ print(res.summary())
224
+ ```
225
+
226
+ **Step 2 — correlations, eigenvalues and forecasts:**
227
+ ```python
228
+ res.plot_correlations(); res.plot_eigenvalues()
229
+ fc = res.forecast(21, init="average") # DSCC-lambda_egarch-av
230
+ ```
231
+
232
+ **Step 3 — the span benchmark (Section 3, Table 1):**
233
+ ```python
234
+ from dscc import elliptope as el
235
+ el.elliptope_volume(3) # pi^2/2
236
+ tab = el.coverage_table(T=400_000, innovations="iid", slice_on=0)
237
+ ```
238
+
239
+ **Step 4 — the monthly minimum-variance backtest (Section 5):**
240
+ ```python
241
+ fcs = [dscc.EqualWeight(), dscc.SampleCovForecaster(), dscc.DCCForecaster(),
242
+ dscc.DSCCForecaster("garch", init="last"),
243
+ dscc.DSCCForecaster("egarch", init="average")]
244
+ bt = dscc.rolling_backtest(factors, fcs, n_months=60)
245
+ bt.performance_table() # Table 2
246
+ bt.pairwise() # Table 3
247
+ bt.turnover_table() # Table 4
248
+ bt.covariance_table() # Tables 5-6
249
+ dscc.plot_wealth(bt) # Figure 4
250
+ ```
251
+
252
+ The script prints every table and writes them as `.tex`, `.md` and `.csv` files, together with
253
+ the figures (PDF and 300-dpi PNG), into the folder given by `--out`.
254
+
255
+ ## 6. Full syntax reference
256
+
257
+ ### `DSCC(data, dynamics="garch", demean=True, complement="householder", xi=None)`
258
+ The model.
259
+
260
+ | Argument | Type | Default | Meaning |
261
+ |---|---|---|---|
262
+ | `data` | DataFrame or (T, k) array | — | returns; column names are carried into every table |
263
+ | `dynamics` | `"garch"`, `"egarch"` | `"garch"` | eigenvalue dynamics: eq. (2.5) or eqs (2.6)–(2.7) |
264
+ | `demean` | bool | `True` | subtract the sample mean (Abadir 2023, §4.2) |
265
+ | `complement` | `"householder"`, `"eig"` | `"householder"` | how the orthogonal complement $Q_{2t}$ in (2.10) is built; irrelevant for k = 2 |
266
+ | `xi` | (T, l) array or None | `None` | precomputed $\xi_t$ of (2.11); pass the authors' MATLAB series to reproduce their likelihood exactly |
267
+
268
+ Methods: `.fit(...)` → `DSCCResults`; `.loglike(theta)` → float (eq. 2.13); `.filter(theta)` → paths.
269
+
270
+ ### `DSCC.fit(start=None, n_starts=1, seed=0, method="SLSQP", maxiter=500, se=True, polish=True, polish_maxiter=20, verbose=False)`
271
+
272
+ | Argument | Default | Meaning |
273
+ |---|---|---|
274
+ | `start` | eq. (5.1) of Abadir (2023) | starting parameter vector |
275
+ | `n_starts` | `1` | number of starts; the extra ones are random draws in the admissible region (the paper's §5.5 uses 10) |
276
+ | `seed` | `0` | seed of the random starts |
277
+ | `method` | `"SLSQP"` | SciPy optimiser; SLSQP enforces $d_{1i}+d_{2i}<1$ |
278
+ | `se` | `True` | standard errors from the profile likelihood with $\delta_t$ fixed at its MLE |
279
+ | `polish` | `True` | derivative-free Powell polish of the best point found |
280
+
281
+ Parameter order (k variables, l = k(k−1)/2): `D0 (k), D11 (k), D21 (k), mu (l), alpha (l), beta (l)`, plus `a (k), c (k)` for EGARCH. This is the same order as the authors' code.
282
+
283
+ ### `DSCCResults`
284
+ | Attribute / method | Returns | Meaning |
285
+ |---|---|---|
286
+ | `.params`, `.bse`, `.tvalues`, `.pvalues` | Series | estimates and Wald inference |
287
+ | `.loglik`, `.aic`, `.bic` | float | fit statistics |
288
+ | `.delta`, `.psi` | array, float | in-sample $\hat\delta_t$; $\hat\psi=\Pr(\delta=0)$ |
289
+ | `.lam`, `.ups` | arrays | $\Lambda_t$ and the free elements of $\Upsilon_t$ |
290
+ | `.sigma(t=None)`, `.correlation(t=None)` | (k,k) or (T,k,k) | $\Sigma_t$ (2.12), $\Omega_t$ (2.14) |
291
+ | `.std_resid()` | (T,k) | $\varepsilon_t=\Sigma_t^{-1/2}x_t$ |
292
+ | `.forecast(H=21, mode="paper", init="last")` | `DSCCForecast` | Section 4 forecasts; `.sigma`, `.correlation`, `.mean_sigma` |
293
+ | `.summary()`, `.to_frame()`, `.to_latex()`, `.to_markdown()` | str / DataFrame | tables |
294
+ | `.plot_correlations()`, `.plot_eigenvalues()` | Figure | figures |
295
+
296
+ `forecast` options: `mode="paper"` iterates $\Upsilon$ with (2.9) and weights the two δ-branches by $\hat\psi$ at every horizon. `mode="replication"` reproduces the authors' scripts. `init="average"` is the "-av" variant.
297
+
298
+ ### `dscc.elliptope`
299
+ | Function | Meaning |
300
+ |---|---|
301
+ | `elliptope_volume(k)` | exact volume of $E_k$ ($\pi^2/2$ for k = 3, eq. 3.2) |
302
+ | `ellipse_slice_area(c)` | $\pi\sqrt{1-c^2}$, the section of $E_3$ at a fixed correlation |
303
+ | `slab_projection_area(lb, ub)` | exact maximal area of a slab (a sharper benchmark than the paper's) |
304
+ | `simulate_dcc(S, alpha, beta, T, innovations="cdcc")` | DCC paths; `"iid"` is the authors' simulator, `"engle"` Engle (2002) |
305
+ | `slice_coverage(points, n_slices=8, slice_on=2, benchmark="paper")` | Table 1 for one design |
306
+ | `coverage_table(...)` | the full Table 1 |
307
+ | `equicorrelation`, `toeplitz_corr`, `uniform_perturbation` | the designs of Table 1 |
308
+
309
+ ### `dscc.portfolio`, `dscc.backtest`, `dscc.DCC`
310
+ | Function | Meaning |
311
+ |---|---|
312
+ | `gmv_weights(Sigma)` | $w=\Sigma^{-1}\iota/\iota'\Sigma^{-1}\iota$ |
313
+ | `performance(daily)` | AV, SD (annualised, percent) and IR |
314
+ | `turnover_leverage(W, R_list)` | TO, GL, PL |
315
+ | `hac_mean_test(d)`, `pairwise_tests(monthly)` | one-sided Newey–West tests (Table 3) |
316
+ | `covariance_summaries(Sigmas)` | $v_h$, $\Delta_h$ (5.2), $d_h$, $\Delta'_h$ (5.3), $\kappa_h$ |
317
+ | `rolling_backtest(returns, forecasters, window=1260, horizon=21, holding="buy_and_hold")` | monthly GMV backtest |
318
+ | `DSCCForecaster`, `DCCForecaster`, `SampleCovForecaster`, `EqualWeight` | the competing models |
319
+ | `DCC(data).fit()` | Engle (2002) DCC(1,1); `.forecast(H)` |
320
+
321
+ ### Data and colours
322
+ `datasets.load_ff5_daily(path=None, start=None, end=None)` and `datasets.load_industry_daily(n=10)` download and cache the French library files (they are not redistributed with the package). `parula_colors(n)`, `matlab_jet_colors`, `turbo_colors`, `bluered_colors`, `sinha_colors`, `resolve_colorscale("Parula")` and `get_cmap("Parula")` handle colours.
323
+
324
+ ## 7. Interpreting the output
325
+
326
+ **The summary table.**
327
+ - *D0, D11, D21* are the GARCH (or EGARCH) coefficients of each eigenvalue $\lambda_{it}$. *D11* is the persistence and *D21* the reaction to the newest rotated return $z_{t-1}$.
328
+ - *mu, alpha, beta* drive each free element $\upsilon_{ijt}$ of the rotation:
329
+ - *mu* is its long-run level, in radians.
330
+ - *alpha* is its persistence.
331
+ - *beta* is the loading on the data innovation $\xi_{ij,t-1}$.
332
+
333
+ A large |alpha| means the eigenvectors, and so the correlation structure, move slowly.
334
+ - *a, c* (EGARCH only) make the response asymmetric: $g_i(v)=|v_i-c_i|-a_i(v_i-c_i)$.
335
+ - The δ block reports the share of days on which the permuted branch $P\,e^{\Upsilon}$ fits better, and $\hat\psi=\Pr(\delta=0)$, which weights the two branches in forecasts.
336
+ - Stars use two-sided Wald p-values. "--" means the standard error is not available: the parameter sits on a bound, or the local Hessian is not positive there, which happens because $\delta_t$ makes the likelihood piecewise smooth.
337
+
338
+ **Table 1.** Each row is a slice of one correlation. "Max cover" is the largest area positive definiteness allows in that slice, and the other columns are the areas DCC actually reaches. DSCC reaches the maximum by construction.
339
+
340
+ **Tables 2–6.**
341
+ - AV, SD and IR are the annualised mean return, volatility and information ratio of daily out-of-sample returns.
342
+ - TO is turnover, GL gross leverage, and PL the share of short positions.
343
+ - In Table 3, a small p-value means Model 1 earns significantly more than Model 2.
344
+ - $\Delta'$ close to 0 means the forecast correlations are close to zero. A large κ means an ill-conditioned matrix.
345
+
346
+ ## 8. Using your own Excel or CSV file
347
+
348
+ ```python
349
+ import pandas as pd
350
+ import dscc
351
+
352
+ df = pd.read_excel("C:/Users/you/Documents/returns.xlsx", index_col=0, parse_dates=True)
353
+ # or: df = pd.read_csv("returns.csv", index_col=0, parse_dates=True)
354
+ df = df[["Asset1", "Asset2", "Asset3"]].dropna()
355
+
356
+ res = dscc.DSCC(df, dynamics="egarch").fit(n_starts=5)
357
+ print(res.summary())
358
+ ```
359
+ On Windows, write paths with forward slashes (`C:/...`) or doubled backslashes (`C:\\...`). Use returns, not prices, and no missing values. Percent returns (as in the French library) keep the parameters on the scale used in the paper.
360
+
361
+ ## 9. Exporting tables and figures
362
+
363
+ ```python
364
+ print(res.to_latex()) # paste into the manuscript
365
+ res.to_frame().to_excel("dscc_estimates.xlsx")
366
+ fig = res.plot_correlations()
367
+ dscc.save_figure(fig, "figure_correlations") # writes .pdf (vector) and .png (300 dpi)
368
+ ```
369
+
370
+ ## 10. The method
371
+
372
+ For $x_t$ with conditional variance $\Sigma_t$:
373
+
374
+ 1. **Representation** ([A23] Prop. 2.1; [AR26] 2.1): $\Sigma_t=P^{\delta_t}e^{\Upsilon_t}\Lambda_te^{-\Upsilon_t}P^{\delta_t}$, where $P$ swaps the first two variates.
375
+ 2. **Eigenvalues** (2.4)–(2.5): with $z_t=e^{-\Upsilon_t}P^{\delta_t}x_t$, $\Lambda_t=D_0+D_{11}\Lambda_{t-1}+D_{21}\,\mathrm{dg}(z_{t-1}z_{t-1}')$; or the EGARCH (2.6) with $g$ of (2.7).
376
+ 3. **Data innovations** (2.10)–(2.11): $x_tx_t'=Q_t\,\mathrm{diag}(x_t'x_t,0)Q_t'$, $|Q_t|=+1$, $\Xi_t=\log Q_t$ (principal value).
377
+ 4. **Rotation dynamics** (2.9): $\upsilon_{ijt}=(1-\alpha_{ij})\mu_{ij}+\alpha_{ij}\upsilon_{ij,t-1}+\beta_{ij}\xi_{ij,t-1}$.
378
+ 5. **Likelihood** (2.13): $\sum_t[\log f_\varepsilon(\Sigma_t^{-1/2}x_t)-\tfrac12\sum_i\log\lambda_{it}]$, with $\delta_t\in\{0,1\}$ chosen to maximise each summand.
379
+ 6. **Forecasts** (Section 4, eq. 4.1): the two δ-branches are iterated forward and weighted by $\hat\psi$.
380
+
381
+ The full step → equation map is in [docs/methods.md](docs/methods.md).
382
+
383
+ ## 11. Fidelity to the paper and to the authors' code
384
+
385
+ Every line was checked against the paper and against the authors' replication code (Zenodo, [doi:10.5281/zenodo.20817596](https://doi.org/10.5281/zenodo.20817596)). Where they disagree, the package follows the **paper** by default and offers an option that reproduces the **code**. The main points:
386
+
387
+ | Point | Paper | Authors' code | `dscc` |
388
+ |---|---|---|---|
389
+ | Complement $Q_{2t}$, k ≥ 3 | not specified | LAPACK's arbitrary null-space basis | deterministic Householder complement; `xi=` reproduces MATLAB |
390
+ | $\xi_t$, k = 2 | arcsin, eq. (4.5) of [A23] | principal log | principal log = atan2 (arcsin fails when $x_1<0$) |
391
+ | $\Upsilon$ over the forecast horizon | iterated with (2.9) | frozen at $\Upsilon_T$ | iterated; `mode="replication"` |
392
+ | DCC simulation, Table 1 | Aielli (2013) cDCC | iid innovations | cDCC; `innovations="iid"` reproduces Table 1 |
393
+ | Holding period | buy-and-hold | weights reset daily | buy-and-hold; `holding="constant"` |
394
+
395
+ Further checks:
396
+ - The general-k filter equals the bivariate closed form of [A23] to $10^{-13}$.
397
+ - $V_3=\pi^2/2$ is exact.
398
+ - The DCC column of Table 1 (ρ = 0.3) is reproduced to the second decimal.
399
+
400
+ The complete list, with measured effects, is in [docs/methods.md](docs/methods.md).
401
+
402
+ ## 12. Practical guidance and pitfalls
403
+
404
+ - **Use several starts.** Because $\delta_t$ switches, the likelihood has many local optima. `n_starts=10` is the paper's choice. On the paper's first window, a single start stopped 10 points below the best value found.
405
+ - **Scale.** Use percent returns. The starting values (5.1) of [A23] are calibrated for them.
406
+ - **Dimension.** The number of parameters grows as $3k(k+1)/2$ (GARCH): k = 5 gives 45, k = 10 gives 165. A 1,260 × 5 fit takes one to three minutes with numba.
407
+ - **k ≥ 3.** Estimates depend on the convention for $Q_{2t}$. Keep the default for reproducible results across machines.
408
+ - **Standard errors** treat $\delta_t$ as known. Read them as approximate.
409
+
410
+ ## 13. Limitations
411
+
412
+ - Only Gaussian innovations are implemented, as in the paper's applications.
413
+ - The NL-DCC (nonlinear-shrinkage DCC) block of De Nard, Ledoit and Wolf (2021), used for the 1,000-stock residuals, is not included. Neither is the CRSP stock data (restricted).
414
+ - The modified-likelihood estimation of the correlation-only parameters mentioned in Section 2.1 is left for future work, as in the paper.
415
+
416
+ ## 14. References
417
+
418
+ - Abadir, K. M. and M. Rockinger (2026). Dynamic spectral conditional correlations. *Econometrics Journal*. https://doi.org/10.1093/ectj/utag017
419
+ - Abadir, K. M. (2023). Explicit minimal representation of variance matrices, and its implication for dynamic volatility models. *Econometrics Journal* 26, 88–104. https://doi.org/10.1093/ectj/utac023
420
+ - Abadir, K. M. and M. Rockinger (2026). Replication package. Zenodo. https://doi.org/10.5281/zenodo.20817596
421
+ - Aielli, G. P. (2013). Dynamic conditional correlation: on properties and estimation. *Journal of Business and Economic Statistics* 31, 282–299.
422
+ - De Nard, G., O. Ledoit and M. Wolf (2021). Factor models for portfolio selection in large dimensions: the good, the better and the ugly. *Journal of Financial Econometrics* 19, 236–257.
423
+ - Engle, R. F. (2002). Dynamic conditional correlation. *Journal of Business and Economic Statistics* 20, 339–350. https://doi.org/10.1198/073500102288618487
424
+ - Lewandowski, D., D. Kurowicka and H. Joe (2009). Generating random correlation matrices based on vines and extended onion method. *Journal of Multivariate Analysis* 100, 1989–2001. https://doi.org/10.1016/j.jmva.2009.04.008
425
+ - Newey, W. K. and K. D. West (1987). A simple, positive semi-definite, heteroskedasticity and autocorrelation consistent covariance matrix. *Econometrica* 55, 703–708. https://doi.org/10.2307/1913610
426
+
427
+ *(Every DOI above was verified on https://doi.org/.)*
428
+
429
+ ## 15. Citation
430
+
431
+ ```bibtex
432
+ @software{roudane_dscc,
433
+ author = {Roudane, Merwan},
434
+ title = {{dscc}: Dynamic Spectral Conditional Correlations in Python},
435
+ year = {2026},
436
+ url = {https://github.com/merwanroudane/dscc},
437
+ version = {0.1.0}
438
+ }
439
+ ```
440
+ Please also cite Abadir and Rockinger (2026), doi:10.1093/ectj/utag017, and Abadir (2023), doi:10.1093/ectj/utac023.
441
+
442
+ ## 16. Author and licence
443
+
444
+ **Dr Merwan Roudane**
445
+ 📧 merwanroudane920@gmail.com
446
+ 🔗 https://github.com/merwanroudane
447
+
448
+ Released under the MIT Licence — see [LICENSE](LICENSE).