alphaengine 1.1.0__tar.gz → 1.1.1__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-1.1.0 → alphaengine-1.1.1}/.github/workflows/publish.yml +1 -1
- {alphaengine-1.1.0 → alphaengine-1.1.1}/CHANGELOG.md +18 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/PKG-INFO +61 -27
- {alphaengine-1.1.0 → alphaengine-1.1.1}/README.md +60 -26
- alphaengine-1.1.1/docs/free-vs-firm.md +88 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/docs/project-format.md +4 -2
- {alphaengine-1.1.0 → alphaengine-1.1.1}/pyproject.toml +1 -4
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/__init__.py +20 -3
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/_version.py +4 -2
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/agent/sim.py +7 -4
- alphaengine-1.1.1/src/alphaengine/auth.py +294 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/cli.py +91 -37
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/client/executor.py +1 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/commands.py +4 -11
- alphaengine-1.1.1/src/alphaengine/contracts/__init__.py +11 -0
- alphaengine-1.1.1/src/alphaengine/contracts/hash_golden.json +113 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/core/__init__.py +1 -1
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/core/pairs.py +1 -1
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/envelope.py +5 -2
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/ideas.py +3 -7
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/io.py +2 -1
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/ledger.py +84 -10
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/memo.py +12 -3
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/pipeline.py +6 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/project.py +26 -27
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/study/__init__.py +4 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/study/report.py +12 -52
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/study/schema.py +75 -10
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/sweep/runner.py +30 -36
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/sync.py +19 -14
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/tui/dispatch.py +2 -3
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/tui/stage.py +2 -1
- {alphaengine-1.1.0 → alphaengine-1.1.1}/tests/test_coverage_paths.py +1 -7
- {alphaengine-1.1.0 → alphaengine-1.1.1}/tests/test_goldens.py +16 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/tests/test_project.py +196 -21
- {alphaengine-1.1.0 → alphaengine-1.1.1}/tests/test_sim.py +2 -2
- alphaengine-1.1.1/tests/test_smoke.py +180 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/tests/test_sweep.py +8 -34
- alphaengine-1.1.0/src/alphaengine/auth.py +0 -203
- alphaengine-1.1.0/tests/test_smoke.py +0 -96
- {alphaengine-1.1.0 → alphaengine-1.1.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/.github/ISSUE_TEMPLATE/data_shape.md +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/.github/ISSUE_TEMPLATE/method_request.md +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/.github/dependabot.yml +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/.github/workflows/ci.yml +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/.github/workflows/codeql.yml +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/.gitignore +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/AGENTS.md +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/CODE_OF_CONDUCT.md +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/CONTRIBUTING.md +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/LICENSE +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/SECURITY.md +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/docs/assets/banner.png +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/docs/assets/data_boundary.png +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/docs/assets/session.png +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/docs/figure_contract.md +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/docs/plugins.md +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/docs/result-format.md +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/docs/workflows/evaluate_process.json +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/docs/workflows/research_week.json +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/docs/workflows/stress_study.json +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/examples/process_stress_monitor.yaml +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/examples/screen_validate_size.yaml +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/scripts/gen_docs.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/__main__.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/agent/__init__.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/agent/answer.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/agent/bakeoff.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/agent/brief.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/agent/chart.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/agent/driver.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/book.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/charts.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/client/__init__.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/client/agent.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/client/session.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/complete.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/connectors/__init__.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/context.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/core/active.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/core/allocate.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/core/backtest.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/core/bakeoff.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/core/covariance.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/core/cross_section.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/core/factors.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/core/market.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/core/options.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/core/panel.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/core/performance.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/core/portfolio.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/core/process.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/core/profile.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/core/rates.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/core/regime.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/core/relations.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/core/risk.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/core/screen.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/core/series_shapes.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/core/signals.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/core/stress.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/core/technical.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/core/trace.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/core/validation.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/core/walkforward.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/datasets.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/demo.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/demo_book.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/demo_returns.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/demo_signal.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/demo_universe.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/events.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/loaders.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/model.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/plugins.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/py.typed +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/repl.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/sweep/__init__.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/tui/__init__.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/tui/app.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/tui/mark.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/tui/typeface.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/src/alphaengine/watch.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/tests/test_agent.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/tests/test_answer.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/tests/test_bakeoff.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/tests/test_book.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/tests/test_cli.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/tests/test_client.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/tests/test_commands.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/tests/test_context.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/tests/test_events.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/tests/test_executor_ops.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/tests/test_io.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/tests/test_loaders.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/tests/test_math_audit.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/tests/test_model.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/tests/test_portfolio.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/tests/test_process.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/tests/test_quant_maths.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/tests/test_relations.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/tests/test_screen.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/tests/test_signals.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/tests/test_trace.py +0 -0
- {alphaengine-1.1.0 → alphaengine-1.1.1}/tests/test_tui.py +0 -0
|
@@ -35,7 +35,7 @@ jobs:
|
|
|
35
35
|
python-version: "3.12"
|
|
36
36
|
- name: Verify git tag matches __version__
|
|
37
37
|
run: |
|
|
38
|
-
python -c "import os,
|
|
38
|
+
python -c "import os, tomllib, sys; v = tomllib.load(open('pyproject.toml', 'rb'))['project']['version']; ref = os.environ.get('GITHUB_REF_NAME') or os.environ.get('GITHUB_REF', '').removeprefix('refs/tags/'); exp = f'v{v}'; sys.exit(f'Tag {ref!r} != {exp!r}' if ref != exp else 0)"
|
|
39
39
|
- run: python -m pip install --upgrade build
|
|
40
40
|
- run: python -m build
|
|
41
41
|
- uses: actions/upload-artifact@v4
|
|
@@ -6,6 +6,24 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
6
6
|
and this project adheres to Semantic Versioning (with computed golden values
|
|
7
7
|
treated as part of the public contract).
|
|
8
8
|
|
|
9
|
+
## [1.1.1] - 2026-10-24
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- **Single firm-key choke point (`alphaengine.auth.require_firm_key`):** Used by every gated command (`run`, `show`, `monitor`/`watch`, `validate`, `screen`, `diagnose`, `signal`, `stress`, `overlap`, `size`, `workflows`, `runs`, `gaps`, `tonight`, and the CLI OS: `init`, `log`, `diff`, `rerun`, `data`, `idea`, `seal`, `report`, `remote`, `push`, `pull`, `plugin`, `shell`). Free and keyless forever: `import alphaengine`, `alphaengine demo`, `alphaengine process`, and `ae verify`.
|
|
13
|
+
- **OS keychain support & key redaction:** `auth.py` stores keys in the OS keychain (`keyring`) when available with `~/.config/alphaengine/credentials.json` (`0600`) as fallback, and `redact_secrets()` strips `ae_live_*` tokens from CLI output, error messages, tracebacks, and `--json` envelopes.
|
|
14
|
+
- **Canonical SHA-256 contract & golden fixture (`alphaengine/contracts/hash_golden.json`):** Unified `content_sha256`, study seals, `.alphaengine/objects/` CAS blobs, dataset hashes, and parameter hashes on `canonical_sha256()` (Schema 1.2 sorted-key JSON, `.8f` float formatting, 64-hex SHA-256). Added `verify_study_mode()` so studies sealed under the pre-1.2 legacy format still verify and are labeled `"legacy"`.
|
|
15
|
+
- **Free vs. Firm documentation (`docs/free-vs-firm.md`):** Documents the offline open-source library boundary, firm `ae_live_` Connect keys, and what uses the network.
|
|
16
|
+
- **Socket-blocked offline smoke test:** Replaced the import-only check in `tests/test_smoke.py` with a socket-blocked test (`socket.socket` and `socket.create_connection` patched to raise) that imports `alphaengine` and executes `deflated_sharpe` (DSR), `pbo_cscv` (PBO via CSCV), `combinatorial_oos_stability`, `performance_report`, `compute_var_cvar`, `sweep`, `load_csv`, `from_quantconnect`, and `from_vectorbt`.
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
- **Cumulative project-wide trials & DSR everywhere:** Project-wide cumulative trial counts (`project_trials` across `.alphaengine/ledger/trials.jsonl`) now feed every DSR — run output, headline `deflated_sharpe` and `n_trials`, `ae push` payloads, and `ae seal` studies — with no per-run or per-family reset.
|
|
20
|
+
- **Identical re-run deduplication:** Re-running an identical configuration (`command`, `params_hash`, and `dataset_hashes` matching a prior run in `.alphaengine/ledger/runs.jsonl`) records `duplicate_of` and adds `0` new trials (`9 -> 9`), whereas distinct configurations always increment cumulative `N` (`9 -> 18`).
|
|
21
|
+
- **Removed bare `except Exception: pass` in `sweep/runner.py`:** `_maybe_record_project_sweep` now raises a descriptive `RuntimeError` when a discovered `.alphaengine/` project ledger cannot be written.
|
|
22
|
+
- **Metadata-driven `__version__` and naming cleanup:** `__version__` is loaded via `importlib.metadata.version("alphaengine")` with no hardcoded version strings; standardized `combinatorial_oos_stability` (with `cpcv_score` emitting `DeprecationWarning`) and `PBO via CSCV` across docs and top-level exports.
|
|
23
|
+
|
|
24
|
+
### Removed
|
|
25
|
+
- **Retail CLI path (`--retail` and `/api/retail/ledger/import`):** Removed `--retail` from `report` and CLI dispatch. Retail ledger import is performed via web upload in the quantOS portal.
|
|
26
|
+
|
|
9
27
|
## [1.1.0] - 2026-10-24
|
|
10
28
|
|
|
11
29
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: alphaengine
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.1
|
|
4
4
|
Summary: Validated research tooling for investment strategies: deflation, overfitting detection, and honest trial counts.
|
|
5
5
|
Project-URL: Homepage, https://qosai.app
|
|
6
6
|
Project-URL: Documentation, https://github.com/quantOSC/alphaengine#readme
|
|
@@ -170,16 +170,15 @@ Each is useful without the one above it. `login` lights the next one.
|
|
|
170
170
|
|
|
171
171
|
| Rung | What you need | What you get |
|
|
172
172
|
|---|---|---|
|
|
173
|
-
| **The maths** | nothing | `alphaengine demo`, `alphaengine process`, and the full Python API (`import alphaengine`, `sweep`, `core`), offline, forever. No account. |
|
|
174
|
-
| **
|
|
173
|
+
| **The maths** | nothing | `alphaengine demo`, `alphaengine process`, `ae verify`, and the full Python API (`import alphaengine`, `sweep`, `core`), offline, forever. No account. |
|
|
174
|
+
| **Firm workflows & CLI OS** | a firm `ae_live_` key from **Connect** in your firm's quantOS portal (`login` or `QUANTOS_API_KEY`; see [docs/free-vs-firm.md](docs/free-vs-firm.md)) | The eight workflow commands (`diagnose`, `screen`, `signal`, `validate`, `stress`, `overlap`, `size`, `monitor`), `workflows`, `runs`, `gaps`, `tonight`, `run <workflow>`, and the Research OS (`init`, `log`, `show`, `diff`, `rerun`, `watch`, `data`, `idea`, `seal`, `report`, `remote`, `push`, `pull`, `plugin`, `shell`). |
|
|
175
175
|
| **Ask anything** | your OWN model key (`login anthropic`) | Plain English in. Runs under your account, not ours. |
|
|
176
176
|
|
|
177
|
-
The
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
work completely offline without an account or key.
|
|
177
|
+
The workflow commands and Research OS require a firm `ae_live_` key issued through
|
|
178
|
+
**Connect** in your firm's quantOS portal (see [docs/free-vs-firm.md](docs/free-vs-firm.md)).
|
|
179
|
+
There is no retail CLI key. `alphaengine demo`, `alphaengine process`, `ae verify`,
|
|
180
|
+
and the Python library (`import alphaengine`) work completely offline without an
|
|
181
|
+
account or key.
|
|
183
182
|
|
|
184
183
|
**How credentials are handled.** QuantOS never receives your LLM provider key:
|
|
185
184
|
it goes directly from this process to your chosen provider. By default, keys can
|
|
@@ -197,7 +196,7 @@ at `login`). To delete the stored file at any time, run
|
|
|
197
196
|
flowchart LR
|
|
198
197
|
A["demo / import<br/>offline maths"] --> B["login<br/>QuantOS key"]
|
|
199
198
|
B --> C["login anthropic<br/>your model"]
|
|
200
|
-
A -.->|"no account"| D["DSR · PBO · ICIR · HRP"]
|
|
199
|
+
A -.->|"no account"| D["DSR · PBO (CSCV) · ICIR · HRP"]
|
|
201
200
|
B -.->|"ae_live_"| E["screen · validate · runs"]
|
|
202
201
|
C -.->|"BYOK"| F["plain English in"]
|
|
203
202
|
```
|
|
@@ -249,11 +248,35 @@ distinction is the whole of the data boundary below.
|
|
|
249
248
|
|
|
250
249
|
---
|
|
251
250
|
|
|
252
|
-
##
|
|
251
|
+
## Quickstart: Offline First, Then Connect for Firms
|
|
253
252
|
|
|
254
|
-
|
|
253
|
+
### 1. Free and offline (no account, no API key)
|
|
254
|
+
|
|
255
|
+
The Python library (`import alphaengine`), every validation and portfolio math primitive, `alphaengine demo`, `alphaengine process`, and `ae verify` run 100% offline with no key (see [Free vs. Firm](docs/free-vs-firm.md)):
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
pip install alphaengine
|
|
259
|
+
|
|
260
|
+
# Run the built-in 9-trial parameter sweep and inspect the surface & DSR verdict
|
|
261
|
+
alphaengine demo
|
|
262
|
+
|
|
263
|
+
# Fit OU, GBM, jump-diffusion, and GARCH(1,1) processes and run DGP stress offline
|
|
264
|
+
alphaengine process
|
|
265
|
+
|
|
266
|
+
# Verify any sealed Study artifact (Schema 1.2 or legacy) without an account
|
|
267
|
+
ae verify study.json
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### 2. Connect for firms (`ae_live_` key from the quantOS portal)
|
|
271
|
+
|
|
272
|
+
CLI workflows and the local-first Research OS (`ae init`, project ledgers, dataset registry, hypothesis tracking, sealing, memos, and workspace sync) require a firm `ae_live_` key issued through **Connect** in your firm's [quantOS portal](https://qosai.app). There is no retail CLI key or `--retail` flag.
|
|
273
|
+
|
|
274
|
+
Both `alphaengine` and the short alias `ae` run the same entry point (see [Free vs. Firm](docs/free-vs-firm.md), [project format](docs/project-format.md), [result envelope](docs/result-format.md), and [plugins](docs/plugins.md)):
|
|
255
275
|
|
|
256
276
|
```bash
|
|
277
|
+
# Sign in with your firm's Connect key (stored in OS keychain or 0600 fallback)
|
|
278
|
+
ae login
|
|
279
|
+
|
|
257
280
|
# 1. Initialize a local .alphaengine/ workspace
|
|
258
281
|
ae init --name equity-momentum
|
|
259
282
|
|
|
@@ -274,7 +297,7 @@ ae log --family mom_20d
|
|
|
274
297
|
ae show HEAD
|
|
275
298
|
ae rerun HEAD
|
|
276
299
|
|
|
277
|
-
# 6. Seal into a Schema 1.2 Study, verify against data, and export a committee memo
|
|
300
|
+
# 6. Seal into a Schema 1.2 Study, verify against data (keyless), and export a committee memo
|
|
278
301
|
ae seal HEAD
|
|
279
302
|
ae verify .alphaengine/studies/HEAD.json
|
|
280
303
|
ae report memo HEAD --format md
|
|
@@ -282,6 +305,18 @@ ae report memo HEAD --format md
|
|
|
282
305
|
|
|
283
306
|
---
|
|
284
307
|
|
|
308
|
+
## What's new in 1.1.1
|
|
309
|
+
|
|
310
|
+
- **Single firm-key choke point (`require_firm_key()`):** Every gated CLI workflow (`run`, `validate`, `screen`, `diagnose`, `signal`, `stress`, `overlap`, `size`, `monitor`) and Research OS command (`init`, `log`, `show`, `diff`, `rerun`, `watch`, `data`, `idea`, `seal`, `report`, `remote`, `push`, `pull`, `plugin`, `shell`) validates a firm `ae_live_` key upfront via `alphaengine.auth.require_firm_key()`. The library, `alphaengine demo`, `alphaengine process`, and `ae verify` remain free and keyless.
|
|
311
|
+
- **OS keychain storage & secret redaction:** `auth.py` stores credentials in the OS keychain (`keyring`) when available with `~/.config/alphaengine/credentials.json` (`0600`) as fallback, and automatically redacts `ae_live_*` tokens from CLI output, errors, tracebacks, and `--json` envelopes.
|
|
312
|
+
- **Retail CLI path removed:** Removed `--retail` and `/api/retail/ledger/import` from the CLI; retail ledger import happens via web upload in the quantOS portal.
|
|
313
|
+
- **Unified canonical SHA-256 contract & golden fixture:** `canonical_sha256()` (Schema 1.2 sorted-key JSON with fixed `.8f` float formatting and full 64-hex SHA-256) powers `content_sha256`, study seals, CAS objects, dataset hashes, and parameter hashes. Legacy seals still verify and are labeled `"legacy"`. Shipped `alphaengine/contracts/hash_golden.json` in the wheel for cross-repo verification.
|
|
314
|
+
- **Project-wide cumulative trials & DSR everywhere (with re-run deduplication):** The project-wide cumulative trial ledger feeds every DSR — run output, headline `deflated_sharpe` and `n_trials`, push payloads, and sealed studies — with no per-run or per-family reset. Re-running an identical configuration (`command` + `params_hash` + `dataset_hashes`) records `duplicate_of` and adds `0` new trials (`9 -> 9`), while distinct configurations increment cumulative `N` (`9 -> 18`).
|
|
315
|
+
- **Metadata versioning & socket-blocked offline test:** `__version__` is read from `importlib.metadata.version("alphaengine")` with no hardcoded version strings, `combinatorial_oos_stability` and `PBO via CSCV` naming is standardized throughout, and `tests/test_smoke.py` enforces zero socket calls across DSR, PBO via CSCV, `combinatorial_oos_stability`, metrics, `sweep`, and loaders.
|
|
316
|
+
- **Free vs. Firm guide:** Added [`docs/free-vs-firm.md`](docs/free-vs-firm.md).
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
285
320
|
## What's new in 1.1.0
|
|
286
321
|
|
|
287
322
|
- **Local-first project workspace (`ae init`):** Creates `.alphaengine/` (`project.toml`, `ledger/`, `data/`, `studies/`, `ideas/`, `universes/`, and SHA-256 content-addressed `objects/`). Commands walk up from the current directory to find the project; outside a project, every command behaves as a standalone call.
|
|
@@ -295,7 +330,7 @@ ae report memo HEAD --format md
|
|
|
295
330
|
## What's new in 1.0.3
|
|
296
331
|
|
|
297
332
|
- **Opt-in series sharing & 512-element wire guard:** By default, workflow step traces (`/api/harness/runs/{id}/traces`) report scalar figures only; full series are shared only when you pass `--share-series` or set `ALPHAENGINE_SHARE_SERIES=1`.
|
|
298
|
-
- **Sealed studies (schema 1.2) & CLI reporting:** Studies now carry a canonical-JSON SHA-256 seal (`content_sha256`), a full 64-hex `data_hash`, and an optional per-trial ledger (`include_ledger=True`). Use `alphaengine seal <study.json>` to seal or verify a study file, and `alphaengine report <study.json
|
|
333
|
+
- **Sealed studies (schema 1.2) & CLI reporting:** Studies now carry a canonical-JSON SHA-256 seal (`content_sha256`), a full 64-hex `data_hash`, and an optional per-trial ledger (`include_ledger=True`). Use `alphaengine seal <study.json>` to seal or verify a study file, and `alphaengine report <study.json>` to ingest into quantOS.
|
|
299
334
|
- **Math fixes:** `SweepResult.verdict()` passes cross-trial Sharpe dispersion into `deflated_sharpe` per Bailey & López de Prado (2014); `deflated_sharpe(n_trials=1)` returns `psr_vs_zero` with `sr0_expected_max = 0.0` instead of deflating as `N=2`; `combinatorial_oos_stability` replaces `cpcv_score` (kept as a deprecated alias); and `pbo_cscv` validates that `n_splits` is an even integer $\ge 2$.
|
|
300
335
|
- **Interop loaders (`alphaengine.io`):** `from_quantconnect(path)` and `from_vectorbt(portfolio_or_csv)` build a `Study` with returns and preserve trial-count provenance (`"asserted"` vs. `"not_recorded"`).
|
|
301
336
|
|
|
@@ -316,7 +351,7 @@ A portal that rejects the trace does not fail the run.
|
|
|
316
351
|
## What's new in 0.8.0
|
|
317
352
|
|
|
318
353
|
Named processes, Grinold, and a frozen chart contract. Existing goldens
|
|
319
|
-
(deflated Sharpe, PBO, performance, screen) are byte-identical. New figures
|
|
354
|
+
(deflated Sharpe, PBO via CSCV, performance, screen) are byte-identical. New figures
|
|
320
355
|
are a public contract from this release. The study schema is **1.1**: optional
|
|
321
356
|
`process` and `charts` fields; 1.0 studies still load.
|
|
322
357
|
|
|
@@ -345,7 +380,7 @@ a = grinold_alpha(panel, ic=0.05, vols=vols) # alpha stays here; missing vols a
|
|
|
345
380
|
## What's new in 0.7.0
|
|
346
381
|
|
|
347
382
|
The daily modelling morning, and the overnight book, without a third
|
|
348
|
-
dependency. Existing goldens (deflated Sharpe, PBO, performance, screen) are
|
|
383
|
+
dependency. Existing goldens (deflated Sharpe, PBO via CSCV, performance, screen) are
|
|
349
384
|
byte-identical. New figures are a public contract from this release.
|
|
350
385
|
|
|
351
386
|
| You have | You get | Module |
|
|
@@ -416,7 +451,7 @@ w = hrp_weights(cov, names=names) # no matrix inverse; weights sum to one
|
|
|
416
451
|
| `watch <pipeline.yaml> [--interval SECONDS]` | re-run a declarative pipeline whenever a registered dataset file changes | shell + session |
|
|
417
452
|
| `seal <study.json \| run \| idea>` | write canonical content_sha256 into a study (or seal a project run/idea) | shell + session |
|
|
418
453
|
| `verify <study.json> [--data FILE]` | verify a study.json content_sha256 seal and optionally re-check figures | shell + session |
|
|
419
|
-
| `report <study.json>
|
|
454
|
+
| `report <study.json> \| memo <idea \| run> [--format md \| pdf]` | send a study to quantOS (/api/me/runs/ingest), or export a cited committee memo | shell + session |
|
|
420
455
|
| `<anything else>` | ask in plain English; your model picks a workflow and drives it | session |
|
|
421
456
|
| `status` | the current run, and what is loaded | session |
|
|
422
457
|
|
|
@@ -477,7 +512,6 @@ w = hrp_weights(cov, names=names) # no matrix inverse; weights sum to one
|
|
|
477
512
|
| `--limit N` | how many rows to show (default 25) |
|
|
478
513
|
| `--budget N` | how many runs a night is worth (default 3) |
|
|
479
514
|
| `--purge` | remove ~/.config/alphaengine/credentials.json and clean up its config directory |
|
|
480
|
-
| `--retail` | send the study to the retail experiment ledger (/api/retail/ledger/import) |
|
|
481
515
|
| `--name NAME` | name for the initialized project or registered dataset |
|
|
482
516
|
| `--idea ID` | attach the run or filter the log to a local hypothesis id |
|
|
483
517
|
| `--family FAMILY` | strategy or experiment family for cumulative trial counting |
|
|
@@ -532,7 +566,6 @@ alphaengine seal HEAD
|
|
|
532
566
|
alphaengine verify study.json
|
|
533
567
|
alphaengine verify study.json --data prices.csv
|
|
534
568
|
alphaengine report study.json
|
|
535
|
-
alphaengine report study.json --retail
|
|
536
569
|
alphaengine report memo HEAD --format md
|
|
537
570
|
alphaengine models
|
|
538
571
|
alphaengine trace
|
|
@@ -587,7 +620,7 @@ above exists to copy:
|
|
|
587
620
|
per-period returns themselves. `sweep` does `np.asarray(list(raw))`, so a dict
|
|
588
621
|
of results iterates its *keys* and fails on the first string.
|
|
589
622
|
|
|
590
|
-
**Return the same length for every combination.** PBO splits the trial matrix
|
|
623
|
+
**Return the same length for every combination.** PBO via CSCV splits the trial matrix
|
|
591
624
|
into time blocks and compares configurations within each block, which only means
|
|
592
625
|
anything if they line up in time. Ragged output is refused rather than truncated,
|
|
593
626
|
because silently trimming produces a confident number over series that do not
|
|
@@ -639,7 +672,7 @@ diffable, and versioned so it still parses in two years.
|
|
|
639
672
|
|
|
640
673
|
| Module | Contents |
|
|
641
674
|
|---|---|
|
|
642
|
-
| `alphaengine.core` | deflated Sharpe, PSR, PBO via CSCV,
|
|
675
|
+
| `alphaengine.core` | deflated Sharpe, PSR, PBO via CSCV, `combinatorial_oos_stability`, minimum track record length, performance and risk |
|
|
643
676
|
| `alphaengine.core.panel` | cross-sectional rank, z-score, winsorize, neutralize |
|
|
644
677
|
| `alphaengine.core.signals` | IC, ICIR, quantile returns, decay |
|
|
645
678
|
| `alphaengine.core.cross_section` | Fama-MacBeth, quantile book with turnover |
|
|
@@ -678,14 +711,15 @@ Study.from_sweep(r, label="momentum, 9 configs").report()
|
|
|
678
711
|
What crosses is an explicit allowlist: the trial count and how it was obtained,
|
|
679
712
|
a content hash of the data, the verdict, the shape of the neighbourhood, the
|
|
680
713
|
performance figures. Computation runs locally; when you are signed in to
|
|
681
|
-
quantOS, summary figures are reported to your account, and full series
|
|
682
|
-
|
|
683
|
-
|
|
714
|
+
quantOS, summary figures are reported to your account, and full return series
|
|
715
|
+
upload only with `--share-series` (or `ALPHAENGINE_SHARE_SERIES=1`). Without
|
|
716
|
+
`--share-series`, a guard keyed on length (at most 512 elements) refuses to send
|
|
684
717
|
anything series-shaped whatever it is called.
|
|
685
718
|
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
719
|
+
### What uses the network
|
|
720
|
+
|
|
721
|
+
- **Zero network calls (completely offline):** `import alphaengine`, `sweep()`, `Study.save()`, `Study.load()`, every math primitive in `alphaengine.core` (`deflated_sharpe`, `pbo_cscv`, `combinatorial_oos_stability`, performance, risk, covariance, allocation, process calibration/stress, Grinold), local loaders (`load_csv`, `from_quantconnect`, `from_vectorbt`), `alphaengine demo`, `alphaengine process`, and `ae verify`.
|
|
722
|
+
- **Uses the network (requires a firm `ae_live_` key from Connect):** `login` / `whoami`, CLI workflows (`validate`, `screen`, `diagnose`, `decompose`, `pairs`, `walkforward`, `compare`, `size`, `run`, `workflows`, `runs`, `gaps`, `tonight`), `Study.report()` / `ae report`, and workspace sync (`ae seal` key check, `ae push`, `ae pull`). Full return series upload **only** when `--share-series` is passed.
|
|
689
723
|
|
|
690
724
|
## Where this sits in QuantOS
|
|
691
725
|
|
|
@@ -123,16 +123,15 @@ Each is useful without the one above it. `login` lights the next one.
|
|
|
123
123
|
|
|
124
124
|
| Rung | What you need | What you get |
|
|
125
125
|
|---|---|---|
|
|
126
|
-
| **The maths** | nothing | `alphaengine demo`, `alphaengine process`, and the full Python API (`import alphaengine`, `sweep`, `core`), offline, forever. No account. |
|
|
127
|
-
| **
|
|
126
|
+
| **The maths** | nothing | `alphaengine demo`, `alphaengine process`, `ae verify`, and the full Python API (`import alphaengine`, `sweep`, `core`), offline, forever. No account. |
|
|
127
|
+
| **Firm workflows & CLI OS** | a firm `ae_live_` key from **Connect** in your firm's quantOS portal (`login` or `QUANTOS_API_KEY`; see [docs/free-vs-firm.md](docs/free-vs-firm.md)) | The eight workflow commands (`diagnose`, `screen`, `signal`, `validate`, `stress`, `overlap`, `size`, `monitor`), `workflows`, `runs`, `gaps`, `tonight`, `run <workflow>`, and the Research OS (`init`, `log`, `show`, `diff`, `rerun`, `watch`, `data`, `idea`, `seal`, `report`, `remote`, `push`, `pull`, `plugin`, `shell`). |
|
|
128
128
|
| **Ask anything** | your OWN model key (`login anthropic`) | Plain English in. Runs under your account, not ours. |
|
|
129
129
|
|
|
130
|
-
The
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
work completely offline without an account or key.
|
|
130
|
+
The workflow commands and Research OS require a firm `ae_live_` key issued through
|
|
131
|
+
**Connect** in your firm's quantOS portal (see [docs/free-vs-firm.md](docs/free-vs-firm.md)).
|
|
132
|
+
There is no retail CLI key. `alphaengine demo`, `alphaengine process`, `ae verify`,
|
|
133
|
+
and the Python library (`import alphaengine`) work completely offline without an
|
|
134
|
+
account or key.
|
|
136
135
|
|
|
137
136
|
**How credentials are handled.** QuantOS never receives your LLM provider key:
|
|
138
137
|
it goes directly from this process to your chosen provider. By default, keys can
|
|
@@ -150,7 +149,7 @@ at `login`). To delete the stored file at any time, run
|
|
|
150
149
|
flowchart LR
|
|
151
150
|
A["demo / import<br/>offline maths"] --> B["login<br/>QuantOS key"]
|
|
152
151
|
B --> C["login anthropic<br/>your model"]
|
|
153
|
-
A -.->|"no account"| D["DSR · PBO · ICIR · HRP"]
|
|
152
|
+
A -.->|"no account"| D["DSR · PBO (CSCV) · ICIR · HRP"]
|
|
154
153
|
B -.->|"ae_live_"| E["screen · validate · runs"]
|
|
155
154
|
C -.->|"BYOK"| F["plain English in"]
|
|
156
155
|
```
|
|
@@ -202,11 +201,35 @@ distinction is the whole of the data boundary below.
|
|
|
202
201
|
|
|
203
202
|
---
|
|
204
203
|
|
|
205
|
-
##
|
|
204
|
+
## Quickstart: Offline First, Then Connect for Firms
|
|
206
205
|
|
|
207
|
-
|
|
206
|
+
### 1. Free and offline (no account, no API key)
|
|
207
|
+
|
|
208
|
+
The Python library (`import alphaengine`), every validation and portfolio math primitive, `alphaengine demo`, `alphaengine process`, and `ae verify` run 100% offline with no key (see [Free vs. Firm](docs/free-vs-firm.md)):
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
pip install alphaengine
|
|
212
|
+
|
|
213
|
+
# Run the built-in 9-trial parameter sweep and inspect the surface & DSR verdict
|
|
214
|
+
alphaengine demo
|
|
215
|
+
|
|
216
|
+
# Fit OU, GBM, jump-diffusion, and GARCH(1,1) processes and run DGP stress offline
|
|
217
|
+
alphaengine process
|
|
218
|
+
|
|
219
|
+
# Verify any sealed Study artifact (Schema 1.2 or legacy) without an account
|
|
220
|
+
ae verify study.json
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### 2. Connect for firms (`ae_live_` key from the quantOS portal)
|
|
224
|
+
|
|
225
|
+
CLI workflows and the local-first Research OS (`ae init`, project ledgers, dataset registry, hypothesis tracking, sealing, memos, and workspace sync) require a firm `ae_live_` key issued through **Connect** in your firm's [quantOS portal](https://qosai.app). There is no retail CLI key or `--retail` flag.
|
|
226
|
+
|
|
227
|
+
Both `alphaengine` and the short alias `ae` run the same entry point (see [Free vs. Firm](docs/free-vs-firm.md), [project format](docs/project-format.md), [result envelope](docs/result-format.md), and [plugins](docs/plugins.md)):
|
|
208
228
|
|
|
209
229
|
```bash
|
|
230
|
+
# Sign in with your firm's Connect key (stored in OS keychain or 0600 fallback)
|
|
231
|
+
ae login
|
|
232
|
+
|
|
210
233
|
# 1. Initialize a local .alphaengine/ workspace
|
|
211
234
|
ae init --name equity-momentum
|
|
212
235
|
|
|
@@ -227,7 +250,7 @@ ae log --family mom_20d
|
|
|
227
250
|
ae show HEAD
|
|
228
251
|
ae rerun HEAD
|
|
229
252
|
|
|
230
|
-
# 6. Seal into a Schema 1.2 Study, verify against data, and export a committee memo
|
|
253
|
+
# 6. Seal into a Schema 1.2 Study, verify against data (keyless), and export a committee memo
|
|
231
254
|
ae seal HEAD
|
|
232
255
|
ae verify .alphaengine/studies/HEAD.json
|
|
233
256
|
ae report memo HEAD --format md
|
|
@@ -235,6 +258,18 @@ ae report memo HEAD --format md
|
|
|
235
258
|
|
|
236
259
|
---
|
|
237
260
|
|
|
261
|
+
## What's new in 1.1.1
|
|
262
|
+
|
|
263
|
+
- **Single firm-key choke point (`require_firm_key()`):** Every gated CLI workflow (`run`, `validate`, `screen`, `diagnose`, `signal`, `stress`, `overlap`, `size`, `monitor`) and Research OS command (`init`, `log`, `show`, `diff`, `rerun`, `watch`, `data`, `idea`, `seal`, `report`, `remote`, `push`, `pull`, `plugin`, `shell`) validates a firm `ae_live_` key upfront via `alphaengine.auth.require_firm_key()`. The library, `alphaengine demo`, `alphaengine process`, and `ae verify` remain free and keyless.
|
|
264
|
+
- **OS keychain storage & secret redaction:** `auth.py` stores credentials in the OS keychain (`keyring`) when available with `~/.config/alphaengine/credentials.json` (`0600`) as fallback, and automatically redacts `ae_live_*` tokens from CLI output, errors, tracebacks, and `--json` envelopes.
|
|
265
|
+
- **Retail CLI path removed:** Removed `--retail` and `/api/retail/ledger/import` from the CLI; retail ledger import happens via web upload in the quantOS portal.
|
|
266
|
+
- **Unified canonical SHA-256 contract & golden fixture:** `canonical_sha256()` (Schema 1.2 sorted-key JSON with fixed `.8f` float formatting and full 64-hex SHA-256) powers `content_sha256`, study seals, CAS objects, dataset hashes, and parameter hashes. Legacy seals still verify and are labeled `"legacy"`. Shipped `alphaengine/contracts/hash_golden.json` in the wheel for cross-repo verification.
|
|
267
|
+
- **Project-wide cumulative trials & DSR everywhere (with re-run deduplication):** The project-wide cumulative trial ledger feeds every DSR — run output, headline `deflated_sharpe` and `n_trials`, push payloads, and sealed studies — with no per-run or per-family reset. Re-running an identical configuration (`command` + `params_hash` + `dataset_hashes`) records `duplicate_of` and adds `0` new trials (`9 -> 9`), while distinct configurations increment cumulative `N` (`9 -> 18`).
|
|
268
|
+
- **Metadata versioning & socket-blocked offline test:** `__version__` is read from `importlib.metadata.version("alphaengine")` with no hardcoded version strings, `combinatorial_oos_stability` and `PBO via CSCV` naming is standardized throughout, and `tests/test_smoke.py` enforces zero socket calls across DSR, PBO via CSCV, `combinatorial_oos_stability`, metrics, `sweep`, and loaders.
|
|
269
|
+
- **Free vs. Firm guide:** Added [`docs/free-vs-firm.md`](docs/free-vs-firm.md).
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
238
273
|
## What's new in 1.1.0
|
|
239
274
|
|
|
240
275
|
- **Local-first project workspace (`ae init`):** Creates `.alphaengine/` (`project.toml`, `ledger/`, `data/`, `studies/`, `ideas/`, `universes/`, and SHA-256 content-addressed `objects/`). Commands walk up from the current directory to find the project; outside a project, every command behaves as a standalone call.
|
|
@@ -248,7 +283,7 @@ ae report memo HEAD --format md
|
|
|
248
283
|
## What's new in 1.0.3
|
|
249
284
|
|
|
250
285
|
- **Opt-in series sharing & 512-element wire guard:** By default, workflow step traces (`/api/harness/runs/{id}/traces`) report scalar figures only; full series are shared only when you pass `--share-series` or set `ALPHAENGINE_SHARE_SERIES=1`.
|
|
251
|
-
- **Sealed studies (schema 1.2) & CLI reporting:** Studies now carry a canonical-JSON SHA-256 seal (`content_sha256`), a full 64-hex `data_hash`, and an optional per-trial ledger (`include_ledger=True`). Use `alphaengine seal <study.json>` to seal or verify a study file, and `alphaengine report <study.json
|
|
286
|
+
- **Sealed studies (schema 1.2) & CLI reporting:** Studies now carry a canonical-JSON SHA-256 seal (`content_sha256`), a full 64-hex `data_hash`, and an optional per-trial ledger (`include_ledger=True`). Use `alphaengine seal <study.json>` to seal or verify a study file, and `alphaengine report <study.json>` to ingest into quantOS.
|
|
252
287
|
- **Math fixes:** `SweepResult.verdict()` passes cross-trial Sharpe dispersion into `deflated_sharpe` per Bailey & López de Prado (2014); `deflated_sharpe(n_trials=1)` returns `psr_vs_zero` with `sr0_expected_max = 0.0` instead of deflating as `N=2`; `combinatorial_oos_stability` replaces `cpcv_score` (kept as a deprecated alias); and `pbo_cscv` validates that `n_splits` is an even integer $\ge 2$.
|
|
253
288
|
- **Interop loaders (`alphaengine.io`):** `from_quantconnect(path)` and `from_vectorbt(portfolio_or_csv)` build a `Study` with returns and preserve trial-count provenance (`"asserted"` vs. `"not_recorded"`).
|
|
254
289
|
|
|
@@ -269,7 +304,7 @@ A portal that rejects the trace does not fail the run.
|
|
|
269
304
|
## What's new in 0.8.0
|
|
270
305
|
|
|
271
306
|
Named processes, Grinold, and a frozen chart contract. Existing goldens
|
|
272
|
-
(deflated Sharpe, PBO, performance, screen) are byte-identical. New figures
|
|
307
|
+
(deflated Sharpe, PBO via CSCV, performance, screen) are byte-identical. New figures
|
|
273
308
|
are a public contract from this release. The study schema is **1.1**: optional
|
|
274
309
|
`process` and `charts` fields; 1.0 studies still load.
|
|
275
310
|
|
|
@@ -298,7 +333,7 @@ a = grinold_alpha(panel, ic=0.05, vols=vols) # alpha stays here; missing vols a
|
|
|
298
333
|
## What's new in 0.7.0
|
|
299
334
|
|
|
300
335
|
The daily modelling morning, and the overnight book, without a third
|
|
301
|
-
dependency. Existing goldens (deflated Sharpe, PBO, performance, screen) are
|
|
336
|
+
dependency. Existing goldens (deflated Sharpe, PBO via CSCV, performance, screen) are
|
|
302
337
|
byte-identical. New figures are a public contract from this release.
|
|
303
338
|
|
|
304
339
|
| You have | You get | Module |
|
|
@@ -369,7 +404,7 @@ w = hrp_weights(cov, names=names) # no matrix inverse; weights sum to one
|
|
|
369
404
|
| `watch <pipeline.yaml> [--interval SECONDS]` | re-run a declarative pipeline whenever a registered dataset file changes | shell + session |
|
|
370
405
|
| `seal <study.json \| run \| idea>` | write canonical content_sha256 into a study (or seal a project run/idea) | shell + session |
|
|
371
406
|
| `verify <study.json> [--data FILE]` | verify a study.json content_sha256 seal and optionally re-check figures | shell + session |
|
|
372
|
-
| `report <study.json>
|
|
407
|
+
| `report <study.json> \| memo <idea \| run> [--format md \| pdf]` | send a study to quantOS (/api/me/runs/ingest), or export a cited committee memo | shell + session |
|
|
373
408
|
| `<anything else>` | ask in plain English; your model picks a workflow and drives it | session |
|
|
374
409
|
| `status` | the current run, and what is loaded | session |
|
|
375
410
|
|
|
@@ -430,7 +465,6 @@ w = hrp_weights(cov, names=names) # no matrix inverse; weights sum to one
|
|
|
430
465
|
| `--limit N` | how many rows to show (default 25) |
|
|
431
466
|
| `--budget N` | how many runs a night is worth (default 3) |
|
|
432
467
|
| `--purge` | remove ~/.config/alphaengine/credentials.json and clean up its config directory |
|
|
433
|
-
| `--retail` | send the study to the retail experiment ledger (/api/retail/ledger/import) |
|
|
434
468
|
| `--name NAME` | name for the initialized project or registered dataset |
|
|
435
469
|
| `--idea ID` | attach the run or filter the log to a local hypothesis id |
|
|
436
470
|
| `--family FAMILY` | strategy or experiment family for cumulative trial counting |
|
|
@@ -485,7 +519,6 @@ alphaengine seal HEAD
|
|
|
485
519
|
alphaengine verify study.json
|
|
486
520
|
alphaengine verify study.json --data prices.csv
|
|
487
521
|
alphaengine report study.json
|
|
488
|
-
alphaengine report study.json --retail
|
|
489
522
|
alphaengine report memo HEAD --format md
|
|
490
523
|
alphaengine models
|
|
491
524
|
alphaengine trace
|
|
@@ -540,7 +573,7 @@ above exists to copy:
|
|
|
540
573
|
per-period returns themselves. `sweep` does `np.asarray(list(raw))`, so a dict
|
|
541
574
|
of results iterates its *keys* and fails on the first string.
|
|
542
575
|
|
|
543
|
-
**Return the same length for every combination.** PBO splits the trial matrix
|
|
576
|
+
**Return the same length for every combination.** PBO via CSCV splits the trial matrix
|
|
544
577
|
into time blocks and compares configurations within each block, which only means
|
|
545
578
|
anything if they line up in time. Ragged output is refused rather than truncated,
|
|
546
579
|
because silently trimming produces a confident number over series that do not
|
|
@@ -592,7 +625,7 @@ diffable, and versioned so it still parses in two years.
|
|
|
592
625
|
|
|
593
626
|
| Module | Contents |
|
|
594
627
|
|---|---|
|
|
595
|
-
| `alphaengine.core` | deflated Sharpe, PSR, PBO via CSCV,
|
|
628
|
+
| `alphaengine.core` | deflated Sharpe, PSR, PBO via CSCV, `combinatorial_oos_stability`, minimum track record length, performance and risk |
|
|
596
629
|
| `alphaengine.core.panel` | cross-sectional rank, z-score, winsorize, neutralize |
|
|
597
630
|
| `alphaengine.core.signals` | IC, ICIR, quantile returns, decay |
|
|
598
631
|
| `alphaengine.core.cross_section` | Fama-MacBeth, quantile book with turnover |
|
|
@@ -631,14 +664,15 @@ Study.from_sweep(r, label="momentum, 9 configs").report()
|
|
|
631
664
|
What crosses is an explicit allowlist: the trial count and how it was obtained,
|
|
632
665
|
a content hash of the data, the verdict, the shape of the neighbourhood, the
|
|
633
666
|
performance figures. Computation runs locally; when you are signed in to
|
|
634
|
-
quantOS, summary figures are reported to your account, and full series
|
|
635
|
-
|
|
636
|
-
|
|
667
|
+
quantOS, summary figures are reported to your account, and full return series
|
|
668
|
+
upload only with `--share-series` (or `ALPHAENGINE_SHARE_SERIES=1`). Without
|
|
669
|
+
`--share-series`, a guard keyed on length (at most 512 elements) refuses to send
|
|
637
670
|
anything series-shaped whatever it is called.
|
|
638
671
|
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
672
|
+
### What uses the network
|
|
673
|
+
|
|
674
|
+
- **Zero network calls (completely offline):** `import alphaengine`, `sweep()`, `Study.save()`, `Study.load()`, every math primitive in `alphaengine.core` (`deflated_sharpe`, `pbo_cscv`, `combinatorial_oos_stability`, performance, risk, covariance, allocation, process calibration/stress, Grinold), local loaders (`load_csv`, `from_quantconnect`, `from_vectorbt`), `alphaengine demo`, `alphaengine process`, and `ae verify`.
|
|
675
|
+
- **Uses the network (requires a firm `ae_live_` key from Connect):** `login` / `whoami`, CLI workflows (`validate`, `screen`, `diagnose`, `decompose`, `pairs`, `walkforward`, `compare`, `size`, `run`, `workflows`, `runs`, `gaps`, `tonight`), `Study.report()` / `ae report`, and workspace sync (`ae seal` key check, `ae push`, `ae pull`). Full return series upload **only** when `--share-series` is passed.
|
|
642
676
|
|
|
643
677
|
## Where this sits in QuantOS
|
|
644
678
|
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Free Open-Source Library vs. Firm CLI Workflows (`Connect`)
|
|
2
|
+
|
|
3
|
+
AlphaEngine has a strict, unambiguous boundary between what is **free and offline forever** for every researcher, and what requires a **firm `ae_live_` key** from **Connect** in the [quantOS portal](https://qosai.app).
|
|
4
|
+
|
|
5
|
+
There is **no retail CLI key** and **no retail CLI path**. Retail ledger import happens by web upload in the quantOS portal, not through the CLI.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. Free, Keyless, and 100% Offline
|
|
10
|
+
|
|
11
|
+
Installing `pip install alphaengine` gives you the complete validation and research library with **no account, no API key, and zero network calls**:
|
|
12
|
+
|
|
13
|
+
| Surface | Commands / Entry Points | Network Calls | Key Required |
|
|
14
|
+
|---|---|---|---|
|
|
15
|
+
| **Python Library** | `import alphaengine`, `sweep()`, `Study`, `save()`, `load()` | **None** | **No** |
|
|
16
|
+
| **Validation Math** | `deflated_sharpe` (DSR), `probabilistic_sharpe_ratio` (PSR), `min_track_record_length`, `pbo_cscv` (PBO via CSCV), `combinatorial_oos_stability` | **None** | **No** |
|
|
17
|
+
| **Portfolio & Process Math** | `performance_report`, `compute_var_cvar`, `alphaengine.core.panel`, `signals`, `cross_section`, `covariance`, `allocate`, `process`, `active` | **None** | **No** |
|
|
18
|
+
| **Loaders** | `load_csv`, `load_delimited`, `from_quantconnect`, `from_vectorbt` | **None** | **No** |
|
|
19
|
+
| **Offline CLI Demos** | `alphaengine demo`, `alphaengine process` | **None** | **No** |
|
|
20
|
+
| **Study Verification** | `ae verify <study.json> [--data <file>]` | **None** | **No** |
|
|
21
|
+
|
|
22
|
+
Anyone receiving a sealed `study.json` (whether an academic referee, a peer, or an allocator) can run `ae verify study.json --data prices.csv` offline without an account to verify both the canonical `content_sha256` seal (including legacy seals) and the 64-hex `data_hash`.
|
|
23
|
+
|
|
24
|
+
### Quickstart: Offline First (No Account Needed)
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install alphaengine
|
|
28
|
+
|
|
29
|
+
# 1. Run the built-in 9-trial parameter sweep and inspect the surface & DSR verdict
|
|
30
|
+
alphaengine demo
|
|
31
|
+
|
|
32
|
+
# 2. Fit OU, GBM, jump-diffusion, and GARCH(1,1) processes and run DGP stress offline
|
|
33
|
+
alphaengine process
|
|
34
|
+
|
|
35
|
+
# 3. Verify any sealed Study artifact (Schema 1.2 or legacy)
|
|
36
|
+
ae verify study.json
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
from alphaengine import (
|
|
41
|
+
combinatorial_oos_stability,
|
|
42
|
+
compute_var_cvar,
|
|
43
|
+
deflated_sharpe,
|
|
44
|
+
pbo_cscv,
|
|
45
|
+
performance_report,
|
|
46
|
+
sweep,
|
|
47
|
+
)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 2. Connect for Firms (`ae_live_` Key Required)
|
|
53
|
+
|
|
54
|
+
CLI workflows and the local-first Research OS (`ae init`, project ledgers, dataset registry, hypothesis tracking, sealing, memos, and workspace sync) are built for quantitative teams and require an `ae_live_` key issued to your firm through **Connect** in the quantOS portal:
|
|
55
|
+
|
|
56
|
+
- **Core workflows:** `diagnose`, `screen`, `signal`, `validate`, `stress`, `overlap`, `size`, `monitor`, `run`, `workflows`, `runs`, `gaps`, `tonight`
|
|
57
|
+
- **Research OS (`ae`):** `init`, `log`, `show`, `diff`, `rerun`, `watch`, `data`, `idea`, `seal`, `report`, `remote`, `push`, `pull`, `plugin`, `shell`
|
|
58
|
+
|
|
59
|
+
Every gated command checks `alphaengine.auth.require_firm_key()` before executing. The server is the authority: the key's firm tier is verified server-side on every request, and a key stops working if its firm leaves an active firm tier.
|
|
60
|
+
|
|
61
|
+
### Quickstart: Connect for Firms
|
|
62
|
+
|
|
63
|
+
1. Open your firm's [quantOS portal](https://qosai.app) → **Connect** and issue an `ae_live_...` key.
|
|
64
|
+
2. Sign in once from your terminal (stored in your OS keychain via `keyring` when available, or `~/.config/alphaengine/credentials.json` with `0600` permissions as fallback):
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
ae login
|
|
68
|
+
# or set: export QUANTOS_API_KEY="ae_live_..."
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
3. Initialize your firm project and run workflows with cumulative project-wide trial accounting:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
ae init --name equity-momentum
|
|
75
|
+
ae data add prices.csv --name equities --asof-col date
|
|
76
|
+
ae idea new "Cross-sectional 20d momentum holds net of costs" --kill-if "DSR < 0.9"
|
|
77
|
+
ae validate --project research.momentum --idea idea_1
|
|
78
|
+
ae seal HEAD
|
|
79
|
+
ae push
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 3. What Uses the Network (and What Never Leaves Your Machine)
|
|
85
|
+
|
|
86
|
+
- **Makes zero network calls:** The Python library (`import alphaengine`), all math functions, `sweep()`, `Study.save()` / `load()`, `alphaengine demo`, `alphaengine process`, and `ae verify`. Enforced in CI by a socket-blocked test (`tests/test_smoke.py`).
|
|
87
|
+
- **Uses the network:** `ae login` / `whoami`, CLI workflows (`validate`, `screen`, `diagnose`, etc.), `Study.report()` / `ae report`, and workspace sync (`ae push`, `ae pull`).
|
|
88
|
+
- **Return series boundary:** By default, only summary figures and canonical SHA-256 hashes cross the wire; any list longer than 512 elements is refused by both client and server guards. Full return series upload **only** when you explicitly pass `--share-series` (or set `ALPHAENGINE_SHARE_SERIES=1`).
|
|
@@ -71,9 +71,11 @@ Each `.jsonl` file under `ledger/`, `data/`, and `ideas/` contains one UTF-8 JSO
|
|
|
71
71
|
|
|
72
72
|
---
|
|
73
73
|
|
|
74
|
-
## 4. Discovery Rule
|
|
74
|
+
## 4. Discovery Rule & Network Boundary
|
|
75
75
|
|
|
76
76
|
When any `ae` / `alphaengine` command runs:
|
|
77
77
|
1. It checks the current working directory and each parent directory for `.alphaengine/project.toml`.
|
|
78
78
|
2. If found, the command attaches to that `Project` instance.
|
|
79
|
-
3. If not found, commands that do not strictly require a project (`demo`, `process`, `
|
|
79
|
+
3. If not found, commands that do not strictly require a project (`demo`, `process`, `verify <study.json>`, `version`, etc.) run in standalone mode without touching the filesystem.
|
|
80
|
+
|
|
81
|
+
**Network boundary:** The Python library (`import alphaengine`, `sweep`, DSR, PBO via CSCV, `combinatorial_oos_stability`, metrics, loaders), `alphaengine demo`, `alphaengine process`, and `ae verify` make no network calls. Network calls occur only during `login`/`whoami`, firm CLI workflows, `report`, and `seal`/`push`/`pull` against the configured remote. Full return series upload only when `--share-series` is explicitly passed; otherwise the 512-element wire guard rejects any series-length list.
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "alphaengine"
|
|
7
|
-
|
|
7
|
+
version = "1.1.1"
|
|
8
8
|
description = "Validated research tooling for investment strategies: deflation, overfitting detection, and honest trial counts."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "Apache-2.0"
|
|
@@ -112,9 +112,6 @@ Documentation = "https://github.com/quantOSC/alphaengine#readme"
|
|
|
112
112
|
Source = "https://github.com/quantOSC/alphaengine"
|
|
113
113
|
Issues = "https://github.com/quantOSC/alphaengine/issues"
|
|
114
114
|
|
|
115
|
-
[tool.hatch.version]
|
|
116
|
-
path = "src/alphaengine/_version.py"
|
|
117
|
-
|
|
118
115
|
[tool.hatch.build.targets.wheel]
|
|
119
116
|
packages = ["src/alphaengine"]
|
|
120
117
|
|
|
@@ -24,14 +24,23 @@ WHAT THIS LIBRARY IS NOT
|
|
|
24
24
|
OFFLINE BY CONSTRUCTION
|
|
25
25
|
Importing this module makes no network call and needs no account. numpy and
|
|
26
26
|
scipy, nothing else. Everything above runs on a laptop with the wifi off.
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
Study ingest still refuses anything series-shaped.
|
|
27
|
+
Summary figures upload only when you explicitly run a firm CLI workflow or
|
|
28
|
+
`report()`; full return series upload only with `--share-series`.
|
|
30
29
|
"""
|
|
31
30
|
|
|
32
31
|
from typing import Any
|
|
33
32
|
|
|
34
33
|
from ._version import __version__
|
|
34
|
+
from .core import (
|
|
35
|
+
combinatorial_oos_stability,
|
|
36
|
+
compute_var_cvar,
|
|
37
|
+
cpcv_score,
|
|
38
|
+
deflated_sharpe,
|
|
39
|
+
min_track_record_length,
|
|
40
|
+
pbo_cscv,
|
|
41
|
+
performance_report,
|
|
42
|
+
probabilistic_sharpe_ratio,
|
|
43
|
+
)
|
|
35
44
|
from .study import SCHEMA_VERSION, Study, load, save
|
|
36
45
|
from .sweep import SweepResult, sweep
|
|
37
46
|
|
|
@@ -51,6 +60,14 @@ __all__ = [
|
|
|
51
60
|
"ReportError",
|
|
52
61
|
"SCHEMA_VERSION",
|
|
53
62
|
"io",
|
|
63
|
+
"combinatorial_oos_stability",
|
|
64
|
+
"cpcv_score",
|
|
65
|
+
"deflated_sharpe",
|
|
66
|
+
"probabilistic_sharpe_ratio",
|
|
67
|
+
"min_track_record_length",
|
|
68
|
+
"pbo_cscv",
|
|
69
|
+
"performance_report",
|
|
70
|
+
"compute_var_cvar",
|
|
54
71
|
]
|
|
55
72
|
|
|
56
73
|
|
|
@@ -146,7 +146,7 @@ is what a changed figure costs. The API may still move underneath it.
|
|
|
146
146
|
# cross-trial Sharpe dispersion into `deflated_sharpe` per Bailey & López de
|
|
147
147
|
# Prado (2014). `combinatorial_oos_stability` replaces `cpcv_score` (kept as a
|
|
148
148
|
# deprecated alias). Study schema 1.2 adds `content_sha256` sealing, full 64-hex
|
|
149
|
-
# data hashes, `alphaengine seal`, `alphaengine report
|
|
149
|
+
# data hashes, `alphaengine seal`, `alphaengine report`, and
|
|
150
150
|
# `alphaengine.io` loaders (`from_quantconnect`, `from_vectorbt`). Series upload
|
|
151
151
|
# on `/traces` is opt-in via `--share-series` or `ALPHAENGINE_SHARE_SERIES=1`.
|
|
152
152
|
# 1.1.0 IS THE LOCAL-FIRST RESEARCH OS. No golden in tests/test_goldens.py
|
|
@@ -159,7 +159,9 @@ is what a changed figure costs. The API may still move underneath it.
|
|
|
159
159
|
# prior-work warnings, export `[run_id]`-cited committee memos, discover
|
|
160
160
|
# `alphaengine.plugins` entry points, watch datasets, monitor live drift, and
|
|
161
161
|
# sync with quantOS on opt-in (`ae push` / `ae pull`).
|
|
162
|
-
|
|
162
|
+
from importlib.metadata import version as _pkg_version
|
|
163
|
+
|
|
164
|
+
__version__ = _pkg_version("alphaengine")
|
|
163
165
|
|
|
164
166
|
#: Default workflow/ingest API host until a dedicated qosai.app API host exists.
|
|
165
167
|
#: Overridable via ``ALPHAENGINE_API_URL`` (or ``QUANTOS_API_URL``).
|