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.
- {alphaengine-0.6.0 → alphaengine-0.7.0}/AGENTS.md +21 -7
- {alphaengine-0.6.0 → alphaengine-0.7.0}/PKG-INFO +130 -19
- {alphaengine-0.6.0 → alphaengine-0.7.0}/README.md +130 -19
- alphaengine-0.7.0/docs/assets/banner.png +0 -0
- alphaengine-0.7.0/docs/assets/data_boundary.png +0 -0
- alphaengine-0.7.0/docs/assets/mark.png +0 -0
- alphaengine-0.7.0/docs/assets/session.png +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/_version.py +16 -1
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/cli.py +390 -185
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/client/executor.py +178 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/commands.py +42 -11
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/core/__init__.py +21 -1
- alphaengine-0.7.0/src/alphaengine/core/allocate.py +221 -0
- alphaengine-0.7.0/src/alphaengine/core/covariance.py +167 -0
- alphaengine-0.7.0/src/alphaengine/core/cross_section.py +176 -0
- alphaengine-0.7.0/src/alphaengine/core/panel.py +289 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/core/signals.py +85 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/demo.py +7 -2
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/repl.py +5 -1
- {alphaengine-0.6.0 → alphaengine-0.7.0}/tests/test_cli.py +60 -6
- {alphaengine-0.6.0 → alphaengine-0.7.0}/tests/test_commands.py +6 -4
- alphaengine-0.7.0/tests/test_quant_maths.py +286 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/.github/workflows/ci.yml +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/.github/workflows/publish.yml +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/.gitignore +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/LICENSE +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/SECURITY.md +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/pyproject.toml +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/scripts/gen_docs.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/__init__.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/__main__.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/agent/__init__.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/agent/answer.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/agent/driver.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/auth.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/book.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/client/__init__.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/client/agent.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/client/session.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/complete.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/connectors/__init__.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/core/backtest.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/core/factors.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/core/pairs.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/core/performance.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/core/profile.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/core/risk.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/core/screen.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/core/series_shapes.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/core/stress.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/core/technical.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/core/validation.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/core/walkforward.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/demo_book.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/demo_returns.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/demo_signal.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/demo_universe.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/events.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/loaders.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/model.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/py.typed +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/study/__init__.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/study/report.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/study/schema.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/sweep/__init__.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/src/alphaengine/sweep/runner.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/tests/test_agent.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/tests/test_answer.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/tests/test_book.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/tests/test_client.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/tests/test_events.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/tests/test_executor_ops.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/tests/test_goldens.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/tests/test_loaders.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/tests/test_model.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/tests/test_screen.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/tests/test_signals.py +0 -0
- {alphaengine-0.6.0 → alphaengine-0.7.0}/tests/test_smoke.py +0 -0
- {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
|
|
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.
|
|
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
|
-
`
|
|
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
|
-
- **
|
|
49
|
-
`
|
|
50
|
-
|
|
51
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
|
114
|
-
alphaengine
|
|
115
|
-
alphaengine
|
|
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
|
-
| `
|
|
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
|
-
| `
|
|
185
|
-
| `
|
|
186
|
-
| `
|
|
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
|
|
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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
|
72
|
-
alphaengine
|
|
73
|
-
alphaengine
|
|
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
|
-
| `
|
|
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
|
-
| `
|
|
143
|
-
| `
|
|
144
|
-
| `
|
|
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
|
|
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
|
|
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
|
-
|
|
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"
|