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.
Files changed (93) hide show
  1. {alphaengine-0.8.0 → alphaengine-0.9.0}/PKG-INFO +47 -11
  2. {alphaengine-0.8.0 → alphaengine-0.9.0}/README.md +43 -10
  3. {alphaengine-0.8.0 → alphaengine-0.9.0}/pyproject.toml +11 -5
  4. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/__init__.py +4 -2
  5. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/_version.py +8 -1
  6. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/cli.py +55 -353
  7. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/client/executor.py +14 -6
  8. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/client/session.py +40 -0
  9. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/backtest.py +32 -1
  10. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/factors.py +15 -1
  11. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/pairs.py +9 -0
  12. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/performance.py +38 -0
  13. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/risk.py +24 -0
  14. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/screen.py +8 -0
  15. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/signals.py +28 -3
  16. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/stress.py +39 -5
  17. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/technical.py +36 -0
  18. alphaengine-0.9.0/src/alphaengine/core/trace.py +136 -0
  19. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/validation.py +56 -3
  20. alphaengine-0.9.0/src/alphaengine/tui/__init__.py +1 -0
  21. alphaengine-0.9.0/src/alphaengine/tui/app.py +379 -0
  22. alphaengine-0.9.0/src/alphaengine/tui/dispatch.py +369 -0
  23. {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_client.py +73 -1
  24. alphaengine-0.9.0/tests/test_math_audit.py +253 -0
  25. alphaengine-0.9.0/tests/test_trace.py +45 -0
  26. alphaengine-0.9.0/tests/test_tui.py +127 -0
  27. {alphaengine-0.8.0 → alphaengine-0.9.0}/.github/workflows/ci.yml +0 -0
  28. {alphaengine-0.8.0 → alphaengine-0.9.0}/.github/workflows/publish.yml +0 -0
  29. {alphaengine-0.8.0 → alphaengine-0.9.0}/.gitignore +0 -0
  30. {alphaengine-0.8.0 → alphaengine-0.9.0}/AGENTS.md +0 -0
  31. {alphaengine-0.8.0 → alphaengine-0.9.0}/LICENSE +0 -0
  32. {alphaengine-0.8.0 → alphaengine-0.9.0}/SECURITY.md +0 -0
  33. {alphaengine-0.8.0 → alphaengine-0.9.0}/docs/assets/banner.png +0 -0
  34. {alphaengine-0.8.0 → alphaengine-0.9.0}/docs/assets/data_boundary.png +0 -0
  35. {alphaengine-0.8.0 → alphaengine-0.9.0}/docs/assets/session.png +0 -0
  36. {alphaengine-0.8.0 → alphaengine-0.9.0}/docs/figure_contract.md +0 -0
  37. {alphaengine-0.8.0 → alphaengine-0.9.0}/docs/workflows/evaluate_process.json +0 -0
  38. {alphaengine-0.8.0 → alphaengine-0.9.0}/docs/workflows/research_week.json +0 -0
  39. {alphaengine-0.8.0 → alphaengine-0.9.0}/docs/workflows/stress_study.json +0 -0
  40. {alphaengine-0.8.0 → alphaengine-0.9.0}/scripts/gen_docs.py +0 -0
  41. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/__main__.py +0 -0
  42. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/agent/__init__.py +0 -0
  43. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/agent/answer.py +0 -0
  44. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/agent/driver.py +0 -0
  45. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/auth.py +0 -0
  46. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/book.py +0 -0
  47. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/charts.py +0 -0
  48. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/client/__init__.py +0 -0
  49. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/client/agent.py +0 -0
  50. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/commands.py +0 -0
  51. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/complete.py +0 -0
  52. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/connectors/__init__.py +0 -0
  53. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/__init__.py +0 -0
  54. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/active.py +0 -0
  55. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/allocate.py +0 -0
  56. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/covariance.py +0 -0
  57. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/cross_section.py +0 -0
  58. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/panel.py +0 -0
  59. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/process.py +0 -0
  60. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/profile.py +0 -0
  61. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/series_shapes.py +0 -0
  62. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/core/walkforward.py +0 -0
  63. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/demo.py +0 -0
  64. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/demo_book.py +0 -0
  65. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/demo_returns.py +0 -0
  66. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/demo_signal.py +0 -0
  67. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/demo_universe.py +0 -0
  68. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/events.py +0 -0
  69. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/loaders.py +0 -0
  70. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/model.py +0 -0
  71. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/py.typed +0 -0
  72. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/repl.py +0 -0
  73. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/study/__init__.py +0 -0
  74. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/study/report.py +0 -0
  75. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/study/schema.py +0 -0
  76. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/sweep/__init__.py +0 -0
  77. {alphaengine-0.8.0 → alphaengine-0.9.0}/src/alphaengine/sweep/runner.py +0 -0
  78. {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_agent.py +0 -0
  79. {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_answer.py +0 -0
  80. {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_book.py +0 -0
  81. {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_cli.py +0 -0
  82. {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_commands.py +0 -0
  83. {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_events.py +0 -0
  84. {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_executor_ops.py +0 -0
  85. {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_goldens.py +0 -0
  86. {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_loaders.py +0 -0
  87. {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_model.py +0 -0
  88. {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_process.py +0 -0
  89. {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_quant_maths.py +0 -0
  90. {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_screen.py +0 -0
  91. {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_signals.py +0 -0
  92. {alphaengine-0.8.0 → alphaengine-0.9.0}/tests/test_smoke.py +0 -0
  93. {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.8.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 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
+ 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
- <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>
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
- The session is the product. Sign in, load something, then ask:
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
- ❯ login
78
- ❯ load prices.csv
79
- ❯ screen
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 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
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
- <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>
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
- The session is the product. Sign in, load something, then ask:
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
- ❯ login
36
- ❯ load prices.csv
37
- ❯ screen
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. Deliberately adds nothing new: argparse from the
46
- # standard library, and the client's urllib transport. A CLI that dragged in a
47
- # TUI framework would break the two-dependency promise above on behalf of people
48
- # who may never run it.
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
- and your data never leaves the machine.
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
- __version__ = "0.8.0"
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"