alphaengine 0.7.0__tar.gz → 0.8.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.
- {alphaengine-0.7.0 → alphaengine-0.8.0}/AGENTS.md +8 -5
- {alphaengine-0.7.0 → alphaengine-0.8.0}/PKG-INFO +56 -8
- {alphaengine-0.7.0 → alphaengine-0.8.0}/README.md +55 -7
- alphaengine-0.8.0/docs/assets/session.png +0 -0
- alphaengine-0.8.0/docs/figure_contract.md +46 -0
- alphaengine-0.8.0/docs/workflows/evaluate_process.json +18 -0
- alphaengine-0.8.0/docs/workflows/research_week.json +29 -0
- alphaengine-0.8.0/docs/workflows/stress_study.json +14 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/_version.py +7 -9
- alphaengine-0.8.0/src/alphaengine/charts.py +56 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/cli.py +162 -25
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/client/executor.py +190 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/commands.py +22 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/core/__init__.py +20 -1
- alphaengine-0.8.0/src/alphaengine/core/active.py +95 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/core/allocate.py +30 -6
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/core/covariance.py +14 -0
- alphaengine-0.8.0/src/alphaengine/core/process.py +450 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/repl.py +1 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/study/report.py +4 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/study/schema.py +7 -1
- {alphaengine-0.7.0 → alphaengine-0.8.0}/tests/test_cli.py +18 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/tests/test_commands.py +2 -2
- alphaengine-0.8.0/tests/test_process.py +201 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/tests/test_sweep.py +27 -0
- alphaengine-0.7.0/docs/assets/mark.png +0 -0
- alphaengine-0.7.0/docs/assets/session.png +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/.github/workflows/ci.yml +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/.github/workflows/publish.yml +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/.gitignore +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/LICENSE +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/SECURITY.md +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/docs/assets/banner.png +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/docs/assets/data_boundary.png +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/pyproject.toml +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/scripts/gen_docs.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/__init__.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/__main__.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/agent/__init__.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/agent/answer.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/agent/driver.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/auth.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/book.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/client/__init__.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/client/agent.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/client/session.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/complete.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/connectors/__init__.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/core/backtest.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/core/cross_section.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/core/factors.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/core/pairs.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/core/panel.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/core/performance.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/core/profile.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/core/risk.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/core/screen.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/core/series_shapes.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/core/signals.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/core/stress.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/core/technical.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/core/validation.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/core/walkforward.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/demo.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/demo_book.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/demo_returns.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/demo_signal.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/demo_universe.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/events.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/loaders.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/model.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/py.typed +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/study/__init__.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/sweep/__init__.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/src/alphaengine/sweep/runner.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/tests/test_agent.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/tests/test_answer.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/tests/test_book.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/tests/test_client.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/tests/test_events.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/tests/test_executor_ops.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/tests/test_goldens.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/tests/test_loaders.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/tests/test_model.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/tests/test_quant_maths.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/tests/test_screen.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/tests/test_signals.py +0 -0
- {alphaengine-0.7.0 → alphaengine-0.8.0}/tests/test_smoke.py +0 -0
|
@@ -56,13 +56,16 @@ animated parameter-surface canvas at boot and while Working) plus
|
|
|
56
56
|
that is a version bump (`_version.py`).
|
|
57
57
|
- **Compute ops on the executor** include the 0.6 workflow set (`backtest`,
|
|
58
58
|
`score_backtest`, `cpcv`, `factors`, `pairs`, `cointegrated_pairs`,
|
|
59
|
-
`walk_forward`, `book_overlap`)
|
|
59
|
+
`walk_forward`, `book_overlap`), the 0.7 CS / book set
|
|
60
60
|
(`panel_transform`, `signal_icir`, `fama_macbeth`, `quantile_book`,
|
|
61
|
-
`ewma_cov`, `denoise_cov`, `hrp`, `risk_parity`, `vol_target`)
|
|
62
|
-
|
|
61
|
+
`ewma_cov`, `denoise_cov`, `hrp`, `risk_parity`, `vol_target`), and the
|
|
62
|
+
0.8 process / Grinold set (`ou_calibrate`, `ou_simulate`, `gbm_calibrate`,
|
|
63
|
+
`jump_calibrate`, `garch`, `dgp_stress`, `grinold_alpha`, `breadth_ir`,
|
|
64
|
+
`detone_cov`). Panels, covariance matrices, GARCH variance paths, OU paths
|
|
65
|
+
and alpha vectors stay in the workspace; figures go over the wire. The
|
|
63
66
|
portal must offer an op in a workflow graph or it sits unused; the CLI
|
|
64
|
-
|
|
65
|
-
they do not shrink the rest of the book.
|
|
67
|
+
`process` command runs the DGP stress offline without a portal. Short names
|
|
68
|
+
in a panel are skipped and counted, they do not shrink the rest of the book.
|
|
66
69
|
- `sweep(..., jobs=N)` defaults to 1. Greater than 1 is opt-in and must keep
|
|
67
70
|
trial index identity, including failures.
|
|
68
71
|
- The `connectors` extra is lazy: parquet via `pyarrow`, HTTP via `httpx` to a
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: alphaengine
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Summary: Validated research tooling for investment strategies: deflation, overfitting detection, and honest trial counts.
|
|
5
5
|
Project-URL: Homepage, https://github.com/quantOSC/alphaengine
|
|
6
6
|
Project-URL: Documentation, https://github.com/quantOSC/alphaengine#readme
|
|
@@ -60,17 +60,14 @@ Description-Content-Type: text/markdown
|
|
|
60
60
|
<img src="https://img.shields.io/badge/deps-numpy%20%2B%20scipy-C4893A?style=flat-square" alt="Two dependencies: numpy and scipy">
|
|
61
61
|
</p>
|
|
62
62
|
|
|
63
|
-
<p align="center">
|
|
64
|
-
<img src="docs/assets/mark.png" alt="AlphaEngine mark" width="96">
|
|
65
|
-
</p>
|
|
66
|
-
|
|
67
63
|
```bash
|
|
68
64
|
pip install alphaengine
|
|
69
65
|
alphaengine demo # the whole offline half, no account, no data of your own
|
|
66
|
+
alphaengine process # fit a DGP to the demo walk and stress it
|
|
70
67
|
```
|
|
71
68
|
|
|
72
69
|
<p align="center">
|
|
73
|
-
<img src="docs/assets/session.png" alt="The session canvas: a
|
|
70
|
+
<img src="docs/assets/session.png" alt="The session canvas: tracked ALPHAENGINE over a teal plateau and amber ridge, then your data never leaves." width="92%">
|
|
74
71
|
</p>
|
|
75
72
|
|
|
76
73
|
The session is the product. Sign in, load something, then ask:
|
|
@@ -196,6 +193,35 @@ distinction is the whole of the data boundary below.
|
|
|
196
193
|
|
|
197
194
|
---
|
|
198
195
|
|
|
196
|
+
## What's new in 0.8.0
|
|
197
|
+
|
|
198
|
+
Named processes, Grinold, and a frozen chart contract. Existing goldens
|
|
199
|
+
(deflated Sharpe, PBO, performance, screen) are byte-identical. New figures
|
|
200
|
+
are a public contract from this release. The study schema is **1.1**: optional
|
|
201
|
+
`process` and `charts` fields; 1.0 studies still load.
|
|
202
|
+
|
|
203
|
+
| You have | You get | Module |
|
|
204
|
+
|---|---|---|
|
|
205
|
+
| A spread or a close | OU / GBM / jump / GARCH(1,1) calibration, then Monte Carlo stress under that law | `core.process` |
|
|
206
|
+
| An IC and a cross-section | Grinold alpha, breadth, transfer coefficient | `core.active` |
|
|
207
|
+
| A return panel | Detoned covariance and a PCA variance-explained table | `core.covariance` |
|
|
208
|
+
| Figures that already travel | `{kind, key, title}` hints a portal maps to a chart | `charts`, [figure contract](docs/figure_contract.md) |
|
|
209
|
+
|
|
210
|
+
The terminal boot is the README banner: tracked `ALPHAENGINE`, the subtitle,
|
|
211
|
+
a teal-left / amber-right mesh (plateau, valley, knife-edge ridge), and
|
|
212
|
+
`your data never leaves.` `alphaengine process` fits a DGP offline, no account.
|
|
213
|
+
|
|
214
|
+
```python
|
|
215
|
+
from alphaengine.core import ou_calibrate, garch_calibrate, dgp_stress, grinold_alpha
|
|
216
|
+
|
|
217
|
+
ou = ou_calibrate(spread) # kappa, theta, half_life; or not mean-reverting
|
|
218
|
+
g = garch_calibrate(returns) # omega, alpha, beta, persistence in (0, 1)
|
|
219
|
+
s = dgp_stress(close, dgp="ou") # n_trials = n_paths, source monte_carlo
|
|
220
|
+
a = grinold_alpha(panel, ic=0.05) # alpha vector stays here; scalars travel
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
199
225
|
## What's new in 0.7.0
|
|
200
226
|
|
|
201
227
|
The daily modelling morning, and the overnight book, without a third
|
|
@@ -237,6 +263,7 @@ w = hrp_weights(cov, names=names) # no matrix inverse; weights sum to one
|
|
|
237
263
|
| Command | Does | Where |
|
|
238
264
|
|---|---|---|
|
|
239
265
|
| `demo` | run the built-in example offline, with no account and no data | shell + session |
|
|
266
|
+
| `process [ou \| gbm \| jump \| garch]` | fit a named process to a series and stress it, offline | shell + session |
|
|
240
267
|
| `runs [--limit N]` | your own week: what ran, what it decided, what it filed | shell + session |
|
|
241
268
|
| `gaps` | what your record says is UNANSWERED, and what closes each one | shell + session |
|
|
242
269
|
| `tonight [--budget N]` | what would run unattended tonight, without running any of it | shell + session |
|
|
@@ -320,6 +347,8 @@ alphaengine overlap
|
|
|
320
347
|
alphaengine size
|
|
321
348
|
alphaengine monitor
|
|
322
349
|
alphaengine demo
|
|
350
|
+
alphaengine process
|
|
351
|
+
alphaengine process ou
|
|
323
352
|
alphaengine runs
|
|
324
353
|
alphaengine runs --limit 50
|
|
325
354
|
alphaengine gaps
|
|
@@ -423,8 +452,11 @@ diffable, and versioned so it still parses in two years.
|
|
|
423
452
|
| `alphaengine.core.panel` | cross-sectional rank, z-score, winsorize, neutralize |
|
|
424
453
|
| `alphaengine.core.signals` | IC, ICIR, quantile returns, decay |
|
|
425
454
|
| `alphaengine.core.cross_section` | Fama-MacBeth, quantile book with turnover |
|
|
426
|
-
| `alphaengine.core.covariance` | EWMA, Ledoit-Wolf, Marchenko-Pastur denoise, detone |
|
|
427
|
-
| `alphaengine.core.allocate` | HRP, risk parity, vol target |
|
|
455
|
+
| `alphaengine.core.covariance` | EWMA, Ledoit-Wolf, Marchenko-Pastur denoise, detone, variance explained |
|
|
456
|
+
| `alphaengine.core.allocate` | HRP, risk parity, vol target (EWMA or GARCH) |
|
|
457
|
+
| `alphaengine.core.process` | OU, GBM, jumps, GARCH(1,1), DGP stress |
|
|
458
|
+
| `alphaengine.core.active` | Grinold alpha, breadth, transfer coefficient |
|
|
459
|
+
| `alphaengine.charts` | frozen `{kind, key, title}` hints; see [figure contract](docs/figure_contract.md) |
|
|
428
460
|
| `alphaengine.sweep` | the grid runner and the sensitivity surface |
|
|
429
461
|
| `alphaengine.study` | the study artifact and its schema |
|
|
430
462
|
| `alphaengine.client` | the workflow client and the step executor |
|
|
@@ -518,6 +550,22 @@ Management* 42(1), 13 to 28.
|
|
|
518
550
|
Fama, E. F., and MacBeth, J. D. (1973). "Risk, Return, and Equilibrium:
|
|
519
551
|
Empirical Tests." *Journal of Political Economy* 81(3), 607 to 636.
|
|
520
552
|
|
|
553
|
+
**Ornstein-Uhlenbeck / Vasicek**
|
|
554
|
+
Vasicek, O. (1977). "An Equilibrium Characterization of the Term Structure."
|
|
555
|
+
*Journal of Financial Economics* 5(2), 177 to 188.
|
|
556
|
+
|
|
557
|
+
**GARCH(1,1)**
|
|
558
|
+
Bollerslev, T. (1986). "Generalized Autoregressive Conditional
|
|
559
|
+
Heteroskedasticity." *Journal of Econometrics* 31(3), 307 to 327.
|
|
560
|
+
|
|
561
|
+
**Jump-diffusion**
|
|
562
|
+
Merton, R. C. (1976). "Option Pricing When Underlying Stock Returns Are
|
|
563
|
+
Discontinuous." *Journal of Financial Economics* 3(1-2), 125 to 144.
|
|
564
|
+
|
|
565
|
+
**The fundamental law of active management**
|
|
566
|
+
Grinold, R. C., and Kahn, R. N. (2000). *Active Portfolio Management.* 2nd ed.
|
|
567
|
+
McGraw-Hill.
|
|
568
|
+
|
|
521
569
|
**Downside deviation**
|
|
522
570
|
Sortino, F. A., and Price, L. N. (1994). "Performance Measurement in a Downside
|
|
523
571
|
Risk Framework." *Journal of Investing* 3(3), 59 to 64.
|
|
@@ -18,17 +18,14 @@
|
|
|
18
18
|
<img src="https://img.shields.io/badge/deps-numpy%20%2B%20scipy-C4893A?style=flat-square" alt="Two dependencies: numpy and scipy">
|
|
19
19
|
</p>
|
|
20
20
|
|
|
21
|
-
<p align="center">
|
|
22
|
-
<img src="docs/assets/mark.png" alt="AlphaEngine mark" width="96">
|
|
23
|
-
</p>
|
|
24
|
-
|
|
25
21
|
```bash
|
|
26
22
|
pip install alphaengine
|
|
27
23
|
alphaengine demo # the whole offline half, no account, no data of your own
|
|
24
|
+
alphaengine process # fit a DGP to the demo walk and stress it
|
|
28
25
|
```
|
|
29
26
|
|
|
30
27
|
<p align="center">
|
|
31
|
-
<img src="docs/assets/session.png" alt="The session canvas: a
|
|
28
|
+
<img src="docs/assets/session.png" alt="The session canvas: tracked ALPHAENGINE over a teal plateau and amber ridge, then your data never leaves." width="92%">
|
|
32
29
|
</p>
|
|
33
30
|
|
|
34
31
|
The session is the product. Sign in, load something, then ask:
|
|
@@ -154,6 +151,35 @@ distinction is the whole of the data boundary below.
|
|
|
154
151
|
|
|
155
152
|
---
|
|
156
153
|
|
|
154
|
+
## What's new in 0.8.0
|
|
155
|
+
|
|
156
|
+
Named processes, Grinold, and a frozen chart contract. Existing goldens
|
|
157
|
+
(deflated Sharpe, PBO, performance, screen) are byte-identical. New figures
|
|
158
|
+
are a public contract from this release. The study schema is **1.1**: optional
|
|
159
|
+
`process` and `charts` fields; 1.0 studies still load.
|
|
160
|
+
|
|
161
|
+
| You have | You get | Module |
|
|
162
|
+
|---|---|---|
|
|
163
|
+
| A spread or a close | OU / GBM / jump / GARCH(1,1) calibration, then Monte Carlo stress under that law | `core.process` |
|
|
164
|
+
| An IC and a cross-section | Grinold alpha, breadth, transfer coefficient | `core.active` |
|
|
165
|
+
| A return panel | Detoned covariance and a PCA variance-explained table | `core.covariance` |
|
|
166
|
+
| Figures that already travel | `{kind, key, title}` hints a portal maps to a chart | `charts`, [figure contract](docs/figure_contract.md) |
|
|
167
|
+
|
|
168
|
+
The terminal boot is the README banner: tracked `ALPHAENGINE`, the subtitle,
|
|
169
|
+
a teal-left / amber-right mesh (plateau, valley, knife-edge ridge), and
|
|
170
|
+
`your data never leaves.` `alphaengine process` fits a DGP offline, no account.
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
from alphaengine.core import ou_calibrate, garch_calibrate, dgp_stress, grinold_alpha
|
|
174
|
+
|
|
175
|
+
ou = ou_calibrate(spread) # kappa, theta, half_life; or not mean-reverting
|
|
176
|
+
g = garch_calibrate(returns) # omega, alpha, beta, persistence in (0, 1)
|
|
177
|
+
s = dgp_stress(close, dgp="ou") # n_trials = n_paths, source monte_carlo
|
|
178
|
+
a = grinold_alpha(panel, ic=0.05) # alpha vector stays here; scalars travel
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
157
183
|
## What's new in 0.7.0
|
|
158
184
|
|
|
159
185
|
The daily modelling morning, and the overnight book, without a third
|
|
@@ -195,6 +221,7 @@ w = hrp_weights(cov, names=names) # no matrix inverse; weights sum to one
|
|
|
195
221
|
| Command | Does | Where |
|
|
196
222
|
|---|---|---|
|
|
197
223
|
| `demo` | run the built-in example offline, with no account and no data | shell + session |
|
|
224
|
+
| `process [ou \| gbm \| jump \| garch]` | fit a named process to a series and stress it, offline | shell + session |
|
|
198
225
|
| `runs [--limit N]` | your own week: what ran, what it decided, what it filed | shell + session |
|
|
199
226
|
| `gaps` | what your record says is UNANSWERED, and what closes each one | shell + session |
|
|
200
227
|
| `tonight [--budget N]` | what would run unattended tonight, without running any of it | shell + session |
|
|
@@ -278,6 +305,8 @@ alphaengine overlap
|
|
|
278
305
|
alphaengine size
|
|
279
306
|
alphaengine monitor
|
|
280
307
|
alphaengine demo
|
|
308
|
+
alphaengine process
|
|
309
|
+
alphaengine process ou
|
|
281
310
|
alphaengine runs
|
|
282
311
|
alphaengine runs --limit 50
|
|
283
312
|
alphaengine gaps
|
|
@@ -381,8 +410,11 @@ diffable, and versioned so it still parses in two years.
|
|
|
381
410
|
| `alphaengine.core.panel` | cross-sectional rank, z-score, winsorize, neutralize |
|
|
382
411
|
| `alphaengine.core.signals` | IC, ICIR, quantile returns, decay |
|
|
383
412
|
| `alphaengine.core.cross_section` | Fama-MacBeth, quantile book with turnover |
|
|
384
|
-
| `alphaengine.core.covariance` | EWMA, Ledoit-Wolf, Marchenko-Pastur denoise, detone |
|
|
385
|
-
| `alphaengine.core.allocate` | HRP, risk parity, vol target |
|
|
413
|
+
| `alphaengine.core.covariance` | EWMA, Ledoit-Wolf, Marchenko-Pastur denoise, detone, variance explained |
|
|
414
|
+
| `alphaengine.core.allocate` | HRP, risk parity, vol target (EWMA or GARCH) |
|
|
415
|
+
| `alphaengine.core.process` | OU, GBM, jumps, GARCH(1,1), DGP stress |
|
|
416
|
+
| `alphaengine.core.active` | Grinold alpha, breadth, transfer coefficient |
|
|
417
|
+
| `alphaengine.charts` | frozen `{kind, key, title}` hints; see [figure contract](docs/figure_contract.md) |
|
|
386
418
|
| `alphaengine.sweep` | the grid runner and the sensitivity surface |
|
|
387
419
|
| `alphaengine.study` | the study artifact and its schema |
|
|
388
420
|
| `alphaengine.client` | the workflow client and the step executor |
|
|
@@ -476,6 +508,22 @@ Management* 42(1), 13 to 28.
|
|
|
476
508
|
Fama, E. F., and MacBeth, J. D. (1973). "Risk, Return, and Equilibrium:
|
|
477
509
|
Empirical Tests." *Journal of Political Economy* 81(3), 607 to 636.
|
|
478
510
|
|
|
511
|
+
**Ornstein-Uhlenbeck / Vasicek**
|
|
512
|
+
Vasicek, O. (1977). "An Equilibrium Characterization of the Term Structure."
|
|
513
|
+
*Journal of Financial Economics* 5(2), 177 to 188.
|
|
514
|
+
|
|
515
|
+
**GARCH(1,1)**
|
|
516
|
+
Bollerslev, T. (1986). "Generalized Autoregressive Conditional
|
|
517
|
+
Heteroskedasticity." *Journal of Econometrics* 31(3), 307 to 327.
|
|
518
|
+
|
|
519
|
+
**Jump-diffusion**
|
|
520
|
+
Merton, R. C. (1976). "Option Pricing When Underlying Stock Returns Are
|
|
521
|
+
Discontinuous." *Journal of Financial Economics* 3(1-2), 125 to 144.
|
|
522
|
+
|
|
523
|
+
**The fundamental law of active management**
|
|
524
|
+
Grinold, R. C., and Kahn, R. N. (2000). *Active Portfolio Management.* 2nd ed.
|
|
525
|
+
McGraw-Hill.
|
|
526
|
+
|
|
479
527
|
**Downside deviation**
|
|
480
528
|
Sortino, F. A., and Price, L. N. (1994). "Performance Measurement in a Downside
|
|
481
529
|
Risk Framework." *Journal of Investing* 3(3), 59 to 64.
|
|
Binary file
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Figure contract
|
|
2
|
+
|
|
3
|
+
A figure that travels is a **named kind**, not a series. The executor attaches
|
|
4
|
+
`charts: [{kind, key, title}]` hints. The portal maps `kind` + `key` to a
|
|
5
|
+
component. Old portals ignore `charts` and still have the raw keys
|
|
6
|
+
(`ic_by_period`, `best_curve`, …).
|
|
7
|
+
|
|
8
|
+
No hint carries a nested series. Titles are one line, no em dash.
|
|
9
|
+
|
|
10
|
+
Study schema **1.1** may also store `charts` and `process` on the artifact.
|
|
11
|
+
Both are optional. A 1.0 study still loads.
|
|
12
|
+
|
|
13
|
+
## Kinds
|
|
14
|
+
|
|
15
|
+
| Kind | Payload | Draws as |
|
|
16
|
+
|---|---|---|
|
|
17
|
+
| `curve` | `{i, v}` | line |
|
|
18
|
+
| `period` | `{p, ic}` or `{p, lambda}` | CS time series |
|
|
19
|
+
| `band` | `{i, lo, mid, hi}` | fan / Monte Carlo quantile |
|
|
20
|
+
| `hist` | `{edges, counts}` | histogram |
|
|
21
|
+
| `cost` | `{bps, sharpe}` | cost ladder |
|
|
22
|
+
| `scatter` | `{x, y}` | overlap |
|
|
23
|
+
| `triangle` | `{a, b, v}` | covariance heatmap |
|
|
24
|
+
| `rows` | bounded dict rows | table |
|
|
25
|
+
| `quantiles` | `[float]` | bar |
|
|
26
|
+
|
|
27
|
+
`i` is a position index into the original series, never a timestamp. Timestamps
|
|
28
|
+
stay on the machine that holds the data.
|
|
29
|
+
|
|
30
|
+
Lists longer than 512 are a series, not a figure, and the wire guard refuses
|
|
31
|
+
them. Sketches (`path_sketch`, `vol_path`, `mean_path`, `band`) are bucketed
|
|
32
|
+
below that cap before they travel.
|
|
33
|
+
|
|
34
|
+
## Who emits what
|
|
35
|
+
|
|
36
|
+
| Op | Typical hints |
|
|
37
|
+
|---|---|
|
|
38
|
+
| `compute.ou_calibrate` | `curve` / `path_sketch` |
|
|
39
|
+
| `compute.ou_simulate` | `curve` / `mean_path`, `band` / `band` |
|
|
40
|
+
| `compute.garch` | `curve` / `vol_path` |
|
|
41
|
+
| `compute.dgp_stress` | `hist` / `sharpe_hist` |
|
|
42
|
+
| `compute.denoise_cov` | `triangle` / `triangle`, `rows` / `variance_explained` |
|
|
43
|
+
| `compute.detone_cov` | same |
|
|
44
|
+
| `compute.grinold_alpha` | scalars only; the alpha vector stays in the workspace |
|
|
45
|
+
|
|
46
|
+
The Python helper is `alphaengine.charts.chart(kind, key, title)`.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "evaluate_process",
|
|
3
|
+
"schema": "alphaengine.workflow/1",
|
|
4
|
+
"title": "what law describes this path?",
|
|
5
|
+
"reproducible": true,
|
|
6
|
+
"needs": ["data"],
|
|
7
|
+
"selection": "all",
|
|
8
|
+
"note": "Portal harness copies this. Agents still only index permitted; these ops sit unused until registered.",
|
|
9
|
+
"stages": [
|
|
10
|
+
{"op": "data.resolve"},
|
|
11
|
+
{"op": "compute.gbm_calibrate"},
|
|
12
|
+
{"op": "compute.ou_calibrate"},
|
|
13
|
+
{"op": "compute.jump_calibrate"},
|
|
14
|
+
{"op": "compute.garch"},
|
|
15
|
+
{"op": "compute.dgp_stress", "params": {"dgp": "gbm"}},
|
|
16
|
+
{"op": "emit.process_report"}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "research_week",
|
|
3
|
+
"schema": "alphaengine.workflow/1",
|
|
4
|
+
"title": "gaps the modeling suite closes once the portal registers the ops",
|
|
5
|
+
"gaps": [
|
|
6
|
+
{
|
|
7
|
+
"question": "what law describes this path?",
|
|
8
|
+
"workflow": "evaluate_process",
|
|
9
|
+
"op": "compute.dgp_stress",
|
|
10
|
+
"cli": "alphaengine process"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"question": "where does it break under a named DGP?",
|
|
14
|
+
"workflow": "stress_study",
|
|
15
|
+
"stage": "dgp_stress",
|
|
16
|
+
"cli": "alphaengine process ou"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"question": "how much alpha does the IC imply?",
|
|
20
|
+
"workflow": "size_position",
|
|
21
|
+
"op": "compute.grinold_alpha"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"question": "is the book the market in disguise?",
|
|
25
|
+
"workflow": "size_position",
|
|
26
|
+
"op": "compute.detone_cov"
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "stress_study",
|
|
3
|
+
"schema": "alphaengine.workflow/1",
|
|
4
|
+
"title": "where does it break?",
|
|
5
|
+
"note": "Additive DGP stage for the existing stress_study graph. Copy into the portal harness. The CLI spelling that does not wait on the portal is `alphaengine process` or `stress --input dgp=ou` once this stage is live.",
|
|
6
|
+
"add_stage": {
|
|
7
|
+
"id": "dgp_stress",
|
|
8
|
+
"op": "compute.dgp_stress",
|
|
9
|
+
"input": "dgp",
|
|
10
|
+
"default": "gbm",
|
|
11
|
+
"values": ["ou", "gbm", "jump", "garch"],
|
|
12
|
+
"after": "compute.cost_ladder"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -63,12 +63,10 @@ is what a changed figure costs. The API may still move underneath it.
|
|
|
63
63
|
# doors, same refusals. The published artefact is a new wheel because 0.6.0
|
|
64
64
|
# already left the building.
|
|
65
65
|
#
|
|
66
|
-
# 0.
|
|
67
|
-
# PBO / performance / screen goldens stay byte-identical. The artefact
|
|
68
|
-
#
|
|
69
|
-
#
|
|
70
|
-
#
|
|
71
|
-
#
|
|
72
|
-
|
|
73
|
-
# did not move.
|
|
74
|
-
__version__ = "0.7.0"
|
|
66
|
+
# 0.8.0 IS THE MODELING SUITE THE REST OF THE LIBRARY WAS MISSING. Existing
|
|
67
|
+
# DSR / PBO / performance / screen goldens stay byte-identical. The artefact
|
|
68
|
+
# grew named processes (OU, GBM, jumps, GARCH), DGP stress with an honest
|
|
69
|
+
# Monte Carlo trial count, Grinold alpha / breadth / TC, a frozen chart
|
|
70
|
+
# vocabulary, and a terminal boot that is the README banner in glyphs.
|
|
71
|
+
# New figures are a public contract from this release; old numbers did not move.
|
|
72
|
+
__version__ = "0.8.0"
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""Frozen chart vocabulary the portal draws from figures.
|
|
2
|
+
|
|
3
|
+
A FIGURE IS A NAMED KIND, not a series. The executor attaches
|
|
4
|
+
`charts: [{kind, key, title}]` hints. The portal maps kind+key to a component.
|
|
5
|
+
Old portals ignore `charts` and still have the raw keys (`ic_by_period`,
|
|
6
|
+
`best_curve`, ...).
|
|
7
|
+
|
|
8
|
+
KINDS
|
|
9
|
+
curve {i, v} line
|
|
10
|
+
period {p, ic|lambda} CS time series
|
|
11
|
+
band {i, lo, mid, hi} fan / Monte Carlo quantile
|
|
12
|
+
hist {edges, counts} histogram
|
|
13
|
+
cost {bps, sharpe} cost ladder
|
|
14
|
+
scatter {x, y} overlap
|
|
15
|
+
triangle {a, b, v} covariance heatmap
|
|
16
|
+
rows bounded dict rows table
|
|
17
|
+
quantiles [float] bar
|
|
18
|
+
|
|
19
|
+
No hint may carry a nested series. Titles are one line, no em dash.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
__all__ = ["CHART_KINDS", "chart", "charts"]
|
|
25
|
+
|
|
26
|
+
CHART_KINDS = frozenset(
|
|
27
|
+
{
|
|
28
|
+
"curve",
|
|
29
|
+
"period",
|
|
30
|
+
"band",
|
|
31
|
+
"hist",
|
|
32
|
+
"cost",
|
|
33
|
+
"scatter",
|
|
34
|
+
"triangle",
|
|
35
|
+
"rows",
|
|
36
|
+
"quantiles",
|
|
37
|
+
}
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def chart(kind: str, key: str, title: str) -> dict[str, str]:
|
|
42
|
+
"""One portal hint. `kind` must be in CHART_KINDS."""
|
|
43
|
+
k = str(kind)
|
|
44
|
+
if k not in CHART_KINDS:
|
|
45
|
+
raise ValueError(f"unknown chart kind {k!r}; expected one of {sorted(CHART_KINDS)}")
|
|
46
|
+
return {"kind": k, "key": str(key), "title": str(title)}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def charts(*items: dict[str, str]) -> list[dict[str, str]]:
|
|
50
|
+
"""Hint list. Empty is allowed: the portal then uses raw keys only."""
|
|
51
|
+
out: list[dict[str, str]] = []
|
|
52
|
+
for item in items:
|
|
53
|
+
if not item:
|
|
54
|
+
continue
|
|
55
|
+
out.append(chart(item["kind"], item["key"], item["title"]) if "kind" in item else dict(item))
|
|
56
|
+
return out
|