squeeze-kernel 0.3.0__tar.gz → 0.4.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.
- {squeeze_kernel-0.3.0 → squeeze_kernel-0.4.0}/PKG-INFO +7 -1
- {squeeze_kernel-0.3.0 → squeeze_kernel-0.4.0}/README.md +6 -0
- {squeeze_kernel-0.3.0 → squeeze_kernel-0.4.0}/pyproject.toml +1 -1
- {squeeze_kernel-0.3.0 → squeeze_kernel-0.4.0}/src/squeeze_kernel/__init__.py +1 -1
- {squeeze_kernel-0.3.0 → squeeze_kernel-0.4.0}/src/squeeze_kernel/estimator.py +37 -3
- {squeeze_kernel-0.3.0 → squeeze_kernel-0.4.0}/src/squeeze_kernel/batch.py +0 -0
- {squeeze_kernel-0.3.0 → squeeze_kernel-0.4.0}/src/squeeze_kernel/kernels.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: squeeze-kernel
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Streaming, PSD-by-construction covariance estimator with Fisher-kernel weighting and adaptive shrinkage
|
|
5
5
|
Keywords: covariance,correlation,ewma,kernel,risk,streaming
|
|
6
6
|
Author: Robert Kende
|
|
@@ -130,6 +130,12 @@ est = SqueezeKernelEstimator(n_assets=100, kappa=1.0, weight_statistic="mahalano
|
|
|
130
130
|
est = SqueezeKernelEstimator(n_assets=100, vol_anchor_phi=0.995)
|
|
131
131
|
```
|
|
132
132
|
|
|
133
|
+
**Cluster shrinkage target** (`shrinkage_target="cluster"`): generalizes the equicorrelation shrinkage target to respect the correlation matrix's own block/cluster structure — with **no clustering algorithm**. The target morphs with the shrinkage intensity, T = (1−α)·T_equi + α·[(1−γ)I + γ·(C∘C)], where C∘C is the Hadamard square of the current correlation (positive semi-definite by the Schur product theorem; entries are pairwise shared-variance fractions) and γ is level-matched automatically. Zero added parameters, still O(n²), and as α→0 it reduces exactly to the default estimator. Held-out one-step NLL on the S&P 500 benchmark: ±0.1 at n=100, **−4.2 at n=200, −25.0 at n=300** — recommended whenever the universe size approaches the effective sample size.
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
est = SqueezeKernelEstimator(n_assets=300, shrinkage_target="cluster")
|
|
137
|
+
```
|
|
138
|
+
|
|
133
139
|
**Alternative kernels**: pass `kernel_fn=kernel_exponential` (with `kernel_kwargs={"gamma": ...}`) or `kernel_chi2_cdf`, or any callable `(d2, *, n_observed, **kw) -> float` mapping to `[0, 1)`. The PSD guarantee holds for any such kernel.
|
|
134
140
|
|
|
135
141
|
## How it works
|
|
@@ -100,6 +100,12 @@ est = SqueezeKernelEstimator(n_assets=100, kappa=1.0, weight_statistic="mahalano
|
|
|
100
100
|
est = SqueezeKernelEstimator(n_assets=100, vol_anchor_phi=0.995)
|
|
101
101
|
```
|
|
102
102
|
|
|
103
|
+
**Cluster shrinkage target** (`shrinkage_target="cluster"`): generalizes the equicorrelation shrinkage target to respect the correlation matrix's own block/cluster structure — with **no clustering algorithm**. The target morphs with the shrinkage intensity, T = (1−α)·T_equi + α·[(1−γ)I + γ·(C∘C)], where C∘C is the Hadamard square of the current correlation (positive semi-definite by the Schur product theorem; entries are pairwise shared-variance fractions) and γ is level-matched automatically. Zero added parameters, still O(n²), and as α→0 it reduces exactly to the default estimator. Held-out one-step NLL on the S&P 500 benchmark: ±0.1 at n=100, **−4.2 at n=200, −25.0 at n=300** — recommended whenever the universe size approaches the effective sample size.
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
est = SqueezeKernelEstimator(n_assets=300, shrinkage_target="cluster")
|
|
107
|
+
```
|
|
108
|
+
|
|
103
109
|
**Alternative kernels**: pass `kernel_fn=kernel_exponential` (with `kernel_kwargs={"gamma": ...}`) or `kernel_chi2_cdf`, or any callable `(d2, *, n_observed, **kw) -> float` mapping to `[0, 1)`. The PSD guarantee holds for any such kernel.
|
|
104
110
|
|
|
105
111
|
## How it works
|
|
@@ -4,7 +4,7 @@ build-backend = "uv_build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "squeeze-kernel"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.4.0"
|
|
8
8
|
description = "Streaming, PSD-by-construction covariance estimator with Fisher-kernel weighting and adaptive shrinkage"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -93,6 +93,20 @@ class SqueezeKernelEstimator:
|
|
|
93
93
|
Decay of the slow per-asset variance anchor (default 0.999,
|
|
94
94
|
effective memory ≈ 1000 trading days). Only used when
|
|
95
95
|
``vol_anchor_phi`` is set.
|
|
96
|
+
shrinkage_target : str
|
|
97
|
+
Geometry of the adaptive shrinkage target. ``'equicorrelation'``
|
|
98
|
+
(default) is the published single-factor target. ``'cluster'``
|
|
99
|
+
uses the concentration-morphing cluster target
|
|
100
|
+
T = (1−α)·T_equi + α·[(1−γ)I + γ·(C∘C)], where C∘C is the Hadamard
|
|
101
|
+
square of the current correlation (PSD by the Schur product
|
|
102
|
+
theorem) and γ = min(1, ρ̄/mean-offdiag(C∘C)) level-matches the
|
|
103
|
+
target to the equicorrelation mass. Respects the correlation
|
|
104
|
+
matrix's own block/cluster structure without any clustering
|
|
105
|
+
algorithm; adds no parameters and stays O(n²). As α → 0 it
|
|
106
|
+
reduces exactly to the published estimator, so behaviour at low
|
|
107
|
+
concentration is unchanged. Held-out one-step NLL on the S&P-500
|
|
108
|
+
benchmark: +0.14 (negligible) at n=100, −4.2 at n=200, −25.0 at
|
|
109
|
+
n=300. Recommended when n approaches the effective sample size.
|
|
96
110
|
|
|
97
111
|
Examples
|
|
98
112
|
--------
|
|
@@ -123,6 +137,7 @@ class SqueezeKernelEstimator:
|
|
|
123
137
|
lambda_corr_fast: float | None = None,
|
|
124
138
|
vol_anchor_phi: float | None = None,
|
|
125
139
|
vol_anchor_decay: float = 0.999,
|
|
140
|
+
shrinkage_target: str = "equicorrelation",
|
|
126
141
|
):
|
|
127
142
|
self.n_assets = n_assets
|
|
128
143
|
self.lambda_vol = lambda_vol
|
|
@@ -145,6 +160,9 @@ class SqueezeKernelEstimator:
|
|
|
145
160
|
raise ValueError("vol_anchor_decay must be in (0, 1).")
|
|
146
161
|
self.vol_anchor_phi = vol_anchor_phi
|
|
147
162
|
self.vol_anchor_decay = vol_anchor_decay
|
|
163
|
+
if shrinkage_target not in ("equicorrelation", "cluster"):
|
|
164
|
+
raise ValueError("shrinkage_target must be 'equicorrelation' or 'cluster'.")
|
|
165
|
+
self.shrinkage_target = shrinkage_target
|
|
148
166
|
|
|
149
167
|
# Resolve shrinkage
|
|
150
168
|
if isinstance(shrinkage, str):
|
|
@@ -384,9 +402,25 @@ class SqueezeKernelEstimator:
|
|
|
384
402
|
if alpha > 0.0 and n > 1:
|
|
385
403
|
# Off-diagonal mean: O(n^2) sum, no mask allocation.
|
|
386
404
|
rho_bar = (corr.sum() - corr.trace()) / self._n_off
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
405
|
+
if self.shrinkage_target == "equicorrelation" or rho_bar <= 0.0:
|
|
406
|
+
corr *= (1.0 - alpha)
|
|
407
|
+
corr += alpha * rho_bar
|
|
408
|
+
np.fill_diagonal(corr, 1.0)
|
|
409
|
+
else:
|
|
410
|
+
# Cluster (concentration-morphing) target:
|
|
411
|
+
# T = (1-alpha) T_equi + alpha [(1-gamma) I + gamma (C o C)]
|
|
412
|
+
# C o C is the Hadamard square of the raw correlation (PSD by
|
|
413
|
+
# the Schur product theorem, unit diagonal for free); gamma is
|
|
414
|
+
# level-matched so the target carries the same average
|
|
415
|
+
# correlation mass as the equicorrelation target. As
|
|
416
|
+
# alpha -> 0 this reduces exactly to the published estimator.
|
|
417
|
+
had = corr * corr # Hadamard square, O(n^2)
|
|
418
|
+
mean_off = (had.sum() - np.trace(had)) / self._n_off
|
|
419
|
+
gamma = min(1.0, rho_bar / max(mean_off, eps))
|
|
420
|
+
corr *= (1.0 - alpha)
|
|
421
|
+
corr += (alpha * (1.0 - alpha)) * rho_bar
|
|
422
|
+
corr += (alpha * alpha * gamma) * had
|
|
423
|
+
np.fill_diagonal(corr, 1.0)
|
|
390
424
|
|
|
391
425
|
# Build covariance from corr and vol_t. We need an output array
|
|
392
426
|
# that the caller can keep, so allocate one cov here (cannot reuse
|
|
File without changes
|
|
File without changes
|