Python package
grubeta
A physics-informed dual-pathway GRU that estimates time-varying CAPM beta while preserving the pricing identity it is estimating — packaged for PyPI with lookahead diagnostics built into the validation path rather than bolted on.
- Distribution
- PyPI
- Validation
- Walk-forward
- Benchmarks
- 3
The problem with a single number
In the CAPM framework, beta measures how strongly a stock moves with the market. It is conventionally estimated as one static coefficient over a historical window — a five-year regression producing a single number.
Market sensitivity is not static. It shifts through crises, earnings announcements, sector rotations, and regime changes. A stock whose beta was 0.85 through a calm year and 1.42 through a drawdown is not well described by the 1.12 that a pooled regression reports, and the difference matters precisely when it matters most: a hedge sized on the average is wrong exactly during the episodes it was bought for.
Rolling-window regression is the usual patch. It trades one problem for two: the window length becomes a free parameter nobody can justify, and the estimate lags every regime change by roughly half the window.
Why a plain neural network is the wrong answer
The obvious move — throw a recurrent network at returns and let it learn beta — discards the reason anyone wants beta in the first place. CAPM's structure is what makes the coefficient interpretable; a free-form network that predicts returns well may do so through a relationship that is not beta at all, and there is no way to tell from the loss.
grubeta is physics-informed in that sense: the architecture preserves the CAPM relation rather than learning around it. A dual-pathway GRU separates the systematic component from the idiosyncratic one, so the quantity the network emits is structurally constrained to be the thing the theory names, and the output stays interpretable as beta rather than as an unnamed latent that happens to fit.
The composite loss encodes what a good beta path looks like, not merely an accurate one:
- Huber on accuracy, so a handful of violent days do not dominate the fit;
- L2 on the path's roughness, because beta that jumps daily is estimation noise wearing a trend's clothing;
- L1 for sparsity, keeping the model from spreading explanation across every available input.
The stability term is the one that earns its place. Without it the estimator produces a technically-lower-loss path that is unusable for hedging, because the position it implies changes every day.
Validation is the actual product
Anything that predicts financial time series is guilty until proven innocent, and the usual mechanism of guilt is lookahead: a feature that quietly encodes information from after the moment it claims to be available. It inflates results and it is nearly invisible in a notebook.
So the validation path is the part of this package I would defend first:
- Walk-forward with anchored expanding windows — the model is refit as time advances and never scored on data it could have seen.
- Strict feature lagging throughout, enforced in construction rather than checked afterward.
- Explicit lookahead diagnostics as a first-class output.
- 63-day out-of-sample validation on 28 XU030 constituents.
- Benchmarks against the alternatives that already work — Kalman filter, GARCH-DCC, and rolling OLS. A dynamic-beta estimator that cannot beat a Kalman filter has not established anything, and comparing only against a static regression would be choosing a straw man.
Packaged to be used
The research is only useful if someone else can run it, so the default path is one call:
```python
from grubeta import estimate_beta
result = estimate_beta("AAPL", "SPY")
print(result["summary"])
```
```
AAPL Dynamic Beta Summary (2016-03-19 to 2026-03-19)
─────────────────────────────────────────────────────
Current Beta: 1.18
Average Beta: 1.12
Beta Range: 0.85 → 1.42
Stability: 0.034 (daily change std)
Systematic R²: 0.52
```
Presets cover the common cases — an event-study configuration that tracks rapid
change around earnings and crises, a smoother configuration for hedging — so
that using the package does not require tuning a model you did not build. Acompare_betas helper runs a cross-section in one call, and the hedging use case
is worked through in the documentation rather than left as an exercise.
Distributed on PyPI under MIT with documentation on Read the Docs, a test suite,
and CI. A manuscript is in preparation for arXiv/SSRN.
This package reports estimates, not advice. The benchmarks establish that theestimator is competitive on out-of-sample beta accuracy; they do not establishthat trading on it makes money, and the documentation does not claim otherwise.