regimelab 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.
- regimelab-0.1.0/.gitignore +17 -0
- regimelab-0.1.0/LICENSE +21 -0
- regimelab-0.1.0/PKG-INFO +254 -0
- regimelab-0.1.0/README.md +213 -0
- regimelab-0.1.0/pyproject.toml +179 -0
- regimelab-0.1.0/src/regimelab/__init__.py +24 -0
- regimelab-0.1.0/src/regimelab/__main__.py +8 -0
- regimelab-0.1.0/src/regimelab/backtest/__init__.py +37 -0
- regimelab-0.1.0/src/regimelab/backtest/engine.py +365 -0
- regimelab-0.1.0/src/regimelab/backtest/metrics.py +345 -0
- regimelab-0.1.0/src/regimelab/backtest/walkforward.py +273 -0
- regimelab-0.1.0/src/regimelab/cli.py +195 -0
- regimelab-0.1.0/src/regimelab/data/__init__.py +22 -0
- regimelab-0.1.0/src/regimelab/data/alignment.py +396 -0
- regimelab-0.1.0/src/regimelab/data/fetcher.py +289 -0
- regimelab-0.1.0/src/regimelab/data/providers/__init__.py +75 -0
- regimelab-0.1.0/src/regimelab/data/providers/base.py +227 -0
- regimelab-0.1.0/src/regimelab/data/providers/parquet.py +150 -0
- regimelab-0.1.0/src/regimelab/data/providers/synthetic.py +261 -0
- regimelab-0.1.0/src/regimelab/data/providers/yahoo.py +152 -0
- regimelab-0.1.0/src/regimelab/features/__init__.py +217 -0
- regimelab-0.1.0/src/regimelab/features/_rolling.py +227 -0
- regimelab-0.1.0/src/regimelab/features/absorption.py +248 -0
- regimelab-0.1.0/src/regimelab/features/breadth.py +189 -0
- regimelab-0.1.0/src/regimelab/features/correlation.py +222 -0
- regimelab-0.1.0/src/regimelab/features/volatility.py +275 -0
- regimelab-0.1.0/src/regimelab/models/__init__.py +66 -0
- regimelab-0.1.0/src/regimelab/models/base.py +512 -0
- regimelab-0.1.0/src/regimelab/models/filters.py +283 -0
- regimelab-0.1.0/src/regimelab/models/gmm.py +150 -0
- regimelab-0.1.0/src/regimelab/models/hamilton.py +255 -0
- regimelab-0.1.0/src/regimelab/models/hmm.py +208 -0
- regimelab-0.1.0/src/regimelab/models/labeling.py +354 -0
- regimelab-0.1.0/src/regimelab/models/registry.py +57 -0
- regimelab-0.1.0/src/regimelab/models/types.py +351 -0
- regimelab-0.1.0/src/regimelab/pipeline.py +250 -0
- regimelab-0.1.0/src/regimelab/py.typed +0 -0
- regimelab-0.1.0/src/regimelab/report/__init__.py +12 -0
- regimelab-0.1.0/src/regimelab/report/html.py +380 -0
- regimelab-0.1.0/src/regimelab/settings.py +345 -0
- regimelab-0.1.0/src/regimelab/store.py +264 -0
- regimelab-0.1.0/src/regimelab/tui/__init__.py +39 -0
- regimelab-0.1.0/src/regimelab/tui/app.py +105 -0
- regimelab-0.1.0/tests/__init__.py +1 -0
- regimelab-0.1.0/tests/conftest.py +56 -0
- regimelab-0.1.0/tests/test_backtest.py +118 -0
- regimelab-0.1.0/tests/test_causality.py +148 -0
regimelab-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 AlgorithmicMind
|
|
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.
|
regimelab-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: regimelab
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Institutional market-regime detection engine: HMM/Hamilton regime switching, PCA absorption ratio, VIX term structure, point-in-time backtesting and automated reporting.
|
|
5
|
+
Project-URL: Homepage, https://github.com/AlgorithmicMind/regimelab
|
|
6
|
+
Project-URL: Repository, https://github.com/AlgorithmicMind/regimelab
|
|
7
|
+
Project-URL: Issues, https://github.com/AlgorithmicMind/regimelab/issues
|
|
8
|
+
Author-email: AlgorithmicMind <tonidinero27@gmail.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: absorption-ratio,backtesting,hidden-markov-model,point-in-time,quantitative-finance,regime-detection,systemic-risk
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
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 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.12
|
|
24
|
+
Requires-Dist: hmmlearn>=0.3.3
|
|
25
|
+
Requires-Dist: numpy>=2.5.2
|
|
26
|
+
Requires-Dist: pandas>=3.0.5
|
|
27
|
+
Requires-Dist: platformdirs>=4.11.5
|
|
28
|
+
Requires-Dist: plotly>=6.0.0
|
|
29
|
+
Requires-Dist: pyarrow>=25.0.1
|
|
30
|
+
Requires-Dist: pydantic-settings>=2.15.0
|
|
31
|
+
Requires-Dist: pydantic>=2.13.5
|
|
32
|
+
Requires-Dist: rich>=15.0.0
|
|
33
|
+
Requires-Dist: scikit-learn>=1.9.0
|
|
34
|
+
Requires-Dist: scipy>=1.18.1
|
|
35
|
+
Requires-Dist: statsmodels>=0.15.0
|
|
36
|
+
Requires-Dist: typer>=0.27.2
|
|
37
|
+
Requires-Dist: yfinance>=1.7.0
|
|
38
|
+
Provides-Extra: tui
|
|
39
|
+
Requires-Dist: textual>=8.2.8; extra == 'tui'
|
|
40
|
+
Description-Content-Type: text/markdown
|
|
41
|
+
|
|
42
|
+
<div align="center">
|
|
43
|
+
|
|
44
|
+
# 🏛️ RegimeLab
|
|
45
|
+
|
|
46
|
+
**Institutional-grade market regime detection, systemic risk telemetry, and walk-forward asset allocation engine in Python.**
|
|
47
|
+
|
|
48
|
+
[](https://pypi.org/project/regimelab/)
|
|
49
|
+
[](https://www.python.org/downloads/)
|
|
50
|
+
[](https://opensource.org/licenses/MIT)
|
|
51
|
+
[](https://mypy-lang.org/)
|
|
52
|
+
[](https://github.com/astral-sh/ruff)
|
|
53
|
+
|
|
54
|
+
</div>
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## ⚡ Why RegimeLab?
|
|
59
|
+
|
|
60
|
+
Most open-source regime detection scripts fit a Hidden Markov Model (HMM) on the entire in-sample dataset and claim predictive power. In production quantitative finance, this fails due to three fatal flaws:
|
|
61
|
+
|
|
62
|
+
1. **Look-Ahead Bias:** Training filters without strict point-in-time (`asof`) truncation leaks future distribution moments into past states.
|
|
63
|
+
2. **Label Switching:** HMM/GMM state indices are mathematically interchangeable between refits. Without canonical sorting, "State 0" randomly alternates between Bull and Bear across rolling windows.
|
|
64
|
+
3. **Calendar Desynchronization:** Multi-asset cross-sections suffer from holiday mismatches, halted assets, and survivorship bias.
|
|
65
|
+
|
|
66
|
+
**RegimeLab** solves these operational hurdles, providing a turnkey, causal quantitative engine for systematic asset allocation and macro risk monitoring.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
### 📊 Feature Matrix: Raw Tooling vs. RegimeLab
|
|
71
|
+
|
|
72
|
+
| Challenge | Raw `hmmlearn` / `statsmodels` | RegimeLab Framework |
|
|
73
|
+
| :--- | :--- | :--- |
|
|
74
|
+
| **State Labeling** | Unordered integer states (permutes on refit) | **Deterministic Canonical Sorting** ($\frac{\mu}{\sigma}$ / conditional vol ordering) |
|
|
75
|
+
| **Temporal Clock** | In-sample full-sample fitting (Look-ahead) | **Strict Point-in-Time (`asof`) cursor** & expanding-window walk-forward |
|
|
76
|
+
| **Systemic Risk** | None | **Kritzman Absorption Ratio (PCA)**, VIX Term Spread & Sector Breadth |
|
|
77
|
+
| **Execution Reality** | Pure theoretical classification | **Walk-Forward Backtester** with transaction costs (bps) and confidence floors |
|
|
78
|
+
| **Data Ingestion** | Expects clean 2D NumPy array | **Multi-Asset PIT Alignment**, staleness budgets, synthetic & Parquet providers |
|
|
79
|
+
| **Reporting** | Matplotlib static plot | **Interactive Plotly HTML reports** + Textual TUI Terminal Dashboard |
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 🚀 Quickstart
|
|
84
|
+
|
|
85
|
+
### 1. Installation
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# Install from PyPI
|
|
89
|
+
pip install regimelab
|
|
90
|
+
|
|
91
|
+
# Or install with interactive TUI support
|
|
92
|
+
pip install "regimelab[tui]"
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### 2. Python API Usage
|
|
96
|
+
|
|
97
|
+
#### Current Market Regime Detection (3 lines)
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
from regimelab import Settings
|
|
101
|
+
from regimelab.pipeline import run_single_asof
|
|
102
|
+
|
|
103
|
+
# Run point-in-time regime inference for any historical or current date
|
|
104
|
+
settings = Settings(data={"provider": "yfinance"})
|
|
105
|
+
payload = run_single_asof(settings, asof="2024-12-31")
|
|
106
|
+
|
|
107
|
+
print(f"Detected Regime: {payload.regime.value}")
|
|
108
|
+
print(f"Confidence: {payload.probabilities.confidence:.2%}")
|
|
109
|
+
print(f"Target Allocation: {payload.target_weights.weights if payload.target_weights else {}}")
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
#### Extract Causal Systemic Risk Features
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
from regimelab import Settings
|
|
116
|
+
from regimelab.data.fetcher import load_aligned_panel
|
|
117
|
+
from regimelab.features import build_feature_matrix
|
|
118
|
+
|
|
119
|
+
settings = Settings(data={"provider": "yfinance"})
|
|
120
|
+
panel = load_aligned_panel(settings)
|
|
121
|
+
features = build_feature_matrix(panel, settings)
|
|
122
|
+
|
|
123
|
+
# Inspect causal feature matrix
|
|
124
|
+
print(features[["absorption_ratio", "absorption_delta", "vix_term_spread", "breadth"]].tail())
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
#### Walk-Forward Backtesting Engine
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
from regimelab import Settings
|
|
131
|
+
from regimelab.pipeline import run_pipeline
|
|
132
|
+
|
|
133
|
+
settings = Settings(
|
|
134
|
+
data={"provider": "synthetic"}, # Fully offline, reproducible dataset
|
|
135
|
+
model={"classifier": "hmm", "n_states": 4},
|
|
136
|
+
backtest={"transaction_cost_bps": 5.0, "confidence_floor": 0.5},
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
result = run_pipeline(settings, command="backtest_run")
|
|
140
|
+
metrics = result.backtest.metrics
|
|
141
|
+
|
|
142
|
+
print(f"Strategy CAGR: {metrics.cagr:.2%}")
|
|
143
|
+
print(f"Sharpe Ratio: {metrics.sharpe:.2f}")
|
|
144
|
+
print(f"Max Drawdown: {metrics.max_drawdown:.2%}")
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### 3. CLI & Terminal Dashboard
|
|
148
|
+
|
|
149
|
+
RegimeLab ships with a powerful Typer CLI:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
# 1. Run full walk-forward pipeline and generate interactive HTML report
|
|
153
|
+
regimelab run --report market_report.html
|
|
154
|
+
|
|
155
|
+
# 2. Inspect point-in-time telemetry for a specific date (JSON output)
|
|
156
|
+
regimelab asof 2023-10-15
|
|
157
|
+
|
|
158
|
+
# 3. Launch the full interactive Textual Terminal Dashboard
|
|
159
|
+
regimelab tui
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Additional CLI commands include `regimelab report OUTPUT` for direct HTML generation and `regimelab asof YYYY-MM-DD --output telemetry.json` for persisted JSON payloads.
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## 🧠 Core Methodology & Architecture
|
|
167
|
+
|
|
168
|
+
```text
|
|
169
|
+
┌──────────────────────────────────────────────┐
|
|
170
|
+
│ Data Layer (PIT Alignment & Caching) │
|
|
171
|
+
└──────────────────────┬───────────────────────┘
|
|
172
|
+
│
|
|
173
|
+
┌──────────────────────▼───────────────────────┐
|
|
174
|
+
│ Causal Features (PCA Absorption, Spread) │
|
|
175
|
+
└──────────────────────┬───────────────────────┘
|
|
176
|
+
│
|
|
177
|
+
┌──────────────────────▼───────────────────────┐
|
|
178
|
+
│ Models: Hamilton / HMM / GMM + Anti-Switch │
|
|
179
|
+
└──────────────────────┬───────────────────────┘
|
|
180
|
+
│
|
|
181
|
+
┌──────────────────────────────┴──────────────────────────────┐
|
|
182
|
+
▼ ▼
|
|
183
|
+
┌─────────────────────────┐ ┌─────────────────────────┐
|
|
184
|
+
│ Walk-Forward Engine │ │ Telemetry, HTML & TUI │
|
|
185
|
+
│ (Dynamic Allocations) │ │ (Interactive Artifacts) │
|
|
186
|
+
└─────────────────────────┘ └─────────────────────────┘
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### 1. Canonical State Labeling (`regimelab.models.labeling`)
|
|
190
|
+
|
|
191
|
+
To eliminate label switching, RegimeLab fits the underlying statistical model (Gaussian HMM, Hamilton Markov Switching, or GMM) and evaluates the conditional distribution parameters of each state. States are sorted by risk-adjusted return ($\frac{\mu}{\sigma}$) and mapped deterministically to:
|
|
192
|
+
|
|
193
|
+
- **BULL_TREND** (High return, low volatility)
|
|
194
|
+
- **NEUTRAL_TRANSITION** (Moderate return, mean-reverting)
|
|
195
|
+
- **HIGH_VOL_BEAR** (Negative drift, elevated variance)
|
|
196
|
+
- **RISK_OFF** (Severe drawdown regime)
|
|
197
|
+
|
|
198
|
+
### 2. Kritzman Absorption Ratio (`regimelab.features.absorption`)
|
|
199
|
+
|
|
200
|
+
Quantifies market fragility via Principal Component Analysis (PCA) over rolling multi-asset return covariance matrices:
|
|
201
|
+
|
|
202
|
+
$$
|
|
203
|
+
\text{Absorption Ratio} = \frac{\sum_{i=1}^{k} \sigma^2_{PC_i}}{\sum_{j=1}^{N} \sigma^2_j}
|
|
204
|
+
$$
|
|
205
|
+
|
|
206
|
+
A rapid spike in the absorption ratio ($\Delta \text{AR} > 1.5$) indicates tightening cross-asset coupling, signaling systemic vulnerability prior to market crashes.
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## ⚙️ Configuration (`regimelab.toml`)
|
|
211
|
+
|
|
212
|
+
Customize execution parameters via `regimelab.toml`, environment variables (`REGIMELAB_DATA__PROVIDER=yfinance`), or Python kwargs:
|
|
213
|
+
|
|
214
|
+
```toml
|
|
215
|
+
[data]
|
|
216
|
+
provider = "yfinance" # "yfinance", "synthetic", or "parquet"
|
|
217
|
+
start = "2005-01-01"
|
|
218
|
+
benchmark = "SPY"
|
|
219
|
+
calendar_anchor = "SPY"
|
|
220
|
+
|
|
221
|
+
[model]
|
|
222
|
+
classifier = "hmm" # "hmm", "gmm", or "hamilton"
|
|
223
|
+
n_states = 4
|
|
224
|
+
covariance_type = "diag"
|
|
225
|
+
min_train_observations = 756
|
|
226
|
+
|
|
227
|
+
[backtest]
|
|
228
|
+
transaction_cost_bps = 5.0
|
|
229
|
+
confidence_floor = 0.5
|
|
230
|
+
refit_frequency_days = 63
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## 🧪 Testing & Formal Verification
|
|
236
|
+
|
|
237
|
+
RegimeLab is built with property-based testing (hypothesis) to mathematically guarantee absence of look-ahead leakage:
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
# Run test suite with causality property tests
|
|
241
|
+
uv run pytest -q
|
|
242
|
+
|
|
243
|
+
# Run strict mypy type checking
|
|
244
|
+
uv run mypy src/regimelab
|
|
245
|
+
|
|
246
|
+
# Lint with ruff
|
|
247
|
+
uv run ruff check .
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## 📄 License
|
|
253
|
+
|
|
254
|
+
MIT License. Developed for quantitative researchers, portfolio managers, and systematic trading engineers.
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# 🏛️ RegimeLab
|
|
4
|
+
|
|
5
|
+
**Institutional-grade market regime detection, systemic risk telemetry, and walk-forward asset allocation engine in Python.**
|
|
6
|
+
|
|
7
|
+
[](https://pypi.org/project/regimelab/)
|
|
8
|
+
[](https://www.python.org/downloads/)
|
|
9
|
+
[](https://opensource.org/licenses/MIT)
|
|
10
|
+
[](https://mypy-lang.org/)
|
|
11
|
+
[](https://github.com/astral-sh/ruff)
|
|
12
|
+
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## ⚡ Why RegimeLab?
|
|
18
|
+
|
|
19
|
+
Most open-source regime detection scripts fit a Hidden Markov Model (HMM) on the entire in-sample dataset and claim predictive power. In production quantitative finance, this fails due to three fatal flaws:
|
|
20
|
+
|
|
21
|
+
1. **Look-Ahead Bias:** Training filters without strict point-in-time (`asof`) truncation leaks future distribution moments into past states.
|
|
22
|
+
2. **Label Switching:** HMM/GMM state indices are mathematically interchangeable between refits. Without canonical sorting, "State 0" randomly alternates between Bull and Bear across rolling windows.
|
|
23
|
+
3. **Calendar Desynchronization:** Multi-asset cross-sections suffer from holiday mismatches, halted assets, and survivorship bias.
|
|
24
|
+
|
|
25
|
+
**RegimeLab** solves these operational hurdles, providing a turnkey, causal quantitative engine for systematic asset allocation and macro risk monitoring.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
### 📊 Feature Matrix: Raw Tooling vs. RegimeLab
|
|
30
|
+
|
|
31
|
+
| Challenge | Raw `hmmlearn` / `statsmodels` | RegimeLab Framework |
|
|
32
|
+
| :--- | :--- | :--- |
|
|
33
|
+
| **State Labeling** | Unordered integer states (permutes on refit) | **Deterministic Canonical Sorting** ($\frac{\mu}{\sigma}$ / conditional vol ordering) |
|
|
34
|
+
| **Temporal Clock** | In-sample full-sample fitting (Look-ahead) | **Strict Point-in-Time (`asof`) cursor** & expanding-window walk-forward |
|
|
35
|
+
| **Systemic Risk** | None | **Kritzman Absorption Ratio (PCA)**, VIX Term Spread & Sector Breadth |
|
|
36
|
+
| **Execution Reality** | Pure theoretical classification | **Walk-Forward Backtester** with transaction costs (bps) and confidence floors |
|
|
37
|
+
| **Data Ingestion** | Expects clean 2D NumPy array | **Multi-Asset PIT Alignment**, staleness budgets, synthetic & Parquet providers |
|
|
38
|
+
| **Reporting** | Matplotlib static plot | **Interactive Plotly HTML reports** + Textual TUI Terminal Dashboard |
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## 🚀 Quickstart
|
|
43
|
+
|
|
44
|
+
### 1. Installation
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# Install from PyPI
|
|
48
|
+
pip install regimelab
|
|
49
|
+
|
|
50
|
+
# Or install with interactive TUI support
|
|
51
|
+
pip install "regimelab[tui]"
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 2. Python API Usage
|
|
55
|
+
|
|
56
|
+
#### Current Market Regime Detection (3 lines)
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from regimelab import Settings
|
|
60
|
+
from regimelab.pipeline import run_single_asof
|
|
61
|
+
|
|
62
|
+
# Run point-in-time regime inference for any historical or current date
|
|
63
|
+
settings = Settings(data={"provider": "yfinance"})
|
|
64
|
+
payload = run_single_asof(settings, asof="2024-12-31")
|
|
65
|
+
|
|
66
|
+
print(f"Detected Regime: {payload.regime.value}")
|
|
67
|
+
print(f"Confidence: {payload.probabilities.confidence:.2%}")
|
|
68
|
+
print(f"Target Allocation: {payload.target_weights.weights if payload.target_weights else {}}")
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
#### Extract Causal Systemic Risk Features
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from regimelab import Settings
|
|
75
|
+
from regimelab.data.fetcher import load_aligned_panel
|
|
76
|
+
from regimelab.features import build_feature_matrix
|
|
77
|
+
|
|
78
|
+
settings = Settings(data={"provider": "yfinance"})
|
|
79
|
+
panel = load_aligned_panel(settings)
|
|
80
|
+
features = build_feature_matrix(panel, settings)
|
|
81
|
+
|
|
82
|
+
# Inspect causal feature matrix
|
|
83
|
+
print(features[["absorption_ratio", "absorption_delta", "vix_term_spread", "breadth"]].tail())
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
#### Walk-Forward Backtesting Engine
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from regimelab import Settings
|
|
90
|
+
from regimelab.pipeline import run_pipeline
|
|
91
|
+
|
|
92
|
+
settings = Settings(
|
|
93
|
+
data={"provider": "synthetic"}, # Fully offline, reproducible dataset
|
|
94
|
+
model={"classifier": "hmm", "n_states": 4},
|
|
95
|
+
backtest={"transaction_cost_bps": 5.0, "confidence_floor": 0.5},
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
result = run_pipeline(settings, command="backtest_run")
|
|
99
|
+
metrics = result.backtest.metrics
|
|
100
|
+
|
|
101
|
+
print(f"Strategy CAGR: {metrics.cagr:.2%}")
|
|
102
|
+
print(f"Sharpe Ratio: {metrics.sharpe:.2f}")
|
|
103
|
+
print(f"Max Drawdown: {metrics.max_drawdown:.2%}")
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### 3. CLI & Terminal Dashboard
|
|
107
|
+
|
|
108
|
+
RegimeLab ships with a powerful Typer CLI:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
# 1. Run full walk-forward pipeline and generate interactive HTML report
|
|
112
|
+
regimelab run --report market_report.html
|
|
113
|
+
|
|
114
|
+
# 2. Inspect point-in-time telemetry for a specific date (JSON output)
|
|
115
|
+
regimelab asof 2023-10-15
|
|
116
|
+
|
|
117
|
+
# 3. Launch the full interactive Textual Terminal Dashboard
|
|
118
|
+
regimelab tui
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Additional CLI commands include `regimelab report OUTPUT` for direct HTML generation and `regimelab asof YYYY-MM-DD --output telemetry.json` for persisted JSON payloads.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## 🧠 Core Methodology & Architecture
|
|
126
|
+
|
|
127
|
+
```text
|
|
128
|
+
┌──────────────────────────────────────────────┐
|
|
129
|
+
│ Data Layer (PIT Alignment & Caching) │
|
|
130
|
+
└──────────────────────┬───────────────────────┘
|
|
131
|
+
│
|
|
132
|
+
┌──────────────────────▼───────────────────────┐
|
|
133
|
+
│ Causal Features (PCA Absorption, Spread) │
|
|
134
|
+
└──────────────────────┬───────────────────────┘
|
|
135
|
+
│
|
|
136
|
+
┌──────────────────────▼───────────────────────┐
|
|
137
|
+
│ Models: Hamilton / HMM / GMM + Anti-Switch │
|
|
138
|
+
└──────────────────────┬───────────────────────┘
|
|
139
|
+
│
|
|
140
|
+
┌──────────────────────────────┴──────────────────────────────┐
|
|
141
|
+
▼ ▼
|
|
142
|
+
┌─────────────────────────┐ ┌─────────────────────────┐
|
|
143
|
+
│ Walk-Forward Engine │ │ Telemetry, HTML & TUI │
|
|
144
|
+
│ (Dynamic Allocations) │ │ (Interactive Artifacts) │
|
|
145
|
+
└─────────────────────────┘ └─────────────────────────┘
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### 1. Canonical State Labeling (`regimelab.models.labeling`)
|
|
149
|
+
|
|
150
|
+
To eliminate label switching, RegimeLab fits the underlying statistical model (Gaussian HMM, Hamilton Markov Switching, or GMM) and evaluates the conditional distribution parameters of each state. States are sorted by risk-adjusted return ($\frac{\mu}{\sigma}$) and mapped deterministically to:
|
|
151
|
+
|
|
152
|
+
- **BULL_TREND** (High return, low volatility)
|
|
153
|
+
- **NEUTRAL_TRANSITION** (Moderate return, mean-reverting)
|
|
154
|
+
- **HIGH_VOL_BEAR** (Negative drift, elevated variance)
|
|
155
|
+
- **RISK_OFF** (Severe drawdown regime)
|
|
156
|
+
|
|
157
|
+
### 2. Kritzman Absorption Ratio (`regimelab.features.absorption`)
|
|
158
|
+
|
|
159
|
+
Quantifies market fragility via Principal Component Analysis (PCA) over rolling multi-asset return covariance matrices:
|
|
160
|
+
|
|
161
|
+
$$
|
|
162
|
+
\text{Absorption Ratio} = \frac{\sum_{i=1}^{k} \sigma^2_{PC_i}}{\sum_{j=1}^{N} \sigma^2_j}
|
|
163
|
+
$$
|
|
164
|
+
|
|
165
|
+
A rapid spike in the absorption ratio ($\Delta \text{AR} > 1.5$) indicates tightening cross-asset coupling, signaling systemic vulnerability prior to market crashes.
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## ⚙️ Configuration (`regimelab.toml`)
|
|
170
|
+
|
|
171
|
+
Customize execution parameters via `regimelab.toml`, environment variables (`REGIMELAB_DATA__PROVIDER=yfinance`), or Python kwargs:
|
|
172
|
+
|
|
173
|
+
```toml
|
|
174
|
+
[data]
|
|
175
|
+
provider = "yfinance" # "yfinance", "synthetic", or "parquet"
|
|
176
|
+
start = "2005-01-01"
|
|
177
|
+
benchmark = "SPY"
|
|
178
|
+
calendar_anchor = "SPY"
|
|
179
|
+
|
|
180
|
+
[model]
|
|
181
|
+
classifier = "hmm" # "hmm", "gmm", or "hamilton"
|
|
182
|
+
n_states = 4
|
|
183
|
+
covariance_type = "diag"
|
|
184
|
+
min_train_observations = 756
|
|
185
|
+
|
|
186
|
+
[backtest]
|
|
187
|
+
transaction_cost_bps = 5.0
|
|
188
|
+
confidence_floor = 0.5
|
|
189
|
+
refit_frequency_days = 63
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## 🧪 Testing & Formal Verification
|
|
195
|
+
|
|
196
|
+
RegimeLab is built with property-based testing (hypothesis) to mathematically guarantee absence of look-ahead leakage:
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
# Run test suite with causality property tests
|
|
200
|
+
uv run pytest -q
|
|
201
|
+
|
|
202
|
+
# Run strict mypy type checking
|
|
203
|
+
uv run mypy src/regimelab
|
|
204
|
+
|
|
205
|
+
# Lint with ruff
|
|
206
|
+
uv run ruff check .
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## 📄 License
|
|
212
|
+
|
|
213
|
+
MIT License. Developed for quantitative researchers, portfolio managers, and systematic trading engineers.
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "regimelab"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Institutional market-regime detection engine: HMM/Hamilton regime switching, PCA absorption ratio, VIX term structure, point-in-time backtesting and automated reporting."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
license-files = ["LICENSE"]
|
|
8
|
+
authors = [
|
|
9
|
+
{ name = "AlgorithmicMind", email = "tonidinero27@gmail.com" }
|
|
10
|
+
]
|
|
11
|
+
keywords = [
|
|
12
|
+
"quantitative-finance",
|
|
13
|
+
"regime-detection",
|
|
14
|
+
"hidden-markov-model",
|
|
15
|
+
"systemic-risk",
|
|
16
|
+
"backtesting",
|
|
17
|
+
"point-in-time",
|
|
18
|
+
"absorption-ratio",
|
|
19
|
+
]
|
|
20
|
+
classifiers = [
|
|
21
|
+
"Development Status :: 3 - Alpha",
|
|
22
|
+
"Intended Audience :: Financial and Insurance Industry",
|
|
23
|
+
"Intended Audience :: Science/Research",
|
|
24
|
+
"License :: OSI Approved :: MIT License",
|
|
25
|
+
"Operating System :: OS Independent",
|
|
26
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
27
|
+
"Programming Language :: Python :: 3.12",
|
|
28
|
+
"Programming Language :: Python :: 3.13",
|
|
29
|
+
"Topic :: Office/Business :: Financial :: Investment",
|
|
30
|
+
"Topic :: Scientific/Engineering :: Information Analysis",
|
|
31
|
+
"Typing :: Typed",
|
|
32
|
+
]
|
|
33
|
+
requires-python = ">=3.12"
|
|
34
|
+
dependencies = [
|
|
35
|
+
"hmmlearn>=0.3.3",
|
|
36
|
+
"numpy>=2.5.2",
|
|
37
|
+
"pandas>=3.0.5",
|
|
38
|
+
"platformdirs>=4.11.5",
|
|
39
|
+
"plotly>=6.0.0",
|
|
40
|
+
"pyarrow>=25.0.1",
|
|
41
|
+
"pydantic>=2.13.5",
|
|
42
|
+
"pydantic-settings>=2.15.0",
|
|
43
|
+
"rich>=15.0.0",
|
|
44
|
+
"scikit-learn>=1.9.0",
|
|
45
|
+
"scipy>=1.18.1",
|
|
46
|
+
"statsmodels>=0.15.0",
|
|
47
|
+
"typer>=0.27.2",
|
|
48
|
+
"yfinance>=1.7.0",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
[project.urls]
|
|
52
|
+
Homepage = "https://github.com/AlgorithmicMind/regimelab"
|
|
53
|
+
Repository = "https://github.com/AlgorithmicMind/regimelab"
|
|
54
|
+
Issues = "https://github.com/AlgorithmicMind/regimelab/issues"
|
|
55
|
+
|
|
56
|
+
[project.scripts]
|
|
57
|
+
regimelab = "regimelab.cli:app"
|
|
58
|
+
|
|
59
|
+
[project.optional-dependencies]
|
|
60
|
+
tui = [
|
|
61
|
+
"textual>=8.2.8",
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
[build-system]
|
|
65
|
+
requires = ["hatchling>=1.27"]
|
|
66
|
+
build-backend = "hatchling.build"
|
|
67
|
+
|
|
68
|
+
[tool.hatch.build.targets.wheel]
|
|
69
|
+
packages = ["src/regimelab"]
|
|
70
|
+
|
|
71
|
+
[tool.hatch.build.targets.sdist]
|
|
72
|
+
include = ["src/regimelab", "tests", "README.md", "LICENSE"]
|
|
73
|
+
|
|
74
|
+
[tool.ruff]
|
|
75
|
+
line-length = 100
|
|
76
|
+
target-version = "py312"
|
|
77
|
+
src = ["src", "tests"]
|
|
78
|
+
|
|
79
|
+
[tool.ruff.lint]
|
|
80
|
+
select = [
|
|
81
|
+
"E", "W", # pycodestyle
|
|
82
|
+
"F", # pyflakes
|
|
83
|
+
"I", # isort
|
|
84
|
+
"N", # pep8-naming
|
|
85
|
+
"UP", # pyupgrade
|
|
86
|
+
"B", # flake8-bugbear
|
|
87
|
+
"A", # flake8-builtins
|
|
88
|
+
"C4", # flake8-comprehensions
|
|
89
|
+
"DTZ", # flake8-datetimez
|
|
90
|
+
"ISC", # implicit-str-concat
|
|
91
|
+
"PIE", # flake8-pie
|
|
92
|
+
"PT", # flake8-pytest-style
|
|
93
|
+
"RET", # flake8-return
|
|
94
|
+
"SIM", # flake8-simplify
|
|
95
|
+
"ARG", # flake8-unused-arguments
|
|
96
|
+
"PD", # pandas-vet
|
|
97
|
+
"PL", # pylint
|
|
98
|
+
"NPY", # numpy-specific
|
|
99
|
+
"PERF", # perflint
|
|
100
|
+
"RUF", # ruff-specific
|
|
101
|
+
]
|
|
102
|
+
ignore = [
|
|
103
|
+
"PLR0913", # quant functions legitimately take many parameters
|
|
104
|
+
"PLR2004", # magic values are readable in numerical code
|
|
105
|
+
"ISC001", # conflicts with the formatter
|
|
106
|
+
]
|
|
107
|
+
|
|
108
|
+
[tool.ruff.lint.per-file-ignores]
|
|
109
|
+
"tests/**" = ["ARG", "PLR2004"]
|
|
110
|
+
|
|
111
|
+
[tool.ruff.lint.pydocstyle]
|
|
112
|
+
convention = "numpy"
|
|
113
|
+
|
|
114
|
+
[tool.mypy]
|
|
115
|
+
python_version = "3.12"
|
|
116
|
+
strict = true
|
|
117
|
+
warn_unreachable = true
|
|
118
|
+
warn_no_return = true
|
|
119
|
+
disallow_any_generics = true
|
|
120
|
+
no_implicit_reexport = true
|
|
121
|
+
show_error_codes = true
|
|
122
|
+
pretty = true
|
|
123
|
+
files = ["src", "tests"]
|
|
124
|
+
|
|
125
|
+
[[tool.mypy.overrides]]
|
|
126
|
+
module = [
|
|
127
|
+
"yfinance.*",
|
|
128
|
+
"hmmlearn.*",
|
|
129
|
+
"statsmodels.*",
|
|
130
|
+
"sklearn.*",
|
|
131
|
+
"scipy.*",
|
|
132
|
+
"plotly.*",
|
|
133
|
+
"textual.*",
|
|
134
|
+
]
|
|
135
|
+
ignore_missing_imports = true
|
|
136
|
+
|
|
137
|
+
[tool.pytest.ini_options]
|
|
138
|
+
minversion = "8.0"
|
|
139
|
+
testpaths = ["tests"]
|
|
140
|
+
addopts = [
|
|
141
|
+
"-ra",
|
|
142
|
+
"--strict-markers",
|
|
143
|
+
"--strict-config",
|
|
144
|
+
"--import-mode=importlib",
|
|
145
|
+
]
|
|
146
|
+
filterwarnings = [
|
|
147
|
+
"error",
|
|
148
|
+
"ignore::DeprecationWarning:hmmlearn.*",
|
|
149
|
+
"ignore::DeprecationWarning:statsmodels.*",
|
|
150
|
+
]
|
|
151
|
+
markers = [
|
|
152
|
+
"network: test requires live network access (deselect with '-m \"not network\"')",
|
|
153
|
+
"slow: test is slow (deselect with '-m \"not slow\"')",
|
|
154
|
+
]
|
|
155
|
+
|
|
156
|
+
[tool.coverage.run]
|
|
157
|
+
source = ["src/regimelab"]
|
|
158
|
+
branch = true
|
|
159
|
+
parallel = true
|
|
160
|
+
|
|
161
|
+
[tool.coverage.report]
|
|
162
|
+
precision = 1
|
|
163
|
+
show_missing = true
|
|
164
|
+
exclude_also = [
|
|
165
|
+
"if TYPE_CHECKING:",
|
|
166
|
+
"raise NotImplementedError",
|
|
167
|
+
"@(abc\\.)?abstractmethod",
|
|
168
|
+
"if __name__ == .__main__.:",
|
|
169
|
+
]
|
|
170
|
+
|
|
171
|
+
[dependency-groups]
|
|
172
|
+
dev = [
|
|
173
|
+
"hypothesis>=6.167.1",
|
|
174
|
+
"mypy>=2.3.1",
|
|
175
|
+
"pandas-stubs>=3.0.5.260730",
|
|
176
|
+
"pytest>=9.1.1",
|
|
177
|
+
"pytest-cov>=7.1.0",
|
|
178
|
+
"ruff>=0.16.5",
|
|
179
|
+
]
|