alphaengine 0.6.0__tar.gz → 0.7.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 (79) hide show
  1. {alphaengine-0.6.0 → alphaengine-0.7.0}/AGENTS.md +21 -7
  2. {alphaengine-0.6.0 → alphaengine-0.7.0}/PKG-INFO +130 -19
  3. {alphaengine-0.6.0 → alphaengine-0.7.0}/README.md +130 -19
  4. alphaengine-0.7.0/docs/assets/banner.png +0 -0
  5. alphaengine-0.7.0/docs/assets/data_boundary.png +0 -0
  6. alphaengine-0.7.0/docs/assets/mark.png +0 -0
  7. alphaengine-0.7.0/docs/assets/session.png +0 -0
  8. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/_version.py +16 -1
  9. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/cli.py +390 -185
  10. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/client/executor.py +178 -0
  11. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/commands.py +42 -11
  12. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/core/__init__.py +21 -1
  13. alphaengine-0.7.0/src/alphaengine/core/allocate.py +221 -0
  14. alphaengine-0.7.0/src/alphaengine/core/covariance.py +167 -0
  15. alphaengine-0.7.0/src/alphaengine/core/cross_section.py +176 -0
  16. alphaengine-0.7.0/src/alphaengine/core/panel.py +289 -0
  17. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/core/signals.py +85 -0
  18. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/demo.py +7 -2
  19. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/repl.py +5 -1
  20. {alphaengine-0.6.0 → alphaengine-0.7.0}/tests/test_cli.py +60 -6
  21. {alphaengine-0.6.0 → alphaengine-0.7.0}/tests/test_commands.py +6 -4
  22. alphaengine-0.7.0/tests/test_quant_maths.py +286 -0
  23. {alphaengine-0.6.0 → alphaengine-0.7.0}/.github/workflows/ci.yml +0 -0
  24. {alphaengine-0.6.0 → alphaengine-0.7.0}/.github/workflows/publish.yml +0 -0
  25. {alphaengine-0.6.0 → alphaengine-0.7.0}/.gitignore +0 -0
  26. {alphaengine-0.6.0 → alphaengine-0.7.0}/LICENSE +0 -0
  27. {alphaengine-0.6.0 → alphaengine-0.7.0}/SECURITY.md +0 -0
  28. {alphaengine-0.6.0 → alphaengine-0.7.0}/pyproject.toml +0 -0
  29. {alphaengine-0.6.0 → alphaengine-0.7.0}/scripts/gen_docs.py +0 -0
  30. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/__init__.py +0 -0
  31. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/__main__.py +0 -0
  32. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/agent/__init__.py +0 -0
  33. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/agent/answer.py +0 -0
  34. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/agent/driver.py +0 -0
  35. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/auth.py +0 -0
  36. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/book.py +0 -0
  37. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/client/__init__.py +0 -0
  38. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/client/agent.py +0 -0
  39. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/client/session.py +0 -0
  40. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/complete.py +0 -0
  41. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/connectors/__init__.py +0 -0
  42. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/core/backtest.py +0 -0
  43. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/core/factors.py +0 -0
  44. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/core/pairs.py +0 -0
  45. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/core/performance.py +0 -0
  46. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/core/profile.py +0 -0
  47. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/core/risk.py +0 -0
  48. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/core/screen.py +0 -0
  49. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/core/series_shapes.py +0 -0
  50. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/core/stress.py +0 -0
  51. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/core/technical.py +0 -0
  52. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/core/validation.py +0 -0
  53. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/core/walkforward.py +0 -0
  54. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/demo_book.py +0 -0
  55. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/demo_returns.py +0 -0
  56. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/demo_signal.py +0 -0
  57. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/demo_universe.py +0 -0
  58. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/events.py +0 -0
  59. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/loaders.py +0 -0
  60. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/model.py +0 -0
  61. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/py.typed +0 -0
  62. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/study/__init__.py +0 -0
  63. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/study/report.py +0 -0
  64. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/study/schema.py +0 -0
  65. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/sweep/__init__.py +0 -0
  66. {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/sweep/runner.py +0 -0
  67. {alphaengine-0.6.0 → alphaengine-0.7.0}/tests/test_agent.py +0 -0
  68. {alphaengine-0.6.0 → alphaengine-0.7.0}/tests/test_answer.py +0 -0
  69. {alphaengine-0.6.0 → alphaengine-0.7.0}/tests/test_book.py +0 -0
  70. {alphaengine-0.6.0 → alphaengine-0.7.0}/tests/test_client.py +0 -0
  71. {alphaengine-0.6.0 → alphaengine-0.7.0}/tests/test_events.py +0 -0
  72. {alphaengine-0.6.0 → alphaengine-0.7.0}/tests/test_executor_ops.py +0 -0
  73. {alphaengine-0.6.0 → alphaengine-0.7.0}/tests/test_goldens.py +0 -0
  74. {alphaengine-0.6.0 → alphaengine-0.7.0}/tests/test_loaders.py +0 -0
  75. {alphaengine-0.6.0 → alphaengine-0.7.0}/tests/test_model.py +0 -0
  76. {alphaengine-0.6.0 → alphaengine-0.7.0}/tests/test_screen.py +0 -0
  77. {alphaengine-0.6.0 → alphaengine-0.7.0}/tests/test_signals.py +0 -0
  78. {alphaengine-0.6.0 → alphaengine-0.7.0}/tests/test_smoke.py +0 -0
  79. {alphaengine-0.6.0 → alphaengine-0.7.0}/tests/test_sweep.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,15 @@ 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`) and 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`). Panels and
62
+ covariance matrices stay in the workspace; figures go over the wire. The
63
+ portal must offer an op in a workflow graph or it sits unused; the CLI
64
+ remains useful without them. Short names in a panel are skipped and counted,
65
+ they do not shrink the rest of the book.
52
66
  - `sweep(..., jobs=N)` defaults to 1. Greater than 1 is opt-in and must keep
53
67
  trial index identity, including failures.
54
68
  - 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.0
3
+ Version: 0.7.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,50 @@ 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>
62
+
63
+ <p align="center">
64
+ <img src="docs/assets/mark.png" alt="AlphaEngine mark" width="96">
65
+ </p>
48
66
 
49
67
  ```bash
50
68
  pip install alphaengine
51
69
  alphaengine demo # the whole offline half, no account, no data of your own
52
70
  ```
53
71
 
72
+ <p align="center">
73
+ <img src="docs/assets/session.png" alt="The session canvas: a living parameter surface, then demo, login, load" width="92%">
74
+ </p>
75
+
76
+ The session is the product. Sign in, load something, then ask:
77
+
78
+ ```bash
79
+ alphaengine
80
+ ❯ login
81
+ ❯ load prices.csv
82
+ ❯ screen
83
+ ```
84
+
85
+ ---
86
+
54
87
  ## What it answers
55
88
 
56
89
  Eight questions, in the order a research week actually asks them. The command
@@ -84,7 +117,7 @@ Or say it in plain English and let your own model pick:
84
117
 
85
118
  ```bash
86
119
  alphaengine
87
- > which of my names are overbought on RSI?
120
+ ❯ which of my names are overbought on RSI?
88
121
  ```
89
122
 
90
123
  That second path is EXPLORATORY: the model chooses a workflow and then chooses
@@ -92,27 +125,48 @@ each step from what the server permits. Two runs of the same question may
92
125
  differ, and the run says so. `run <workflow>` is SCRIPTED and reproducible.
93
126
  Both are legitimate; presenting one as the other is not.
94
127
 
128
+ ---
129
+
95
130
  ## The three rungs
96
131
 
97
- Each is useful without the one above it. The boot screen shows which are lit.
132
+ Each is useful without the one above it. `login` lights the next one.
98
133
 
99
134
  | Rung | What you need | What you get |
100
135
  |---|---|---|
101
136
  | **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. |
137
+ | **Workflows** | a QuantOS `ae_live_` key (`login`) | The loop end to end, with the record. |
138
+ | **Ask anything** | your OWN model key (`login anthropic`) | Plain English in. Runs under your account, not ours. |
104
139
 
105
140
  Nothing here stores a model key: it is read from your environment at call time
106
141
  and handed to the provider's own client. There is no field to put one in.
107
142
 
143
+ ```mermaid
144
+ flowchart LR
145
+ A["demo / import<br/>offline maths"] --> B["login<br/>QuantOS key"]
146
+ B --> C["login anthropic<br/>your model"]
147
+ A -.->|"no account"| D["DSR · PBO · ICIR · HRP"]
148
+ B -.->|"ae_live_"| E["screen · validate · runs"]
149
+ C -.->|"BYOK"| F["plain English in"]
150
+ ```
151
+
152
+ ---
153
+
108
154
  ## Getting your data in
109
155
 
110
- Three doors, and nothing is ever fetched on your behalf.
156
+ One verb, three shapes. Nothing is ever fetched on your behalf.
157
+
158
+ ```bash
159
+ load prices.csv # a local CSV
160
+ load sp500 # registered in the portal, with the closes you stored
161
+ load research.momentum # a module of yours (the only door that can carry a simulator)
162
+ ```
163
+
164
+ From a shell the same doors are flags, for scripts:
111
165
 
112
166
  ```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
167
+ alphaengine screen --data prices.csv
168
+ alphaengine screen --universe sp500
169
+ alphaengine validate --project research.momentum
116
170
  ```
117
171
 
118
172
  `--data` reads three shapes, decided by the header and nothing else:
@@ -136,6 +190,39 @@ for the scores it measures — while the rest run on prices alone.
136
190
  upload decrypted back to your own account, not us fetching market data, and the
137
191
  distinction is the whole of the data boundary below.
138
192
 
193
+ <p align="center">
194
+ <img src="docs/assets/data_boundary.png" alt="Your machine holds prices and notebooks; only figures cross to the QuantOS record" width="92%">
195
+ </p>
196
+
197
+ ---
198
+
199
+ ## What's new in 0.7.0
200
+
201
+ The daily modelling morning, and the overnight book, without a third
202
+ dependency. Existing goldens (deflated Sharpe, PBO, performance, screen) are
203
+ byte-identical. New figures are a public contract from this release.
204
+
205
+ | You have | You get | Module |
206
+ |---|---|---|
207
+ | A raw factor panel | Cross-sectional rank, z-score, winsorize, neutralize | `core.panel` |
208
+ | A signal and prices | ICIR, Newey-West t-stat, Fama-MacBeth λ, quantile book with one-way turnover | `core.signals`, `core.cross_section` |
209
+ | A return panel | EWMA / Ledoit-Wolf / Marchenko-Pastur covariance, HRP, risk parity, vol target | `core.covariance`, `core.allocate` |
210
+
211
+ The session is slimmer too: `login` lights a rung, `load` is the one data verb,
212
+ and boot paints the parameter surface this tool actually judges rather than a
213
+ command encyclopedia.
214
+
215
+ ```python
216
+ from alphaengine.core import cs_zscore, signal_icir, hrp_weights, fama_macbeth
217
+
218
+ z = cs_zscore(factor_panel) # skipped names are counted, not dropped
219
+ ic = signal_icir(signal, prices) # Spearman ICIR; Pearson is opt-in
220
+ fm = fama_macbeth(signal, prices) # λ_mean, t-stat, Newey-West
221
+ w = hrp_weights(cov, names=names) # no matrix inverse; weights sum to one
222
+ ```
223
+
224
+ ---
225
+
139
226
  ## Command reference
140
227
 
141
228
  `alphaengine commands` prints this directory in the terminal, and
@@ -154,7 +241,8 @@ distinction is the whole of the data boundary below.
154
241
  | `gaps` | what your record says is UNANSWERED, and what closes each one | shell + session |
155
242
  | `tonight [--budget N]` | what would run unattended tonight, without running any of it | shell + session |
156
243
  | `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 |
244
+ | `login [quantos \| anthropic \| openai \| gemini \| groq \| azure \| openrouter \| gateway]` | sign in, or login anthropic for a model key | shell + session |
245
+ | `key [quantos \| anthropic \| openai \| gemini \| groq \| azure \| openrouter \| gateway]` | same as login: enter a credential, or see which rungs are lit | session |
158
246
  | `commands [verb]` | this directory, or one command in full | shell + session |
159
247
  | `models` | which model providers this machine can actually use | shell + session |
160
248
  | `model [<provider[:name]>]` | pin the model for this session, or show the pin | session |
@@ -181,9 +269,10 @@ distinction is the whole of the data boundary below.
181
269
  | Command | Does | Where |
182
270
  |---|---|---|
183
271
  | `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 |
272
+ | `load <file \| module \| universe>` | a CSV, a project module, or a portal universe | session |
273
+ | `universe <name>` | same as load: a universe registered in the portal | session |
274
+ | `data <file>` | same as load: a local CSV or parquet | session |
275
+ | `project <module>` | same as load: a module with data and backtest_fn | session |
187
276
 
188
277
  ### Session
189
278
 
@@ -191,7 +280,7 @@ distinction is the whole of the data boundary below.
191
280
  |---|---|---|
192
281
  | `logout` | remove stored credentials from this machine | shell + session |
193
282
  | `version` | print the version | shell |
194
- | `help` | the short list | session |
283
+ | `help` | the short list: demo, login, load, then a question | session |
195
284
  | `quit` | leave the session | session |
196
285
 
197
286
  ### Data flags
@@ -237,6 +326,7 @@ alphaengine gaps
237
326
  alphaengine tonight
238
327
  alphaengine tonight --budget 5
239
328
  alphaengine workflows
329
+ alphaengine login
240
330
  alphaengine commands
241
331
  alphaengine run screen_universe --universe sp500
242
332
  alphaengine run size_position --data returns.csv
@@ -329,7 +419,12 @@ diffable, and versioned so it still parses in two years.
329
419
 
330
420
  | Module | Contents |
331
421
  |---|---|
332
- | `alphaengine.core` | deflated Sharpe, PSR, PBO via CSCV, CPCV, minimum track record length, performance and risk statistics |
422
+ | `alphaengine.core` | deflated Sharpe, PSR, PBO via CSCV, CPCV, minimum track record length, performance and risk |
423
+ | `alphaengine.core.panel` | cross-sectional rank, z-score, winsorize, neutralize |
424
+ | `alphaengine.core.signals` | IC, ICIR, quantile returns, decay |
425
+ | `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 |
333
428
  | `alphaengine.sweep` | the grid runner and the sensitivity surface |
334
429
  | `alphaengine.study` | the study artifact and its schema |
335
430
  | `alphaengine.client` | the workflow client and the step executor |
@@ -401,12 +496,28 @@ Probability of Backtest Overfitting." *Journal of Computational Finance* 20(4),
401
496
  López de Prado, M. (2018). *Advances in Financial Machine Learning.* Wiley,
402
497
  chapters 7 and 12.
403
498
 
499
+ **Hierarchical Risk Parity**
500
+ López de Prado, M. (2016). "Building Diversified Portfolios that Outperform
501
+ Out of Sample." *Journal of Portfolio Management* 42(4), 59 to 69.
502
+
503
+ **Covariance shrinkage and spectral denoising**
504
+ Ledoit, O., and Wolf, M. (2004). "A Well-Conditioned Estimator for
505
+ Large-Dimensional Covariance Matrices." *Journal of Multivariate Analysis*
506
+ 88(2), 365 to 411.
507
+ Laloux, L., Cizeau, P., Bouchaud, J.-P., and Potters, M. (1999). "Noise
508
+ Dressing of Financial Correlation Matrices." *Physical Review Letters* 83(7),
509
+ 1467 to 1470.
510
+
404
511
  **Multiple testing in asset pricing**
405
512
  Harvey, C. R., Liu, Y., and Zhu, H. (2016). "... and the Cross-Section of
406
513
  Expected Returns." *Review of Financial Studies* 29(1), 5 to 68.
407
514
  Harvey, C. R., and Liu, Y. (2015). "Backtesting." *Journal of Portfolio
408
515
  Management* 42(1), 13 to 28.
409
516
 
517
+ **Fama-MacBeth**
518
+ Fama, E. F., and MacBeth, J. D. (1973). "Risk, Return, and Equilibrium:
519
+ Empirical Tests." *Journal of Political Economy* 81(3), 607 to 636.
520
+
410
521
  **Downside deviation**
411
522
  Sortino, F. A., and Price, L. N. (1994). "Performance Measurement in a Downside
412
523
  Risk Framework." *Journal of Investing* 3(3), 59 to 64.
@@ -1,14 +1,47 @@
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>
20
+
21
+ <p align="center">
22
+ <img src="docs/assets/mark.png" alt="AlphaEngine mark" width="96">
23
+ </p>
6
24
 
7
25
  ```bash
8
26
  pip install alphaengine
9
27
  alphaengine demo # the whole offline half, no account, no data of your own
10
28
  ```
11
29
 
30
+ <p align="center">
31
+ <img src="docs/assets/session.png" alt="The session canvas: a living parameter surface, then demo, login, load" width="92%">
32
+ </p>
33
+
34
+ The session is the product. Sign in, load something, then ask:
35
+
36
+ ```bash
37
+ alphaengine
38
+ ❯ login
39
+ ❯ load prices.csv
40
+ ❯ screen
41
+ ```
42
+
43
+ ---
44
+
12
45
  ## What it answers
13
46
 
14
47
  Eight questions, in the order a research week actually asks them. The command
@@ -42,7 +75,7 @@ Or say it in plain English and let your own model pick:
42
75
 
43
76
  ```bash
44
77
  alphaengine
45
- > which of my names are overbought on RSI?
78
+ ❯ which of my names are overbought on RSI?
46
79
  ```
47
80
 
48
81
  That second path is EXPLORATORY: the model chooses a workflow and then chooses
@@ -50,27 +83,48 @@ each step from what the server permits. Two runs of the same question may
50
83
  differ, and the run says so. `run <workflow>` is SCRIPTED and reproducible.
51
84
  Both are legitimate; presenting one as the other is not.
52
85
 
86
+ ---
87
+
53
88
  ## The three rungs
54
89
 
55
- Each is useful without the one above it. The boot screen shows which are lit.
90
+ Each is useful without the one above it. `login` lights the next one.
56
91
 
57
92
  | Rung | What you need | What you get |
58
93
  |---|---|---|
59
94
  | **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. |
95
+ | **Workflows** | a QuantOS `ae_live_` key (`login`) | The loop end to end, with the record. |
96
+ | **Ask anything** | your OWN model key (`login anthropic`) | Plain English in. Runs under your account, not ours. |
62
97
 
63
98
  Nothing here stores a model key: it is read from your environment at call time
64
99
  and handed to the provider's own client. There is no field to put one in.
65
100
 
101
+ ```mermaid
102
+ flowchart LR
103
+ A["demo / import<br/>offline maths"] --> B["login<br/>QuantOS key"]
104
+ B --> C["login anthropic<br/>your model"]
105
+ A -.->|"no account"| D["DSR · PBO · ICIR · HRP"]
106
+ B -.->|"ae_live_"| E["screen · validate · runs"]
107
+ C -.->|"BYOK"| F["plain English in"]
108
+ ```
109
+
110
+ ---
111
+
66
112
  ## Getting your data in
67
113
 
68
- Three doors, and nothing is ever fetched on your behalf.
114
+ One verb, three shapes. Nothing is ever fetched on your behalf.
115
+
116
+ ```bash
117
+ load prices.csv # a local CSV
118
+ load sp500 # registered in the portal, with the closes you stored
119
+ load research.momentum # a module of yours (the only door that can carry a simulator)
120
+ ```
121
+
122
+ From a shell the same doors are flags, for scripts:
69
123
 
70
124
  ```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
125
+ alphaengine screen --data prices.csv
126
+ alphaengine screen --universe sp500
127
+ alphaengine validate --project research.momentum
74
128
  ```
75
129
 
76
130
  `--data` reads three shapes, decided by the header and nothing else:
@@ -94,6 +148,39 @@ for the scores it measures — while the rest run on prices alone.
94
148
  upload decrypted back to your own account, not us fetching market data, and the
95
149
  distinction is the whole of the data boundary below.
96
150
 
151
+ <p align="center">
152
+ <img src="docs/assets/data_boundary.png" alt="Your machine holds prices and notebooks; only figures cross to the QuantOS record" width="92%">
153
+ </p>
154
+
155
+ ---
156
+
157
+ ## What's new in 0.7.0
158
+
159
+ The daily modelling morning, and the overnight book, without a third
160
+ dependency. Existing goldens (deflated Sharpe, PBO, performance, screen) are
161
+ byte-identical. New figures are a public contract from this release.
162
+
163
+ | You have | You get | Module |
164
+ |---|---|---|
165
+ | A raw factor panel | Cross-sectional rank, z-score, winsorize, neutralize | `core.panel` |
166
+ | A signal and prices | ICIR, Newey-West t-stat, Fama-MacBeth λ, quantile book with one-way turnover | `core.signals`, `core.cross_section` |
167
+ | A return panel | EWMA / Ledoit-Wolf / Marchenko-Pastur covariance, HRP, risk parity, vol target | `core.covariance`, `core.allocate` |
168
+
169
+ The session is slimmer too: `login` lights a rung, `load` is the one data verb,
170
+ and boot paints the parameter surface this tool actually judges rather than a
171
+ command encyclopedia.
172
+
173
+ ```python
174
+ from alphaengine.core import cs_zscore, signal_icir, hrp_weights, fama_macbeth
175
+
176
+ z = cs_zscore(factor_panel) # skipped names are counted, not dropped
177
+ ic = signal_icir(signal, prices) # Spearman ICIR; Pearson is opt-in
178
+ fm = fama_macbeth(signal, prices) # λ_mean, t-stat, Newey-West
179
+ w = hrp_weights(cov, names=names) # no matrix inverse; weights sum to one
180
+ ```
181
+
182
+ ---
183
+
97
184
  ## Command reference
98
185
 
99
186
  `alphaengine commands` prints this directory in the terminal, and
@@ -112,7 +199,8 @@ distinction is the whole of the data boundary below.
112
199
  | `gaps` | what your record says is UNANSWERED, and what closes each one | shell + session |
113
200
  | `tonight [--budget N]` | what would run unattended tonight, without running any of it | shell + session |
114
201
  | `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 |
202
+ | `login [quantos \| anthropic \| openai \| gemini \| groq \| azure \| openrouter \| gateway]` | sign in, or login anthropic for a model key | shell + session |
203
+ | `key [quantos \| anthropic \| openai \| gemini \| groq \| azure \| openrouter \| gateway]` | same as login: enter a credential, or see which rungs are lit | session |
116
204
  | `commands [verb]` | this directory, or one command in full | shell + session |
117
205
  | `models` | which model providers this machine can actually use | shell + session |
118
206
  | `model [<provider[:name]>]` | pin the model for this session, or show the pin | session |
@@ -139,9 +227,10 @@ distinction is the whole of the data boundary below.
139
227
  | Command | Does | Where |
140
228
  |---|---|---|
141
229
  | `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 |
230
+ | `load <file \| module \| universe>` | a CSV, a project module, or a portal universe | session |
231
+ | `universe <name>` | same as load: a universe registered in the portal | session |
232
+ | `data <file>` | same as load: a local CSV or parquet | session |
233
+ | `project <module>` | same as load: a module with data and backtest_fn | session |
145
234
 
146
235
  ### Session
147
236
 
@@ -149,7 +238,7 @@ distinction is the whole of the data boundary below.
149
238
  |---|---|---|
150
239
  | `logout` | remove stored credentials from this machine | shell + session |
151
240
  | `version` | print the version | shell |
152
- | `help` | the short list | session |
241
+ | `help` | the short list: demo, login, load, then a question | session |
153
242
  | `quit` | leave the session | session |
154
243
 
155
244
  ### Data flags
@@ -195,6 +284,7 @@ alphaengine gaps
195
284
  alphaengine tonight
196
285
  alphaengine tonight --budget 5
197
286
  alphaengine workflows
287
+ alphaengine login
198
288
  alphaengine commands
199
289
  alphaengine run screen_universe --universe sp500
200
290
  alphaengine run size_position --data returns.csv
@@ -287,7 +377,12 @@ diffable, and versioned so it still parses in two years.
287
377
 
288
378
  | Module | Contents |
289
379
  |---|---|
290
- | `alphaengine.core` | deflated Sharpe, PSR, PBO via CSCV, CPCV, minimum track record length, performance and risk statistics |
380
+ | `alphaengine.core` | deflated Sharpe, PSR, PBO via CSCV, CPCV, minimum track record length, performance and risk |
381
+ | `alphaengine.core.panel` | cross-sectional rank, z-score, winsorize, neutralize |
382
+ | `alphaengine.core.signals` | IC, ICIR, quantile returns, decay |
383
+ | `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 |
291
386
  | `alphaengine.sweep` | the grid runner and the sensitivity surface |
292
387
  | `alphaengine.study` | the study artifact and its schema |
293
388
  | `alphaengine.client` | the workflow client and the step executor |
@@ -359,12 +454,28 @@ Probability of Backtest Overfitting." *Journal of Computational Finance* 20(4),
359
454
  López de Prado, M. (2018). *Advances in Financial Machine Learning.* Wiley,
360
455
  chapters 7 and 12.
361
456
 
457
+ **Hierarchical Risk Parity**
458
+ López de Prado, M. (2016). "Building Diversified Portfolios that Outperform
459
+ Out of Sample." *Journal of Portfolio Management* 42(4), 59 to 69.
460
+
461
+ **Covariance shrinkage and spectral denoising**
462
+ Ledoit, O., and Wolf, M. (2004). "A Well-Conditioned Estimator for
463
+ Large-Dimensional Covariance Matrices." *Journal of Multivariate Analysis*
464
+ 88(2), 365 to 411.
465
+ Laloux, L., Cizeau, P., Bouchaud, J.-P., and Potters, M. (1999). "Noise
466
+ Dressing of Financial Correlation Matrices." *Physical Review Letters* 83(7),
467
+ 1467 to 1470.
468
+
362
469
  **Multiple testing in asset pricing**
363
470
  Harvey, C. R., Liu, Y., and Zhu, H. (2016). "... and the Cross-Section of
364
471
  Expected Returns." *Review of Financial Studies* 29(1), 5 to 68.
365
472
  Harvey, C. R., and Liu, Y. (2015). "Backtesting." *Journal of Portfolio
366
473
  Management* 42(1), 13 to 28.
367
474
 
475
+ **Fama-MacBeth**
476
+ Fama, E. F., and MacBeth, J. D. (1973). "Risk, Return, and Equilibrium:
477
+ Empirical Tests." *Journal of Political Economy* 81(3), 607 to 636.
478
+
368
479
  **Downside deviation**
369
480
  Sortino, F. A., and Price, L. N. (1994). "Performance Measurement in a Downside
370
481
  Risk Framework." *Journal of Investing* 3(3), 59 to 64.
Binary file
Binary file
@@ -56,4 +56,19 @@ is what a changed figure costs. The API may still move underneath it.
56
56
  # A new published wheel is a new thing people `pip install`. While the leading
57
57
  # digit is 0 the MINOR position carries that, the same way 0.5.0 carried a
58
58
  # surface change that left every figure byte-identical.
59
- __version__ = "0.6.0"
59
+ #
60
+ # 0.6.1 IS THE SCREEN, NOT THE MATHS. No computed value moved. The session is a
61
+ # transcript now: a hue-cycling wait-star over a travelling plateau, cards for
62
+ # what a step found, a composer instead of a dashboard. Same rungs, same
63
+ # doors, same refusals. The published artefact is a new wheel because 0.6.0
64
+ # already left the building.
65
+ #
66
+ # 0.7.0 IS NEW PUBLIC FIGURES, AND A SIMPLER OS AROUND THEM. Existing DSR /
67
+ # PBO / performance / screen goldens stay byte-identical. The artefact grew
68
+ # the daily cross-section (rank, z-score, winsorize, neutralize, ICIR,
69
+ # Fama-MacBeth, quantile book with turnover) and the overnight book
70
+ # (EWMA / Ledoit-Wolf / Marchenko-Pastur covariance, HRP, risk parity, vol
71
+ # target), plus a living parameter-surface canvas and one-verb `login` /
72
+ # `load`. New numbers are a public contract from this release; old numbers
73
+ # did not move.
74
+ __version__ = "0.7.0"