alphaengine 0.8.0__tar.gz → 0.9.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.8.0 → alphaengine-0.9.0}/PKG-INFO +47 -11
- {alphaengine-0.8.0 → alphaengine-0.9.0}/README.md +43 -10
- {alphaengine-0.8.0 → alphaengine-0.9.0}/pyproject.toml +11 -5
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/__init__.py +4 -2
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/_version.py +8 -1
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/cli.py +55 -353
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/client/executor.py +14 -6
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/client/session.py +40 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/backtest.py +32 -1
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/factors.py +15 -1
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/pairs.py +9 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/performance.py +38 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/risk.py +24 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/screen.py +8 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/signals.py +28 -3
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/stress.py +39 -5
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/technical.py +36 -0
- alphaengine-0.9.0/src/alphaengine/core/trace.py +136 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/validation.py +56 -3
- alphaengine-0.9.0/src/alphaengine/tui/__init__.py +1 -0
- alphaengine-0.9.0/src/alphaengine/tui/app.py +379 -0
- alphaengine-0.9.0/src/alphaengine/tui/dispatch.py +369 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_client.py +73 -1
- alphaengine-0.9.0/tests/test_math_audit.py +253 -0
- alphaengine-0.9.0/tests/test_trace.py +45 -0
- alphaengine-0.9.0/tests/test_tui.py +127 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/.github/workflows/ci.yml +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/.github/workflows/publish.yml +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/.gitignore +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/AGENTS.md +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/LICENSE +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/SECURITY.md +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/docs/assets/banner.png +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/docs/assets/data_boundary.png +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/docs/assets/session.png +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/docs/figure_contract.md +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/docs/workflows/evaluate_process.json +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/docs/workflows/research_week.json +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/docs/workflows/stress_study.json +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/scripts/gen_docs.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/__main__.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/agent/__init__.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/agent/answer.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/agent/driver.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/auth.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/book.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/charts.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/client/__init__.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/client/agent.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/commands.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/complete.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/connectors/__init__.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/__init__.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/active.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/allocate.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/covariance.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/cross_section.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/panel.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/process.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/profile.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/series_shapes.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/walkforward.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/demo.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/demo_book.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/demo_returns.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/demo_signal.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/demo_universe.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/events.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/loaders.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/model.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/py.typed +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/repl.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/study/__init__.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/study/report.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/study/schema.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/sweep/__init__.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/sweep/runner.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_agent.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_answer.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_book.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_cli.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_commands.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_events.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_executor_ops.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_goldens.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_loaders.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_model.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_process.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_quant_maths.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_screen.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_signals.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_smoke.py +0 -0
- {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_sweep.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: alphaengine
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.9.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
|
|
@@ -36,8 +36,11 @@ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
|
36
36
|
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
37
37
|
Requires-Dist: ruff==0.16.1; extra == 'dev'
|
|
38
38
|
Requires-Dist: statsmodels>=0.14; extra == 'dev'
|
|
39
|
+
Requires-Dist: textual>=1.0; extra == 'dev'
|
|
39
40
|
Provides-Extra: factors
|
|
40
41
|
Requires-Dist: statsmodels>=0.14; extra == 'factors'
|
|
42
|
+
Provides-Extra: tui
|
|
43
|
+
Requires-Dist: textual>=1.0; extra == 'tui'
|
|
41
44
|
Description-Content-Type: text/markdown
|
|
42
45
|
|
|
43
46
|
<p align="center">
|
|
@@ -61,24 +64,46 @@ Description-Content-Type: text/markdown
|
|
|
61
64
|
</p>
|
|
62
65
|
|
|
63
66
|
```bash
|
|
64
|
-
pip install alphaengine
|
|
65
|
-
alphaengine
|
|
66
|
-
alphaengine
|
|
67
|
+
pip install alphaengine # library and one-shot commands
|
|
68
|
+
pip install "alphaengine[tui]" # the full-screen session
|
|
69
|
+
alphaengine demo # offline. no account, no data of yours
|
|
70
|
+
alphaengine # the session
|
|
71
|
+
alphaengine process # fit a DGP to the demo walk and stress it
|
|
67
72
|
```
|
|
68
73
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
74
|
+
If the shell cannot find `alphaengine`, this always works:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
python -m alphaengine demo
|
|
78
|
+
python -m alphaengine
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
┌──────────┬─────────────────────────────────────┬──────────────────┐
|
|
83
|
+
│ ● maths │ Ask in plain English. │ sharpe │
|
|
84
|
+
│ always │ │ mean / std √252 │
|
|
85
|
+
│ ○ flows │ > which names are overbought? │ ▁▂▃▅▇█▇▅▃ │
|
|
86
|
+
│ ○ ask │ │ 0 0.0012 │
|
|
87
|
+
│ │ chose screen_universe │ 1 -0.0040 │
|
|
88
|
+
│ loaded │ │ │
|
|
89
|
+
│ sp500 │ │ │
|
|
90
|
+
└──────────┴─────────────────────────────────────┴──────────────────┘
|
|
91
|
+
```
|
|
72
92
|
|
|
73
|
-
|
|
93
|
+
There is one session, and it is this screen. A sentence picks a workflow.
|
|
94
|
+
`run <name>` follows that workflow exactly. The math pane opens when a run
|
|
95
|
+
has a statistic to show.
|
|
74
96
|
|
|
75
97
|
```bash
|
|
76
98
|
alphaengine
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
99
|
+
> login
|
|
100
|
+
> load prices.csv
|
|
101
|
+
> screen
|
|
80
102
|
```
|
|
81
103
|
|
|
104
|
+
Prices stay on this machine. A math line's series can travel on its own trace
|
|
105
|
+
so it can be charted. The figures posted with the step stay summaries.
|
|
106
|
+
|
|
82
107
|
---
|
|
83
108
|
|
|
84
109
|
## What it answers
|
|
@@ -193,6 +218,17 @@ distinction is the whole of the data boundary below.
|
|
|
193
218
|
|
|
194
219
|
---
|
|
195
220
|
|
|
221
|
+
## What's new in 0.9.0
|
|
222
|
+
|
|
223
|
+
`next_open` fills wait for a prior close. The first bar of a next-open backtest
|
|
224
|
+
no longer trades that bar's own signal at that bar's open. Close fills are
|
|
225
|
+
unchanged, and the published goldens do not move.
|
|
226
|
+
|
|
227
|
+
The session is the full-screen terminal (`pip install "alphaengine[tui]"`).
|
|
228
|
+
Each statistic keeps its formula, inputs, and series. Those series post to
|
|
229
|
+
`/api/harness/runs/{id}/traces`. A portal that rejects the trace does not fail
|
|
230
|
+
the run.
|
|
231
|
+
|
|
196
232
|
## What's new in 0.8.0
|
|
197
233
|
|
|
198
234
|
Named processes, Grinold, and a frozen chart contract. Existing goldens
|
|
@@ -19,24 +19,46 @@
|
|
|
19
19
|
</p>
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
|
-
pip install alphaengine
|
|
23
|
-
alphaengine
|
|
24
|
-
alphaengine
|
|
22
|
+
pip install alphaengine # library and one-shot commands
|
|
23
|
+
pip install "alphaengine[tui]" # the full-screen session
|
|
24
|
+
alphaengine demo # offline. no account, no data of yours
|
|
25
|
+
alphaengine # the session
|
|
26
|
+
alphaengine process # fit a DGP to the demo walk and stress it
|
|
25
27
|
```
|
|
26
28
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
If the shell cannot find `alphaengine`, this always works:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
python -m alphaengine demo
|
|
33
|
+
python -m alphaengine
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
┌──────────┬─────────────────────────────────────┬──────────────────┐
|
|
38
|
+
│ ● maths │ Ask in plain English. │ sharpe │
|
|
39
|
+
│ always │ │ mean / std √252 │
|
|
40
|
+
│ ○ flows │ > which names are overbought? │ ▁▂▃▅▇█▇▅▃ │
|
|
41
|
+
│ ○ ask │ │ 0 0.0012 │
|
|
42
|
+
│ │ chose screen_universe │ 1 -0.0040 │
|
|
43
|
+
│ loaded │ │ │
|
|
44
|
+
│ sp500 │ │ │
|
|
45
|
+
└──────────┴─────────────────────────────────────┴──────────────────┘
|
|
46
|
+
```
|
|
30
47
|
|
|
31
|
-
|
|
48
|
+
There is one session, and it is this screen. A sentence picks a workflow.
|
|
49
|
+
`run <name>` follows that workflow exactly. The math pane opens when a run
|
|
50
|
+
has a statistic to show.
|
|
32
51
|
|
|
33
52
|
```bash
|
|
34
53
|
alphaengine
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
54
|
+
> login
|
|
55
|
+
> load prices.csv
|
|
56
|
+
> screen
|
|
38
57
|
```
|
|
39
58
|
|
|
59
|
+
Prices stay on this machine. A math line's series can travel on its own trace
|
|
60
|
+
so it can be charted. The figures posted with the step stay summaries.
|
|
61
|
+
|
|
40
62
|
---
|
|
41
63
|
|
|
42
64
|
## What it answers
|
|
@@ -151,6 +173,17 @@ distinction is the whole of the data boundary below.
|
|
|
151
173
|
|
|
152
174
|
---
|
|
153
175
|
|
|
176
|
+
## What's new in 0.9.0
|
|
177
|
+
|
|
178
|
+
`next_open` fills wait for a prior close. The first bar of a next-open backtest
|
|
179
|
+
no longer trades that bar's own signal at that bar's open. Close fills are
|
|
180
|
+
unchanged, and the published goldens do not move.
|
|
181
|
+
|
|
182
|
+
The session is the full-screen terminal (`pip install "alphaengine[tui]"`).
|
|
183
|
+
Each statistic keeps its formula, inputs, and series. Those series post to
|
|
184
|
+
`/api/harness/runs/{id}/traces`. A portal that rejects the trace does not fail
|
|
185
|
+
the run.
|
|
186
|
+
|
|
154
187
|
## What's new in 0.8.0
|
|
155
188
|
|
|
156
189
|
Named processes, Grinold, and a frozen chart contract. Existing goldens
|
|
@@ -42,10 +42,10 @@ dependencies = [
|
|
|
42
42
|
"scipy>=1.10",
|
|
43
43
|
]
|
|
44
44
|
|
|
45
|
-
# THE TERMINAL ENTRY POINT.
|
|
46
|
-
# standard library, and the client's urllib transport.
|
|
47
|
-
#
|
|
48
|
-
#
|
|
45
|
+
# THE TERMINAL ENTRY POINT. One-shot commands add nothing: argparse from the
|
|
46
|
+
# standard library, and the client's urllib transport. The full-screen session
|
|
47
|
+
# is the optional `tui` extra, so `import alphaengine` and a library install
|
|
48
|
+
# stay at numpy and scipy.
|
|
49
49
|
#
|
|
50
50
|
# INSTALL THIS IN YOUR PROJECT VENV, NOT WITH pipx OR `uv tool install`.
|
|
51
51
|
# `compute.*` ops execute in-process against your own DataFrames, so tool
|
|
@@ -75,6 +75,11 @@ connectors = [
|
|
|
75
75
|
"httpx>=0.27",
|
|
76
76
|
"pyarrow>=15.0",
|
|
77
77
|
]
|
|
78
|
+
# The interactive session. Not a core dependency: a researcher who only wants
|
|
79
|
+
# a deflated Sharpe should not install a TUI framework to get one.
|
|
80
|
+
tui = [
|
|
81
|
+
"textual>=1.0",
|
|
82
|
+
]
|
|
78
83
|
dev = [
|
|
79
84
|
"pytest>=8.0",
|
|
80
85
|
"pytest-cov>=5.0",
|
|
@@ -88,6 +93,7 @@ dev = [
|
|
|
88
93
|
# this, mypy cannot resolve statsmodels in a clean environment even though
|
|
89
94
|
# it resolves fine on a machine that happens to have it.
|
|
90
95
|
"statsmodels>=0.14",
|
|
96
|
+
"textual>=1.0",
|
|
91
97
|
]
|
|
92
98
|
|
|
93
99
|
[project.urls]
|
|
@@ -179,5 +185,5 @@ ignore_missing_imports = true
|
|
|
179
185
|
# import is an error, so this is the difference between a build that passes on a
|
|
180
186
|
# machine that happens to have them and one that passes anywhere.
|
|
181
187
|
[[tool.mypy.overrides]]
|
|
182
|
-
module = ["scipy.*", "statsmodels.*", "pyarrow.*", "httpx"]
|
|
188
|
+
module = ["scipy.*", "statsmodels.*", "pyarrow.*", "httpx", "textual.*"]
|
|
183
189
|
ignore_missing_imports = true
|
|
@@ -23,8 +23,10 @@ WHAT THIS LIBRARY IS NOT
|
|
|
23
23
|
|
|
24
24
|
OFFLINE BY CONSTRUCTION
|
|
25
25
|
Importing this module makes no network call and needs no account. numpy and
|
|
26
|
-
scipy, nothing else. Everything above runs on a laptop with the wifi off
|
|
27
|
-
|
|
26
|
+
scipy, nothing else. Everything above runs on a laptop with the wifi off.
|
|
27
|
+
A workflow run can also send a math trace — the formula, its inputs, and
|
|
28
|
+
the series that line was computed on — to the portal on its own channel.
|
|
29
|
+
Study ingest still refuses anything series-shaped.
|
|
28
30
|
"""
|
|
29
31
|
|
|
30
32
|
from typing import Any
|
|
@@ -69,4 +69,11 @@ is what a changed figure costs. The API may still move underneath it.
|
|
|
69
69
|
# Monte Carlo trial count, Grinold alpha / breadth / TC, a frozen chart
|
|
70
70
|
# vocabulary, and a terminal boot that is the README banner in glyphs.
|
|
71
71
|
# New figures are a public contract from this release; old numbers did not move.
|
|
72
|
-
|
|
72
|
+
#
|
|
73
|
+
# 0.9.0: `run_backtest(..., fill_timing="next_open")` no longer fills the first
|
|
74
|
+
# bar with that bar's own signal. A signal is known at the close, and the open
|
|
75
|
+
# of the same bar printed before it. The first fill is now the next bar's open.
|
|
76
|
+
# Close fills are unchanged. No golden in tests/test_goldens.py moves. The
|
|
77
|
+
# same release makes the full-screen terminal the only session, and posts each
|
|
78
|
+
# math line's series on `/traces` without putting those series inside figures.
|
|
79
|
+
__version__ = "0.9.0"
|