alphaengine 0.6.1__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.
Files changed (86) hide show
  1. {alphaengine-0.6.1 → alphaengine-0.8.0}/AGENTS.md +24 -7
  2. {alphaengine-0.6.1 → alphaengine-0.8.0}/PKG-INFO +178 -19
  3. {alphaengine-0.6.1 → alphaengine-0.8.0}/README.md +178 -19
  4. alphaengine-0.8.0/docs/assets/banner.png +0 -0
  5. alphaengine-0.8.0/docs/assets/data_boundary.png +0 -0
  6. alphaengine-0.8.0/docs/assets/session.png +0 -0
  7. alphaengine-0.8.0/docs/figure_contract.md +46 -0
  8. alphaengine-0.8.0/docs/workflows/evaluate_process.json +18 -0
  9. alphaengine-0.8.0/docs/workflows/research_week.json +29 -0
  10. alphaengine-0.8.0/docs/workflows/stress_study.json +14 -0
  11. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/_version.py +8 -1
  12. alphaengine-0.8.0/src/alphaengine/charts.py +56 -0
  13. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/cli.py +414 -94
  14. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/client/executor.py +368 -0
  15. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/commands.py +64 -11
  16. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/core/__init__.py +40 -1
  17. alphaengine-0.8.0/src/alphaengine/core/active.py +95 -0
  18. alphaengine-0.8.0/src/alphaengine/core/allocate.py +245 -0
  19. alphaengine-0.8.0/src/alphaengine/core/covariance.py +181 -0
  20. alphaengine-0.8.0/src/alphaengine/core/cross_section.py +176 -0
  21. alphaengine-0.8.0/src/alphaengine/core/panel.py +289 -0
  22. alphaengine-0.8.0/src/alphaengine/core/process.py +450 -0
  23. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/core/signals.py +85 -0
  24. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/demo.py +2 -1
  25. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/repl.py +6 -1
  26. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/study/report.py +4 -0
  27. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/study/schema.py +7 -1
  28. {alphaengine-0.6.1 → alphaengine-0.8.0}/tests/test_cli.py +78 -6
  29. {alphaengine-0.6.1 → alphaengine-0.8.0}/tests/test_commands.py +7 -5
  30. alphaengine-0.8.0/tests/test_process.py +201 -0
  31. alphaengine-0.8.0/tests/test_quant_maths.py +286 -0
  32. {alphaengine-0.6.1 → alphaengine-0.8.0}/tests/test_sweep.py +27 -0
  33. {alphaengine-0.6.1 → alphaengine-0.8.0}/.github/workflows/ci.yml +0 -0
  34. {alphaengine-0.6.1 → alphaengine-0.8.0}/.github/workflows/publish.yml +0 -0
  35. {alphaengine-0.6.1 → alphaengine-0.8.0}/.gitignore +0 -0
  36. {alphaengine-0.6.1 → alphaengine-0.8.0}/LICENSE +0 -0
  37. {alphaengine-0.6.1 → alphaengine-0.8.0}/SECURITY.md +0 -0
  38. {alphaengine-0.6.1 → alphaengine-0.8.0}/pyproject.toml +0 -0
  39. {alphaengine-0.6.1 → alphaengine-0.8.0}/scripts/gen_docs.py +0 -0
  40. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/__init__.py +0 -0
  41. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/__main__.py +0 -0
  42. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/agent/__init__.py +0 -0
  43. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/agent/answer.py +0 -0
  44. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/agent/driver.py +0 -0
  45. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/auth.py +0 -0
  46. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/book.py +0 -0
  47. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/client/__init__.py +0 -0
  48. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/client/agent.py +0 -0
  49. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/client/session.py +0 -0
  50. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/complete.py +0 -0
  51. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/connectors/__init__.py +0 -0
  52. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/core/backtest.py +0 -0
  53. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/core/factors.py +0 -0
  54. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/core/pairs.py +0 -0
  55. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/core/performance.py +0 -0
  56. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/core/profile.py +0 -0
  57. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/core/risk.py +0 -0
  58. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/core/screen.py +0 -0
  59. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/core/series_shapes.py +0 -0
  60. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/core/stress.py +0 -0
  61. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/core/technical.py +0 -0
  62. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/core/validation.py +0 -0
  63. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/core/walkforward.py +0 -0
  64. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/demo_book.py +0 -0
  65. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/demo_returns.py +0 -0
  66. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/demo_signal.py +0 -0
  67. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/demo_universe.py +0 -0
  68. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/events.py +0 -0
  69. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/loaders.py +0 -0
  70. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/model.py +0 -0
  71. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/py.typed +0 -0
  72. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/study/__init__.py +0 -0
  73. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/sweep/__init__.py +0 -0
  74. {alphaengine-0.6.1 → alphaengine-0.8.0}/src/alphaengine/sweep/runner.py +0 -0
  75. {alphaengine-0.6.1 → alphaengine-0.8.0}/tests/test_agent.py +0 -0
  76. {alphaengine-0.6.1 → alphaengine-0.8.0}/tests/test_answer.py +0 -0
  77. {alphaengine-0.6.1 → alphaengine-0.8.0}/tests/test_book.py +0 -0
  78. {alphaengine-0.6.1 → alphaengine-0.8.0}/tests/test_client.py +0 -0
  79. {alphaengine-0.6.1 → alphaengine-0.8.0}/tests/test_events.py +0 -0
  80. {alphaengine-0.6.1 → alphaengine-0.8.0}/tests/test_executor_ops.py +0 -0
  81. {alphaengine-0.6.1 → alphaengine-0.8.0}/tests/test_goldens.py +0 -0
  82. {alphaengine-0.6.1 → alphaengine-0.8.0}/tests/test_loaders.py +0 -0
  83. {alphaengine-0.6.1 → alphaengine-0.8.0}/tests/test_model.py +0 -0
  84. {alphaengine-0.6.1 → alphaengine-0.8.0}/tests/test_screen.py +0 -0
  85. {alphaengine-0.6.1 → alphaengine-0.8.0}/tests/test_signals.py +0 -0
  86. {alphaengine-0.6.1 → alphaengine-0.8.0}/tests/test_smoke.py +0 -0
@@ -3,7 +3,8 @@
3
3
  ## Cursor Cloud specific instructions
4
4
 
5
5
  AlphaEngine is a pure-Python CLI + library (`alphaengine`) for validated quant
6
- research. There is no GUI; all interaction is via the terminal or
6
+ research. There is no windowed GUI: the product is a terminal session (an
7
+ animated parameter-surface canvas at boot and while Working) plus
7
8
  `import alphaengine`.
8
9
 
9
10
  ### Environment
@@ -29,12 +30,20 @@ research. There is no GUI; all interaction is via the terminal or
29
30
  - **Three rungs.** `demo` and the importable library are fully offline. Workflow
30
31
  CLI verbs (`diagnose`, `screen`, …, `run <workflow>`) need a portal
31
32
  `ae_live_` key (`QUANTOS_API_KEY`). Plain-English mode also needs a **model**
32
- key. Any OpenAI-compatible key works: Anthropic, OpenAI (`OPENAI_BASE_URL` for
33
+ key. In a session: `login` (QuantOS) or `login anthropic`. `key` is the same
34
+ verb. Any OpenAI-compatible key works: Anthropic, OpenAI (`OPENAI_BASE_URL` for
33
35
  gateways), Gemini, Groq, OpenRouter, Azure, or
34
36
  `ALPHAENGINE_API_KEY`+`ALPHAENGINE_BASE_URL`. `alphaengine models` lists what
35
37
  this machine can actually use. Keys may persist in
36
38
  `~/.config/alphaengine/credentials.json` (mode 0600) if the user says yes at
37
- `key <provider>`; env always wins. LLM keys are never sent to QuantOS.
39
+ `login`; env always wins. LLM keys are never sent to QuantOS.
40
+ - **One data verb.** `load prices.csv` / `load research.momentum` / `load sp500`
41
+ unifies `--data` / `--project` / `--universe`. The old verbs still work.
42
+ - **Motion is a real TTY.** Boot and `Working` paint a tall parameter-surface
43
+ canvas. Tests that monkeypatch `_tty` get colour without frame sleeps
44
+ (`_live_tty` gates motion). Do not add `time.sleep` on the `_tty()` path.
45
+ This image often has `NO_COLOR=1`; unset it to see the canvas
46
+ (`env -u NO_COLOR COLORTERM=truecolor TERM=xterm-256color`).
38
47
  - **A stop / `marginal` verdict exits 0.** Only a step that could not execute
39
48
  exits non-zero. Unauthenticated workflow calls exit 2.
40
49
  - **Data never leaves.** Executor and study-report guards refuse lists longer
@@ -45,10 +54,18 @@ research. There is no GUI; all interaction is via the terminal or
45
54
  keys. `alphaengine trace` reads the local dump.
46
55
  - **Goldens are a public contract.** Do not "fix" a golden to land a speedup;
47
56
  that is a version bump (`_version.py`).
48
- - **New compute ops** (`backtest`, `score_backtest`, `cpcv`, `factors`, `pairs`,
49
- `cointegrated_pairs`, `walk_forward`, `book_overlap`) are on the executor.
50
- The portal must offer them in a workflow graph or they sit unused; the CLI
51
- remains useful without them.
57
+ - **Compute ops on the executor** include the 0.6 workflow set (`backtest`,
58
+ `score_backtest`, `cpcv`, `factors`, `pairs`, `cointegrated_pairs`,
59
+ `walk_forward`, `book_overlap`), the 0.7 CS / book set
60
+ (`panel_transform`, `signal_icir`, `fama_macbeth`, `quantile_book`,
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
66
+ portal must offer an op in a workflow graph or it sits unused; the CLI
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.
52
69
  - `sweep(..., jobs=N)` defaults to 1. Greater than 1 is opt-in and must keep
53
70
  trial index identity, including failures.
54
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.6.1
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
@@ -40,17 +40,47 @@ Provides-Extra: factors
40
40
  Requires-Dist: statsmodels>=0.14; extra == 'factors'
41
41
  Description-Content-Type: text/markdown
42
42
 
43
- # AlphaEngine
43
+ <p align="center">
44
+ <img src="docs/assets/banner.png" alt="AlphaEngine: the research loop, on your machine" width="100%">
45
+ </p>
44
46
 
45
- **The research loop, on your machine.** Ask what is worth looking at, whether it
46
- holds up, how much to hold, and whether anything has crossed a line. Your data
47
- never leaves.
47
+ <h1 align="center">AlphaEngine</h1>
48
+
49
+ <p align="center">
50
+ <strong>The research loop, on your machine.</strong><br>
51
+ Ask what is worth looking at, whether it holds up, how much to hold,<br>
52
+ and whether anything has crossed a line. Your data never leaves.
53
+ </p>
54
+
55
+ <p align="center">
56
+ <a href="https://pypi.org/project/alphaengine/"><img src="https://img.shields.io/pypi/v/alphaengine.svg?style=flat-square&color=1B7A7A" alt="PyPI"></a>
57
+ <a href="https://pypi.org/project/alphaengine/"><img src="https://img.shields.io/pypi/pyversions/alphaengine.svg?style=flat-square" alt="Python 3.10+"></a>
58
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-0B1220?style=flat-square" alt="Apache 2.0"></a>
59
+ <a href="https://github.com/quantOSC/alphaengine/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/quantOSC/alphaengine/ci.yml?branch=main&style=flat-square&label=CI" alt="CI"></a>
60
+ <img src="https://img.shields.io/badge/deps-numpy%20%2B%20scipy-C4893A?style=flat-square" alt="Two dependencies: numpy and scipy">
61
+ </p>
48
62
 
49
63
  ```bash
50
64
  pip install alphaengine
51
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
67
+ ```
68
+
69
+ <p align="center">
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%">
71
+ </p>
72
+
73
+ The session is the product. Sign in, load something, then ask:
74
+
75
+ ```bash
76
+ alphaengine
77
+ ❯ login
78
+ ❯ load prices.csv
79
+ ❯ screen
52
80
  ```
53
81
 
82
+ ---
83
+
54
84
  ## What it answers
55
85
 
56
86
  Eight questions, in the order a research week actually asks them. The command
@@ -84,7 +114,7 @@ Or say it in plain English and let your own model pick:
84
114
 
85
115
  ```bash
86
116
  alphaengine
87
- > which of my names are overbought on RSI?
117
+ ❯ which of my names are overbought on RSI?
88
118
  ```
89
119
 
90
120
  That second path is EXPLORATORY: the model chooses a workflow and then chooses
@@ -92,27 +122,48 @@ each step from what the server permits. Two runs of the same question may
92
122
  differ, and the run says so. `run <workflow>` is SCRIPTED and reproducible.
93
123
  Both are legitimate; presenting one as the other is not.
94
124
 
125
+ ---
126
+
95
127
  ## The three rungs
96
128
 
97
- Each is useful without the one above it. The boot screen shows which are lit.
129
+ Each is useful without the one above it. `login` lights the next one.
98
130
 
99
131
  | Rung | What you need | What you get |
100
132
  |---|---|---|
101
133
  | **The maths** | nothing | Every statistic, offline, forever. No account. |
102
- | **Workflows** | a QuantOS `ae_live_` key | The loop end to end, with the record. |
103
- | **Ask anything** | your OWN model key | Plain English in. Runs under your account, not ours. |
134
+ | **Workflows** | a QuantOS `ae_live_` key (`login`) | The loop end to end, with the record. |
135
+ | **Ask anything** | your OWN model key (`login anthropic`) | Plain English in. Runs under your account, not ours. |
104
136
 
105
137
  Nothing here stores a model key: it is read from your environment at call time
106
138
  and handed to the provider's own client. There is no field to put one in.
107
139
 
140
+ ```mermaid
141
+ flowchart LR
142
+ A["demo / import<br/>offline maths"] --> B["login<br/>QuantOS key"]
143
+ B --> C["login anthropic<br/>your model"]
144
+ A -.->|"no account"| D["DSR · PBO · ICIR · HRP"]
145
+ B -.->|"ae_live_"| E["screen · validate · runs"]
146
+ C -.->|"BYOK"| F["plain English in"]
147
+ ```
148
+
149
+ ---
150
+
108
151
  ## Getting your data in
109
152
 
110
- Three doors, and nothing is ever fetched on your behalf.
153
+ One verb, three shapes. Nothing is ever fetched on your behalf.
154
+
155
+ ```bash
156
+ load prices.csv # a local CSV
157
+ load sp500 # registered in the portal, with the closes you stored
158
+ load research.momentum # a module of yours (the only door that can carry a simulator)
159
+ ```
160
+
161
+ From a shell the same doors are flags, for scripts:
111
162
 
112
163
  ```bash
113
- alphaengine run screen_universe --data prices.csv # a local CSV
114
- alphaengine run screen_universe --universe sp500 # registered in the portal
115
- alphaengine run validate_study --project research.momentum # a module of yours
164
+ alphaengine screen --data prices.csv
165
+ alphaengine screen --universe sp500
166
+ alphaengine validate --project research.momentum
116
167
  ```
117
168
 
118
169
  `--data` reads three shapes, decided by the header and nothing else:
@@ -136,6 +187,68 @@ for the scores it measures — while the rest run on prices alone.
136
187
  upload decrypted back to your own account, not us fetching market data, and the
137
188
  distinction is the whole of the data boundary below.
138
189
 
190
+ <p align="center">
191
+ <img src="docs/assets/data_boundary.png" alt="Your machine holds prices and notebooks; only figures cross to the QuantOS record" width="92%">
192
+ </p>
193
+
194
+ ---
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
+
225
+ ## What's new in 0.7.0
226
+
227
+ The daily modelling morning, and the overnight book, without a third
228
+ dependency. Existing goldens (deflated Sharpe, PBO, performance, screen) are
229
+ byte-identical. New figures are a public contract from this release.
230
+
231
+ | You have | You get | Module |
232
+ |---|---|---|
233
+ | A raw factor panel | Cross-sectional rank, z-score, winsorize, neutralize | `core.panel` |
234
+ | A signal and prices | ICIR, Newey-West t-stat, Fama-MacBeth λ, quantile book with one-way turnover | `core.signals`, `core.cross_section` |
235
+ | A return panel | EWMA / Ledoit-Wolf / Marchenko-Pastur covariance, HRP, risk parity, vol target | `core.covariance`, `core.allocate` |
236
+
237
+ The session is slimmer too: `login` lights a rung, `load` is the one data verb,
238
+ and boot paints the parameter surface this tool actually judges rather than a
239
+ command encyclopedia.
240
+
241
+ ```python
242
+ from alphaengine.core import cs_zscore, signal_icir, hrp_weights, fama_macbeth
243
+
244
+ z = cs_zscore(factor_panel) # skipped names are counted, not dropped
245
+ ic = signal_icir(signal, prices) # Spearman ICIR; Pearson is opt-in
246
+ fm = fama_macbeth(signal, prices) # λ_mean, t-stat, Newey-West
247
+ w = hrp_weights(cov, names=names) # no matrix inverse; weights sum to one
248
+ ```
249
+
250
+ ---
251
+
139
252
  ## Command reference
140
253
 
141
254
  `alphaengine commands` prints this directory in the terminal, and
@@ -150,11 +263,13 @@ distinction is the whole of the data boundary below.
150
263
  | Command | Does | Where |
151
264
  |---|---|---|
152
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 |
153
267
  | `runs [--limit N]` | your own week: what ran, what it decided, what it filed | shell + session |
154
268
  | `gaps` | what your record says is UNANSWERED, and what closes each one | shell + session |
155
269
  | `tonight [--budget N]` | what would run unattended tonight, without running any of it | shell + session |
156
270
  | `workflows` | what the server offers, what each needs, and which reproduce | shell + session |
157
- | `key [quantos \| anthropic \| openai \| gemini \| groq \| azure \| openrouter \| gateway]` | enter a credential now, or see which rungs are unlocked | session |
271
+ | `login [quantos \| anthropic \| openai \| gemini \| groq \| azure \| openrouter \| gateway]` | sign in, or login anthropic for a model key | shell + session |
272
+ | `key [quantos \| anthropic \| openai \| gemini \| groq \| azure \| openrouter \| gateway]` | same as login: enter a credential, or see which rungs are lit | session |
158
273
  | `commands [verb]` | this directory, or one command in full | shell + session |
159
274
  | `models` | which model providers this machine can actually use | shell + session |
160
275
  | `model [<provider[:name]>]` | pin the model for this session, or show the pin | session |
@@ -181,9 +296,10 @@ distinction is the whole of the data boundary below.
181
296
  | Command | Does | Where |
182
297
  |---|---|---|
183
298
  | `book [<name> \| status]` | show or load sleeves on the multi-strategy book | session |
184
- | `universe <name>` | load a universe you registered in the portal, with its closes | session |
185
- | `data <file>` | load a local CSV or parquet without leaving the session | session |
186
- | `project <module>` | load `data` and `backtest_fn` from a module of yours | session |
299
+ | `load <file \| module \| universe>` | a CSV, a project module, or a portal universe | session |
300
+ | `universe <name>` | same as load: a universe registered in the portal | session |
301
+ | `data <file>` | same as load: a local CSV or parquet | session |
302
+ | `project <module>` | same as load: a module with data and backtest_fn | session |
187
303
 
188
304
  ### Session
189
305
 
@@ -191,7 +307,7 @@ distinction is the whole of the data boundary below.
191
307
  |---|---|---|
192
308
  | `logout` | remove stored credentials from this machine | shell + session |
193
309
  | `version` | print the version | shell |
194
- | `help` | the short list | session |
310
+ | `help` | the short list: demo, login, load, then a question | session |
195
311
  | `quit` | leave the session | session |
196
312
 
197
313
  ### Data flags
@@ -231,12 +347,15 @@ alphaengine overlap
231
347
  alphaengine size
232
348
  alphaengine monitor
233
349
  alphaengine demo
350
+ alphaengine process
351
+ alphaengine process ou
234
352
  alphaengine runs
235
353
  alphaengine runs --limit 50
236
354
  alphaengine gaps
237
355
  alphaengine tonight
238
356
  alphaengine tonight --budget 5
239
357
  alphaengine workflows
358
+ alphaengine login
240
359
  alphaengine commands
241
360
  alphaengine run screen_universe --universe sp500
242
361
  alphaengine run size_position --data returns.csv
@@ -329,7 +448,15 @@ diffable, and versioned so it still parses in two years.
329
448
 
330
449
  | Module | Contents |
331
450
  |---|---|
332
- | `alphaengine.core` | deflated Sharpe, PSR, PBO via CSCV, CPCV, minimum track record length, performance and risk statistics |
451
+ | `alphaengine.core` | deflated Sharpe, PSR, PBO via CSCV, CPCV, minimum track record length, performance and risk |
452
+ | `alphaengine.core.panel` | cross-sectional rank, z-score, winsorize, neutralize |
453
+ | `alphaengine.core.signals` | IC, ICIR, quantile returns, decay |
454
+ | `alphaengine.core.cross_section` | Fama-MacBeth, quantile book with turnover |
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) |
333
460
  | `alphaengine.sweep` | the grid runner and the sensitivity surface |
334
461
  | `alphaengine.study` | the study artifact and its schema |
335
462
  | `alphaengine.client` | the workflow client and the step executor |
@@ -401,12 +528,44 @@ Probability of Backtest Overfitting." *Journal of Computational Finance* 20(4),
401
528
  López de Prado, M. (2018). *Advances in Financial Machine Learning.* Wiley,
402
529
  chapters 7 and 12.
403
530
 
531
+ **Hierarchical Risk Parity**
532
+ López de Prado, M. (2016). "Building Diversified Portfolios that Outperform
533
+ Out of Sample." *Journal of Portfolio Management* 42(4), 59 to 69.
534
+
535
+ **Covariance shrinkage and spectral denoising**
536
+ Ledoit, O., and Wolf, M. (2004). "A Well-Conditioned Estimator for
537
+ Large-Dimensional Covariance Matrices." *Journal of Multivariate Analysis*
538
+ 88(2), 365 to 411.
539
+ Laloux, L., Cizeau, P., Bouchaud, J.-P., and Potters, M. (1999). "Noise
540
+ Dressing of Financial Correlation Matrices." *Physical Review Letters* 83(7),
541
+ 1467 to 1470.
542
+
404
543
  **Multiple testing in asset pricing**
405
544
  Harvey, C. R., Liu, Y., and Zhu, H. (2016). "... and the Cross-Section of
406
545
  Expected Returns." *Review of Financial Studies* 29(1), 5 to 68.
407
546
  Harvey, C. R., and Liu, Y. (2015). "Backtesting." *Journal of Portfolio
408
547
  Management* 42(1), 13 to 28.
409
548
 
549
+ **Fama-MacBeth**
550
+ Fama, E. F., and MacBeth, J. D. (1973). "Risk, Return, and Equilibrium:
551
+ Empirical Tests." *Journal of Political Economy* 81(3), 607 to 636.
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
+
410
569
  **Downside deviation**
411
570
  Sortino, F. A., and Price, L. N. (1994). "Performance Measurement in a Downside
412
571
  Risk Framework." *Journal of Investing* 3(3), 59 to 64.
@@ -1,14 +1,44 @@
1
- # AlphaEngine
2
-
3
- **The research loop, on your machine.** Ask what is worth looking at, whether it
4
- holds up, how much to hold, and whether anything has crossed a line. Your data
5
- never leaves.
1
+ <p align="center">
2
+ <img src="docs/assets/banner.png" alt="AlphaEngine: the research loop, on your machine" width="100%">
3
+ </p>
4
+
5
+ <h1 align="center">AlphaEngine</h1>
6
+
7
+ <p align="center">
8
+ <strong>The research loop, on your machine.</strong><br>
9
+ Ask what is worth looking at, whether it holds up, how much to hold,<br>
10
+ and whether anything has crossed a line. Your data never leaves.
11
+ </p>
12
+
13
+ <p align="center">
14
+ <a href="https://pypi.org/project/alphaengine/"><img src="https://img.shields.io/pypi/v/alphaengine.svg?style=flat-square&color=1B7A7A" alt="PyPI"></a>
15
+ <a href="https://pypi.org/project/alphaengine/"><img src="https://img.shields.io/pypi/pyversions/alphaengine.svg?style=flat-square" alt="Python 3.10+"></a>
16
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-0B1220?style=flat-square" alt="Apache 2.0"></a>
17
+ <a href="https://github.com/quantOSC/alphaengine/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/quantOSC/alphaengine/ci.yml?branch=main&style=flat-square&label=CI" alt="CI"></a>
18
+ <img src="https://img.shields.io/badge/deps-numpy%20%2B%20scipy-C4893A?style=flat-square" alt="Two dependencies: numpy and scipy">
19
+ </p>
6
20
 
7
21
  ```bash
8
22
  pip install alphaengine
9
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
25
+ ```
26
+
27
+ <p align="center">
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%">
29
+ </p>
30
+
31
+ The session is the product. Sign in, load something, then ask:
32
+
33
+ ```bash
34
+ alphaengine
35
+ ❯ login
36
+ ❯ load prices.csv
37
+ ❯ screen
10
38
  ```
11
39
 
40
+ ---
41
+
12
42
  ## What it answers
13
43
 
14
44
  Eight questions, in the order a research week actually asks them. The command
@@ -42,7 +72,7 @@ Or say it in plain English and let your own model pick:
42
72
 
43
73
  ```bash
44
74
  alphaengine
45
- > which of my names are overbought on RSI?
75
+ ❯ which of my names are overbought on RSI?
46
76
  ```
47
77
 
48
78
  That second path is EXPLORATORY: the model chooses a workflow and then chooses
@@ -50,27 +80,48 @@ each step from what the server permits. Two runs of the same question may
50
80
  differ, and the run says so. `run <workflow>` is SCRIPTED and reproducible.
51
81
  Both are legitimate; presenting one as the other is not.
52
82
 
83
+ ---
84
+
53
85
  ## The three rungs
54
86
 
55
- Each is useful without the one above it. The boot screen shows which are lit.
87
+ Each is useful without the one above it. `login` lights the next one.
56
88
 
57
89
  | Rung | What you need | What you get |
58
90
  |---|---|---|
59
91
  | **The maths** | nothing | Every statistic, offline, forever. No account. |
60
- | **Workflows** | a QuantOS `ae_live_` key | The loop end to end, with the record. |
61
- | **Ask anything** | your OWN model key | Plain English in. Runs under your account, not ours. |
92
+ | **Workflows** | a QuantOS `ae_live_` key (`login`) | The loop end to end, with the record. |
93
+ | **Ask anything** | your OWN model key (`login anthropic`) | Plain English in. Runs under your account, not ours. |
62
94
 
63
95
  Nothing here stores a model key: it is read from your environment at call time
64
96
  and handed to the provider's own client. There is no field to put one in.
65
97
 
98
+ ```mermaid
99
+ flowchart LR
100
+ A["demo / import<br/>offline maths"] --> B["login<br/>QuantOS key"]
101
+ B --> C["login anthropic<br/>your model"]
102
+ A -.->|"no account"| D["DSR · PBO · ICIR · HRP"]
103
+ B -.->|"ae_live_"| E["screen · validate · runs"]
104
+ C -.->|"BYOK"| F["plain English in"]
105
+ ```
106
+
107
+ ---
108
+
66
109
  ## Getting your data in
67
110
 
68
- Three doors, and nothing is ever fetched on your behalf.
111
+ One verb, three shapes. Nothing is ever fetched on your behalf.
69
112
 
70
113
  ```bash
71
- alphaengine run screen_universe --data prices.csv # a local CSV
72
- alphaengine run screen_universe --universe sp500 # registered in the portal
73
- alphaengine run validate_study --project research.momentum # a module of yours
114
+ load prices.csv # a local CSV
115
+ load sp500 # registered in the portal, with the closes you stored
116
+ load research.momentum # a module of yours (the only door that can carry a simulator)
117
+ ```
118
+
119
+ From a shell the same doors are flags, for scripts:
120
+
121
+ ```bash
122
+ alphaengine screen --data prices.csv
123
+ alphaengine screen --universe sp500
124
+ alphaengine validate --project research.momentum
74
125
  ```
75
126
 
76
127
  `--data` reads three shapes, decided by the header and nothing else:
@@ -94,6 +145,68 @@ for the scores it measures — while the rest run on prices alone.
94
145
  upload decrypted back to your own account, not us fetching market data, and the
95
146
  distinction is the whole of the data boundary below.
96
147
 
148
+ <p align="center">
149
+ <img src="docs/assets/data_boundary.png" alt="Your machine holds prices and notebooks; only figures cross to the QuantOS record" width="92%">
150
+ </p>
151
+
152
+ ---
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
+
183
+ ## What's new in 0.7.0
184
+
185
+ The daily modelling morning, and the overnight book, without a third
186
+ dependency. Existing goldens (deflated Sharpe, PBO, performance, screen) are
187
+ byte-identical. New figures are a public contract from this release.
188
+
189
+ | You have | You get | Module |
190
+ |---|---|---|
191
+ | A raw factor panel | Cross-sectional rank, z-score, winsorize, neutralize | `core.panel` |
192
+ | A signal and prices | ICIR, Newey-West t-stat, Fama-MacBeth λ, quantile book with one-way turnover | `core.signals`, `core.cross_section` |
193
+ | A return panel | EWMA / Ledoit-Wolf / Marchenko-Pastur covariance, HRP, risk parity, vol target | `core.covariance`, `core.allocate` |
194
+
195
+ The session is slimmer too: `login` lights a rung, `load` is the one data verb,
196
+ and boot paints the parameter surface this tool actually judges rather than a
197
+ command encyclopedia.
198
+
199
+ ```python
200
+ from alphaengine.core import cs_zscore, signal_icir, hrp_weights, fama_macbeth
201
+
202
+ z = cs_zscore(factor_panel) # skipped names are counted, not dropped
203
+ ic = signal_icir(signal, prices) # Spearman ICIR; Pearson is opt-in
204
+ fm = fama_macbeth(signal, prices) # λ_mean, t-stat, Newey-West
205
+ w = hrp_weights(cov, names=names) # no matrix inverse; weights sum to one
206
+ ```
207
+
208
+ ---
209
+
97
210
  ## Command reference
98
211
 
99
212
  `alphaengine commands` prints this directory in the terminal, and
@@ -108,11 +221,13 @@ distinction is the whole of the data boundary below.
108
221
  | Command | Does | Where |
109
222
  |---|---|---|
110
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 |
111
225
  | `runs [--limit N]` | your own week: what ran, what it decided, what it filed | shell + session |
112
226
  | `gaps` | what your record says is UNANSWERED, and what closes each one | shell + session |
113
227
  | `tonight [--budget N]` | what would run unattended tonight, without running any of it | shell + session |
114
228
  | `workflows` | what the server offers, what each needs, and which reproduce | shell + session |
115
- | `key [quantos \| anthropic \| openai \| gemini \| groq \| azure \| openrouter \| gateway]` | enter a credential now, or see which rungs are unlocked | session |
229
+ | `login [quantos \| anthropic \| openai \| gemini \| groq \| azure \| openrouter \| gateway]` | sign in, or login anthropic for a model key | shell + session |
230
+ | `key [quantos \| anthropic \| openai \| gemini \| groq \| azure \| openrouter \| gateway]` | same as login: enter a credential, or see which rungs are lit | session |
116
231
  | `commands [verb]` | this directory, or one command in full | shell + session |
117
232
  | `models` | which model providers this machine can actually use | shell + session |
118
233
  | `model [<provider[:name]>]` | pin the model for this session, or show the pin | session |
@@ -139,9 +254,10 @@ distinction is the whole of the data boundary below.
139
254
  | Command | Does | Where |
140
255
  |---|---|---|
141
256
  | `book [<name> \| status]` | show or load sleeves on the multi-strategy book | session |
142
- | `universe <name>` | load a universe you registered in the portal, with its closes | session |
143
- | `data <file>` | load a local CSV or parquet without leaving the session | session |
144
- | `project <module>` | load `data` and `backtest_fn` from a module of yours | session |
257
+ | `load <file \| module \| universe>` | a CSV, a project module, or a portal universe | session |
258
+ | `universe <name>` | same as load: a universe registered in the portal | session |
259
+ | `data <file>` | same as load: a local CSV or parquet | session |
260
+ | `project <module>` | same as load: a module with data and backtest_fn | session |
145
261
 
146
262
  ### Session
147
263
 
@@ -149,7 +265,7 @@ distinction is the whole of the data boundary below.
149
265
  |---|---|---|
150
266
  | `logout` | remove stored credentials from this machine | shell + session |
151
267
  | `version` | print the version | shell |
152
- | `help` | the short list | session |
268
+ | `help` | the short list: demo, login, load, then a question | session |
153
269
  | `quit` | leave the session | session |
154
270
 
155
271
  ### Data flags
@@ -189,12 +305,15 @@ alphaengine overlap
189
305
  alphaengine size
190
306
  alphaengine monitor
191
307
  alphaengine demo
308
+ alphaengine process
309
+ alphaengine process ou
192
310
  alphaengine runs
193
311
  alphaengine runs --limit 50
194
312
  alphaengine gaps
195
313
  alphaengine tonight
196
314
  alphaengine tonight --budget 5
197
315
  alphaengine workflows
316
+ alphaengine login
198
317
  alphaengine commands
199
318
  alphaengine run screen_universe --universe sp500
200
319
  alphaengine run size_position --data returns.csv
@@ -287,7 +406,15 @@ diffable, and versioned so it still parses in two years.
287
406
 
288
407
  | Module | Contents |
289
408
  |---|---|
290
- | `alphaengine.core` | deflated Sharpe, PSR, PBO via CSCV, CPCV, minimum track record length, performance and risk statistics |
409
+ | `alphaengine.core` | deflated Sharpe, PSR, PBO via CSCV, CPCV, minimum track record length, performance and risk |
410
+ | `alphaengine.core.panel` | cross-sectional rank, z-score, winsorize, neutralize |
411
+ | `alphaengine.core.signals` | IC, ICIR, quantile returns, decay |
412
+ | `alphaengine.core.cross_section` | Fama-MacBeth, quantile book with turnover |
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) |
291
418
  | `alphaengine.sweep` | the grid runner and the sensitivity surface |
292
419
  | `alphaengine.study` | the study artifact and its schema |
293
420
  | `alphaengine.client` | the workflow client and the step executor |
@@ -359,12 +486,44 @@ Probability of Backtest Overfitting." *Journal of Computational Finance* 20(4),
359
486
  López de Prado, M. (2018). *Advances in Financial Machine Learning.* Wiley,
360
487
  chapters 7 and 12.
361
488
 
489
+ **Hierarchical Risk Parity**
490
+ López de Prado, M. (2016). "Building Diversified Portfolios that Outperform
491
+ Out of Sample." *Journal of Portfolio Management* 42(4), 59 to 69.
492
+
493
+ **Covariance shrinkage and spectral denoising**
494
+ Ledoit, O., and Wolf, M. (2004). "A Well-Conditioned Estimator for
495
+ Large-Dimensional Covariance Matrices." *Journal of Multivariate Analysis*
496
+ 88(2), 365 to 411.
497
+ Laloux, L., Cizeau, P., Bouchaud, J.-P., and Potters, M. (1999). "Noise
498
+ Dressing of Financial Correlation Matrices." *Physical Review Letters* 83(7),
499
+ 1467 to 1470.
500
+
362
501
  **Multiple testing in asset pricing**
363
502
  Harvey, C. R., Liu, Y., and Zhu, H. (2016). "... and the Cross-Section of
364
503
  Expected Returns." *Review of Financial Studies* 29(1), 5 to 68.
365
504
  Harvey, C. R., and Liu, Y. (2015). "Backtesting." *Journal of Portfolio
366
505
  Management* 42(1), 13 to 28.
367
506
 
507
+ **Fama-MacBeth**
508
+ Fama, E. F., and MacBeth, J. D. (1973). "Risk, Return, and Equilibrium:
509
+ Empirical Tests." *Journal of Political Economy* 81(3), 607 to 636.
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
+
368
527
  **Downside deviation**
369
528
  Sortino, F. A., and Price, L. N. (1994). "Performance Measurement in a Downside
370
529
  Risk Framework." *Journal of Investing* 3(3), 59 to 64.
Binary file