numeraire 0.2.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. numeraire-0.2.0/.github/workflows/ci.yml +91 -0
  2. numeraire-0.2.0/.github/workflows/docs.yml +51 -0
  3. numeraire-0.2.0/.github/workflows/publish.yml +37 -0
  4. numeraire-0.2.0/.gitignore +29 -0
  5. numeraire-0.2.0/.pre-commit-config.yaml +24 -0
  6. numeraire-0.2.0/.python-version +1 -0
  7. numeraire-0.2.0/CHANGELOG.md +50 -0
  8. numeraire-0.2.0/LICENSE +28 -0
  9. numeraire-0.2.0/PKG-INFO +105 -0
  10. numeraire-0.2.0/README.md +57 -0
  11. numeraire-0.2.0/docs/.gitignore +5 -0
  12. numeraire-0.2.0/docs/_static/.gitkeep +0 -0
  13. numeraire-0.2.0/docs/_templates/.gitkeep +0 -0
  14. numeraire-0.2.0/docs/api/adapters.skfolio.md +14 -0
  15. numeraire-0.2.0/docs/api/baselines.md +20 -0
  16. numeraire-0.2.0/docs/api/comparison.md +15 -0
  17. numeraire-0.2.0/docs/api/core.capabilities.md +6 -0
  18. numeraire-0.2.0/docs/api/core.data.md +20 -0
  19. numeraire-0.2.0/docs/api/core.engine.md +23 -0
  20. numeraire-0.2.0/docs/api/core.evaluators.md +23 -0
  21. numeraire-0.2.0/docs/api/core.protocols.md +21 -0
  22. numeraire-0.2.0/docs/api/core.registry.md +16 -0
  23. numeraire-0.2.0/docs/api/core.schema.md +6 -0
  24. numeraire-0.2.0/docs/api/core.simulate.md +16 -0
  25. numeraire-0.2.0/docs/api/core.sorts.md +15 -0
  26. numeraire-0.2.0/docs/api/core.splitter.md +15 -0
  27. numeraire-0.2.0/docs/api/core.stats.md +27 -0
  28. numeraire-0.2.0/docs/api/index.md +91 -0
  29. numeraire-0.2.0/docs/api/numeraire.md +9 -0
  30. numeraire-0.2.0/docs/api/reference.md +7 -0
  31. numeraire-0.2.0/docs/api/testing.md +19 -0
  32. numeraire-0.2.0/docs/architecture.md +177 -0
  33. numeraire-0.2.0/docs/changelog.md +2 -0
  34. numeraire-0.2.0/docs/comparison.md +112 -0
  35. numeraire-0.2.0/docs/conf.py +77 -0
  36. numeraire-0.2.0/docs/extending.md +212 -0
  37. numeraire-0.2.0/docs/index.md +91 -0
  38. numeraire-0.2.0/docs/quickstart.md +169 -0
  39. numeraire-0.2.0/pyproject.toml +116 -0
  40. numeraire-0.2.0/src/numeraire/__init__.py +118 -0
  41. numeraire-0.2.0/src/numeraire/adapters/__init__.py +6 -0
  42. numeraire-0.2.0/src/numeraire/adapters/skfolio_adapter.py +105 -0
  43. numeraire-0.2.0/src/numeraire/baselines/__init__.py +39 -0
  44. numeraire-0.2.0/src/numeraire/baselines/forecast.py +64 -0
  45. numeraire-0.2.0/src/numeraire/baselines/weights.py +218 -0
  46. numeraire-0.2.0/src/numeraire/comparison.py +216 -0
  47. numeraire-0.2.0/src/numeraire/core/__init__.py +13 -0
  48. numeraire-0.2.0/src/numeraire/core/_ingest.py +63 -0
  49. numeraire-0.2.0/src/numeraire/core/capabilities.py +25 -0
  50. numeraire-0.2.0/src/numeraire/core/data.py +823 -0
  51. numeraire-0.2.0/src/numeraire/core/engine.py +610 -0
  52. numeraire-0.2.0/src/numeraire/core/evaluators.py +348 -0
  53. numeraire-0.2.0/src/numeraire/core/protocols.py +120 -0
  54. numeraire-0.2.0/src/numeraire/core/registry.py +32 -0
  55. numeraire-0.2.0/src/numeraire/core/schema.py +40 -0
  56. numeraire-0.2.0/src/numeraire/core/simulate.py +231 -0
  57. numeraire-0.2.0/src/numeraire/core/sorts.py +101 -0
  58. numeraire-0.2.0/src/numeraire/core/splitter.py +113 -0
  59. numeraire-0.2.0/src/numeraire/core/stats.py +385 -0
  60. numeraire-0.2.0/src/numeraire/methods/__init__.py +5 -0
  61. numeraire-0.2.0/src/numeraire/py.typed +0 -0
  62. numeraire-0.2.0/src/numeraire/reference.py +225 -0
  63. numeraire-0.2.0/src/numeraire/testing.py +401 -0
  64. numeraire-0.2.0/tests/conftest.py +203 -0
  65. numeraire-0.2.0/tests/test_baselines.py +188 -0
  66. numeraire-0.2.0/tests/test_char_blocks.py +131 -0
  67. numeraire-0.2.0/tests/test_comparison.py +259 -0
  68. numeraire-0.2.0/tests/test_cross_section_view.py +165 -0
  69. numeraire-0.2.0/tests/test_data.py +157 -0
  70. numeraire-0.2.0/tests/test_economic_value.py +121 -0
  71. numeraire-0.2.0/tests/test_engine.py +120 -0
  72. numeraire-0.2.0/tests/test_evaluators.py +179 -0
  73. numeraire-0.2.0/tests/test_ingest_seam.py +100 -0
  74. numeraire-0.2.0/tests/test_input_ingestion.py +219 -0
  75. numeraire-0.2.0/tests/test_multiblock_view.py +78 -0
  76. numeraire-0.2.0/tests/test_no_lookahead.py +150 -0
  77. numeraire-0.2.0/tests/test_no_lookahead_engine.py +119 -0
  78. numeraire-0.2.0/tests/test_panel_internals.py +163 -0
  79. numeraire-0.2.0/tests/test_parallel.py +152 -0
  80. numeraire-0.2.0/tests/test_pricing.py +296 -0
  81. numeraire-0.2.0/tests/test_reference.py +211 -0
  82. numeraire-0.2.0/tests/test_refit_and_validation.py +150 -0
  83. numeraire-0.2.0/tests/test_simulate.py +145 -0
  84. numeraire-0.2.0/tests/test_skfolio_adapter.py +109 -0
  85. numeraire-0.2.0/tests/test_sorts.py +93 -0
  86. numeraire-0.2.0/tests/test_spine.py +63 -0
  87. numeraire-0.2.0/tests/test_splitter.py +55 -0
  88. numeraire-0.2.0/tests/test_stats.py +258 -0
  89. numeraire-0.2.0/tests/test_testing.py +304 -0
  90. numeraire-0.2.0/tests/test_view_combinations.py +206 -0
  91. numeraire-0.2.0/tests/test_vintaged_block.py +70 -0
  92. numeraire-0.2.0/tests/test_walk_forward_panel.py +118 -0
  93. numeraire-0.2.0/uv.lock +2311 -0
@@ -0,0 +1,91 @@
1
+ name: CI
2
+ on:
3
+ push: { branches: [main] }
4
+ pull_request:
5
+ jobs:
6
+ # The single required check (branch protection points at "check"). Do NOT rename it or split it
7
+ # into a matrix — that renames the reported check and breaks protection. The extra compat lanes
8
+ # below are separate, non-required jobs.
9
+ check:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+ - uses: astral-sh/setup-uv@v6
14
+ with: { python-version: "3.12" }
15
+ - run: uv sync --extra dev
16
+ - name: Lint & format
17
+ run: uv run ruff check . && uv run ruff format --check .
18
+ - name: Type check (core + baselines, strict)
19
+ run: uv run basedpyright src/numeraire/core src/numeraire/baselines
20
+ - name: Architecture boundary
21
+ run: uv run lint-imports
22
+ - name: Tests
23
+ run: uv run pytest
24
+ - name: Build
25
+ run: uv build
26
+
27
+ # Floor lane (non-required): lowest supported Python + oldest dependency versions the pyproject
28
+ # constraints allow (numpy 1.26 / scipy 1.11 / pandas 2.x / scikit-learn 1.4). Catches use of
29
+ # APIs newer than the declared floor — the default `check` lane runs current deps (pandas 3.x),
30
+ # so this is where a pandas-2-vs-3 back-compat break would surface.
31
+ floor:
32
+ runs-on: ubuntu-latest
33
+ steps:
34
+ - uses: actions/checkout@v4
35
+ - uses: astral-sh/setup-uv@v6
36
+ with: { python-version: "3.11" }
37
+ - run: uv sync --extra dev --resolution lowest-direct
38
+ - name: Tests
39
+ run: uv run pytest
40
+
41
+ # Leading-edge lane (non-required): newest supported Python + newest dependency versions
42
+ # (pandas 3.x). Catches forward-compat breaks ahead of the required lane moving up.
43
+ leading-edge:
44
+ runs-on: ubuntu-latest
45
+ steps:
46
+ - uses: actions/checkout@v4
47
+ - uses: astral-sh/setup-uv@v6
48
+ with: { python-version: "3.13" }
49
+ - run: uv sync --extra dev --upgrade
50
+ - name: Tests
51
+ run: uv run pytest
52
+
53
+ # Packaging lane (non-required): build the sdist + wheel and validate that the distributions
54
+ # are PyPI-ready (metadata renders, long_description is valid). `twine` is a dev/CI-only tool,
55
+ # never a runtime dependency of the package.
56
+ dist:
57
+ runs-on: ubuntu-latest
58
+ steps:
59
+ - uses: actions/checkout@v4
60
+ with: { fetch-depth: 0 } # full history so hatch-vcs derives the version
61
+ - uses: astral-sh/setup-uv@v6
62
+ with: { python-version: "3.12" }
63
+ - run: uv sync --extra dev
64
+ - name: Build
65
+ run: uv build
66
+ - name: Check distributions
67
+ run: uv run twine check dist/*
68
+
69
+ # Optional adapter lane (non-required): installs the heavy [skfolio] extra so the skfolio
70
+ # adapter tests actually run (they self-skip in the required lane, which omits the extra).
71
+ skfolio:
72
+ runs-on: ubuntu-latest
73
+ steps:
74
+ - uses: actions/checkout@v4
75
+ - uses: astral-sh/setup-uv@v6
76
+ with: { python-version: "3.12" }
77
+ - run: uv sync --extra dev --extra skfolio
78
+ - name: Adapter tests
79
+ run: uv run pytest tests/test_skfolio_adapter.py
80
+
81
+ # Documentation lane (non-required): build the Sphinx site with -W so any cross-reference rot
82
+ # (a broken :class: target, a renamed symbol, a dead toctree link) fails the build immediately.
83
+ docs:
84
+ runs-on: ubuntu-latest
85
+ steps:
86
+ - uses: actions/checkout@v4
87
+ - uses: astral-sh/setup-uv@v6
88
+ with: { python-version: "3.12" }
89
+ - run: uv sync --extra docs
90
+ - name: Build docs (warnings are errors)
91
+ run: uv run sphinx-build -W --keep-going -b html docs docs/_build/html
@@ -0,0 +1,51 @@
1
+ # Build the Sphinx documentation and publish it to GitHub Pages.
2
+ #
3
+ # This runs only on pushes to `main` that touch the docs or the documented source, and only the
4
+ # deploy step needs write access — permissions are scoped to the minimum Pages/OIDC set. Nothing is
5
+ # published from a pull request, so the site never changes before a change is merged.
6
+ name: Docs
7
+
8
+ on:
9
+ push:
10
+ branches: [main]
11
+ paths:
12
+ - "docs/**"
13
+ - "src/**"
14
+ - "pyproject.toml"
15
+ - ".github/workflows/docs.yml"
16
+ workflow_dispatch:
17
+
18
+ # Allow the workflow to mint an OIDC token and publish to Pages; read-only otherwise.
19
+ permissions:
20
+ contents: read
21
+ pages: write
22
+ id-token: write
23
+
24
+ # One in-flight deployment at a time; let a newer push supersede an older run.
25
+ concurrency:
26
+ group: pages
27
+ cancel-in-progress: false
28
+
29
+ jobs:
30
+ build:
31
+ runs-on: ubuntu-latest
32
+ steps:
33
+ - uses: actions/checkout@v4
34
+ - uses: astral-sh/setup-uv@v6
35
+ with: { python-version: "3.12" }
36
+ - run: uv sync --extra docs
37
+ - name: Build docs (warnings are errors)
38
+ run: uv run sphinx-build -W --keep-going -b html docs docs/_build/html
39
+ - uses: actions/upload-pages-artifact@v3
40
+ with:
41
+ path: docs/_build/html
42
+
43
+ deploy:
44
+ needs: build
45
+ runs-on: ubuntu-latest
46
+ environment:
47
+ name: github-pages
48
+ url: ${{ steps.deployment.outputs.page_url }}
49
+ steps:
50
+ - id: deployment
51
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,37 @@
1
+ # Publish to PyPI via Trusted Publishing (OIDC, no stored secrets/tokens).
2
+ #
3
+ # DISARMED ON PURPOSE. This workflow can only be started by hand
4
+ # (`workflow_dispatch`) so it CANNOT fire automatically today — publishing to
5
+ # PyPI is a deliberate, separate decision that is not yet enabled.
6
+ #
7
+ # To ARM it once a Trusted Publisher for `numeraire` is configured on PyPI
8
+ # (https://pypi.org/manage/project/numeraire/settings/publishing/ — point it at
9
+ # this repo + this workflow filename + the `pypi` environment), replace the
10
+ # `workflow_dispatch` trigger below with:
11
+ #
12
+ # on:
13
+ # release:
14
+ # types: [published]
15
+ #
16
+ # so that cutting a GitHub Release publishes the matching tagged version. Until
17
+ # then, keep `workflow_dispatch` as the ONLY trigger.
18
+ name: Publish
19
+ on:
20
+ workflow_dispatch: {}
21
+
22
+ jobs:
23
+ publish:
24
+ runs-on: ubuntu-latest
25
+ environment: pypi
26
+ permissions:
27
+ id-token: write # required for PyPI Trusted Publishing (OIDC); no secrets
28
+ steps:
29
+ - uses: actions/checkout@v4
30
+ with: { fetch-depth: 0 } # full history so hatch-vcs derives the version from the tag
31
+ - uses: astral-sh/setup-uv@v6
32
+ with: { python-version: "3.12" }
33
+ - name: Build
34
+ run: uv build
35
+ - name: Check distributions
36
+ run: uvx twine check dist/* # ephemeral twine; the publish job needs no dev toolchain
37
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,29 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ .venv/
5
+ dist/
6
+ build/
7
+ *.egg-info/
8
+ .coverage
9
+ coverage.xml
10
+ .pytest_cache/
11
+ .ruff_cache/
12
+ .hypothesis/
13
+ .import_linter_cache/
14
+
15
+ # OS
16
+ .DS_Store
17
+
18
+ # Secrets / credentials
19
+ .env
20
+ .env.*
21
+ *.pem
22
+ *.key
23
+ .pypirc
24
+ secrets/
25
+
26
+ # Local data & working directories
27
+ data/
28
+ cache/
29
+ runs/
@@ -0,0 +1,24 @@
1
+ repos:
2
+ - repo: https://github.com/astral-sh/ruff-pre-commit
3
+ rev: v0.6.9
4
+ hooks:
5
+ - { id: ruff, args: [--fix] }
6
+ - { id: ruff-format }
7
+ - repo: https://github.com/pre-commit/pre-commit-hooks
8
+ rev: v5.0.0
9
+ hooks:
10
+ - { id: check-added-large-files, args: [--maxkb=512] } # block accidental data commits
11
+ - { id: detect-private-key }
12
+ - { id: end-of-file-fixer }
13
+ - { id: trailing-whitespace }
14
+ - repo: https://github.com/gitleaks/gitleaks
15
+ rev: v8.21.0
16
+ hooks:
17
+ - { id: gitleaks } # secret scanning
18
+ - repo: local
19
+ hooks:
20
+ - id: import-linter
21
+ name: import-linter (architecture boundary)
22
+ entry: lint-imports
23
+ language: system
24
+ pass_filenames: false
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,50 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+ Versions are tag-driven (`hatch-vcs`).
8
+
9
+ ## [Unreleased]
10
+
11
+ ## [0.2.0] - 2026-07-05
12
+
13
+ First tagged release. The spine is capability-complete: `to_weights`, `to_forecast`,
14
+ and `to_pricing` are all crystallized protocols with walk-forward drivers, native
15
+ evaluators, and a conformance suite.
16
+
17
+ ### Added
18
+
19
+ - **Pricing capability** — `SupportsPricing.expected_returns`, `walk_forward_pricing` /
20
+ `pricing_in_sample`, cross-sectional R² and average-|α| evaluators, and
21
+ `numeraire.comparison.compare` to score competing pricing models (factor models, SDFs,
22
+ risk-premium estimators) on one common set of test assets. Every result row carries an
23
+ explicit `protocol` label (`in_sample` / `walk_forward`), so explanatory numbers are
24
+ never confusable with out-of-sample ones.
25
+ - **Conformance suite** (`numeraire.testing.check_estimator`) — capabilities, output
26
+ shapes, determinism, a no-look-ahead property test, and an engine round-trip: the
27
+ self-certification any extension runs before its numbers are trusted.
28
+ - **Reference registry** (`numeraire.reference.ReferenceResult`) — pinned published
29
+ results with tolerance bands and data-access tiers (`public` / `credentialed` /
30
+ `restricted`); CI stays green on public data while the same case runs verbatim wherever
31
+ licensed data is present.
32
+ - **Bundled baselines** (`numeraire.baselines`) — equal weight (1/N), minimum variance,
33
+ mean-variance, and historical mean, registered through the same entry-point mechanism as
34
+ any external method.
35
+ - **Weight-stream simulator** — `simulate_weights` + `RebalanceSchedule` with explicit
36
+ drift, turnover, and cost conventions.
37
+ - **Inference toolkit** (`core.stats`) — GRS, Clark-West, paired Sharpe
38
+ (Jobson-Korkie–Memmel), HAC alpha regression, Bonferroni/Holm/BHY adjustments, and
39
+ certainty-equivalent / return-loss / performance-fee measures.
40
+ - **Cross-sectional data layer** — `CrossSectionView` with zero-copy point-in-time
41
+ windows, a ragged-panel walk-forward engine, parallel fold execution, refit-cadence
42
+ control, and a validation-split helper.
43
+ - **Interop** — polars/arrow ingestion at the view boundary (narwhals-optional, zero new
44
+ hard dependencies) and a skfolio adapter (`[skfolio]` extra) that wraps portfolio
45
+ optimizers as `to_weights` estimators.
46
+
47
+ Python ≥ 3.11, pandas ≥ 2.2.
48
+
49
+ [Unreleased]: https://github.com/py-numeraire/numeraire/compare/v0.2.0...HEAD
50
+ [0.2.0]: https://github.com/py-numeraire/numeraire/releases/tag/v0.2.0
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2026, Yuheng Wu
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,105 @@
1
+ Metadata-Version: 2.4
2
+ Name: numeraire
3
+ Version: 0.2.0
4
+ Summary: A research framework for backtesting, comparing, and replicating empirical asset-pricing methods.
5
+ Project-URL: Homepage, https://github.com/py-numeraire/numeraire
6
+ Project-URL: Documentation, https://py-numeraire.github.io/numeraire/
7
+ Project-URL: Repository, https://github.com/py-numeraire/numeraire
8
+ Project-URL: Issues, https://github.com/py-numeraire/numeraire/issues
9
+ Project-URL: Changelog, https://github.com/py-numeraire/numeraire/blob/main/CHANGELOG.md
10
+ Project-URL: Releases, https://github.com/py-numeraire/numeraire/releases
11
+ Author-email: Yuheng Wu <wuyuheng20074@live.com>
12
+ License-Expression: BSD-3-Clause
13
+ License-File: LICENSE
14
+ Keywords: asset pricing,backtesting,empirical finance,factor models,portfolio,replication
15
+ Classifier: Development Status :: 4 - Beta
16
+ Classifier: Intended Audience :: Science/Research
17
+ Classifier: License :: OSI Approved :: BSD License
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Office/Business :: Financial :: Investment
23
+ Classifier: Topic :: Scientific/Engineering
24
+ Classifier: Typing :: Typed
25
+ Requires-Python: >=3.11
26
+ Requires-Dist: numpy>=1.26
27
+ Requires-Dist: pandas>=2.2
28
+ Requires-Dist: scikit-learn>=1.4
29
+ Requires-Dist: scipy>=1.11
30
+ Provides-Extra: dev
31
+ Requires-Dist: basedpyright>=1.18; extra == 'dev'
32
+ Requires-Dist: build>=1.2; extra == 'dev'
33
+ Requires-Dist: hypothesis>=6.0; extra == 'dev'
34
+ Requires-Dist: import-linter>=2.0; extra == 'dev'
35
+ Requires-Dist: pandas-stubs>=2.0; extra == 'dev'
36
+ Requires-Dist: pre-commit>=3.7; extra == 'dev'
37
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
38
+ Requires-Dist: pytest>=8.0; extra == 'dev'
39
+ Requires-Dist: ruff>=0.6; extra == 'dev'
40
+ Requires-Dist: twine>=5.0; extra == 'dev'
41
+ Provides-Extra: docs
42
+ Requires-Dist: myst-parser>=3.0; extra == 'docs'
43
+ Requires-Dist: pydata-sphinx-theme>=0.15; extra == 'docs'
44
+ Requires-Dist: sphinx>=7.3; extra == 'docs'
45
+ Provides-Extra: skfolio
46
+ Requires-Dist: skfolio>=0.5; extra == 'skfolio'
47
+ Description-Content-Type: text/markdown
48
+
49
+ # numeraire
50
+
51
+ A research framework providing a **stable bedrock** for **backtesting, comparing, and
52
+ replicating** empirical asset-pricing / financial-econometrics methods (IPCA, VoC, KNS, 1/A,
53
+ factor-model tests, …), **extensible by design** so new methods plug in as first-class extensions.
54
+
55
+ **Documentation:** <https://py-numeraire.github.io/numeraire/>
56
+
57
+ The *numéraire* is the reference unit against which all prices are measured. Core stays
58
+ **representation-agnostic**: it defines *capabilities* (what a model can produce — weights, pricing,
59
+ …), never a specific method's internal form, so linear-factor, nonlinear/RFF, neural, and
60
+ distributional methods are all first-class.
61
+
62
+ ## Architecture (the boundary rule)
63
+
64
+ `numeraire.core` is exactly the modules that depend on no specific method and that every method
65
+ depends on. Dependency arrows point toward `core`; **`core` never imports a method, an adapter, or
66
+ a reference library.** This is enforced in CI by `import-linter` — the lint rule *is* the
67
+ architecture (see `pyproject.toml [tool.importlinter]`).
68
+
69
+ ```
70
+ src/numeraire/
71
+ core/ # spine: DataView/Estimator/Splitter/Evaluator protocols, capabilities,
72
+ # result schema, evaluator registry (stable, strict-typed, high-coverage)
73
+ adapters/ # thin wrappers making reference libraries conform to core — glue, not spine
74
+ methods/ # published methods bundled as extensions (VoC, 1/A, classical tests, …)
75
+ ```
76
+
77
+ Methods register via the `numeraire.methods` entry-point group, so external packages
78
+ (`numeraire-yourlab`, `numeraire-<method>`) are first-class peers without editing core.
79
+
80
+ ## Install
81
+
82
+ ```bash
83
+ uv sync --extra dev # dev environment
84
+ ```
85
+
86
+ Base install is the spine + native general evaluators only; method/adapter deps are extras.
87
+
88
+ ## Develop
89
+
90
+ ```bash
91
+ uv run ruff check . && uv run ruff format --check . # lint + format
92
+ uv run basedpyright src/numeraire/core # strict types on core
93
+ uv run lint-imports # architecture boundary
94
+ uv run pytest # tests (public/synthetic data only)
95
+ ```
96
+
97
+ ## Status
98
+
99
+ Pre-1.0, development. Usable via GitHub install; **not on PyPI yet** (the capability layer is
100
+ expected to crystallize once three real adapters land). The spine (`DataView`, walk-forward OOS
101
+ engine, `Splitter`, native evaluators) is in place; the first method (1/A conservative slope) is
102
+ wired end-to-end.
103
+
104
+ License: BSD-3-Clause. Never commit CRSP/WRDS/proprietary data or credentials (`data/`, `ref/`,
105
+ `.env` are git-ignored).
@@ -0,0 +1,57 @@
1
+ # numeraire
2
+
3
+ A research framework providing a **stable bedrock** for **backtesting, comparing, and
4
+ replicating** empirical asset-pricing / financial-econometrics methods (IPCA, VoC, KNS, 1/A,
5
+ factor-model tests, …), **extensible by design** so new methods plug in as first-class extensions.
6
+
7
+ **Documentation:** <https://py-numeraire.github.io/numeraire/>
8
+
9
+ The *numéraire* is the reference unit against which all prices are measured. Core stays
10
+ **representation-agnostic**: it defines *capabilities* (what a model can produce — weights, pricing,
11
+ …), never a specific method's internal form, so linear-factor, nonlinear/RFF, neural, and
12
+ distributional methods are all first-class.
13
+
14
+ ## Architecture (the boundary rule)
15
+
16
+ `numeraire.core` is exactly the modules that depend on no specific method and that every method
17
+ depends on. Dependency arrows point toward `core`; **`core` never imports a method, an adapter, or
18
+ a reference library.** This is enforced in CI by `import-linter` — the lint rule *is* the
19
+ architecture (see `pyproject.toml [tool.importlinter]`).
20
+
21
+ ```
22
+ src/numeraire/
23
+ core/ # spine: DataView/Estimator/Splitter/Evaluator protocols, capabilities,
24
+ # result schema, evaluator registry (stable, strict-typed, high-coverage)
25
+ adapters/ # thin wrappers making reference libraries conform to core — glue, not spine
26
+ methods/ # published methods bundled as extensions (VoC, 1/A, classical tests, …)
27
+ ```
28
+
29
+ Methods register via the `numeraire.methods` entry-point group, so external packages
30
+ (`numeraire-yourlab`, `numeraire-<method>`) are first-class peers without editing core.
31
+
32
+ ## Install
33
+
34
+ ```bash
35
+ uv sync --extra dev # dev environment
36
+ ```
37
+
38
+ Base install is the spine + native general evaluators only; method/adapter deps are extras.
39
+
40
+ ## Develop
41
+
42
+ ```bash
43
+ uv run ruff check . && uv run ruff format --check . # lint + format
44
+ uv run basedpyright src/numeraire/core # strict types on core
45
+ uv run lint-imports # architecture boundary
46
+ uv run pytest # tests (public/synthetic data only)
47
+ ```
48
+
49
+ ## Status
50
+
51
+ Pre-1.0, development. Usable via GitHub install; **not on PyPI yet** (the capability layer is
52
+ expected to crystallize once three real adapters land). The spine (`DataView`, walk-forward OOS
53
+ engine, `Splitter`, native evaluators) is in place; the first method (1/A conservative slope) is
54
+ wired end-to-end.
55
+
56
+ License: BSD-3-Clause. Never commit CRSP/WRDS/proprietary data or credentials (`data/`, `ref/`,
57
+ `.env` are git-ignored).
@@ -0,0 +1,5 @@
1
+ # Sphinx build output
2
+ _build/
3
+
4
+ # autosummary-generated stub pages (regenerated on every build)
5
+ api/generated/
File without changes
File without changes
@@ -0,0 +1,14 @@
1
+ # numeraire.adapters.skfolio_adapter
2
+
3
+ ```{eval-rst}
4
+ .. currentmodule:: numeraire.adapters.skfolio_adapter
5
+
6
+ .. automodule:: numeraire.adapters.skfolio_adapter
7
+ :no-members:
8
+
9
+ .. autosummary::
10
+ :toctree: generated
11
+ :nosignatures:
12
+
13
+ SkfolioWeights
14
+ ```
@@ -0,0 +1,20 @@
1
+ # numeraire.baselines
2
+
3
+ ```{eval-rst}
4
+ .. currentmodule:: numeraire.baselines
5
+
6
+ .. automodule:: numeraire.baselines
7
+ :no-members:
8
+
9
+ .. autosummary::
10
+ :toctree: generated
11
+ :nosignatures:
12
+
13
+ EqualWeight
14
+ MinVariance
15
+ MeanVariance
16
+ HistoricalMean
17
+ equal_weights
18
+ minimum_variance_weights
19
+ mean_variance_weights
20
+ ```
@@ -0,0 +1,15 @@
1
+ # numeraire.comparison
2
+
3
+ ```{eval-rst}
4
+ .. currentmodule:: numeraire.comparison
5
+
6
+ .. automodule:: numeraire.comparison
7
+ :no-members:
8
+
9
+ .. autosummary::
10
+ :toctree: generated
11
+ :nosignatures:
12
+
13
+ compare
14
+ ComparisonEntry
15
+ ```
@@ -0,0 +1,6 @@
1
+ # numeraire.core.capabilities
2
+
3
+ ```{eval-rst}
4
+ .. automodule:: numeraire.core.capabilities
5
+ :members:
6
+ ```
@@ -0,0 +1,20 @@
1
+ # numeraire.core.data
2
+
3
+ ```{eval-rst}
4
+ .. currentmodule:: numeraire.core.data
5
+
6
+ .. automodule:: numeraire.core.data
7
+ :no-members:
8
+
9
+ .. autosummary::
10
+ :toctree: generated
11
+ :nosignatures:
12
+
13
+ TimeSeriesView
14
+ CrossSectionView
15
+ FeatureBlock
16
+ VintagedBlock
17
+ CharBlock
18
+ PanelTensor
19
+ Block
20
+ ```
@@ -0,0 +1,23 @@
1
+ # numeraire.core.engine
2
+
3
+ ```{eval-rst}
4
+ .. currentmodule:: numeraire.core.engine
5
+
6
+ .. automodule:: numeraire.core.engine
7
+ :no-members:
8
+
9
+ .. autosummary::
10
+ :toctree: generated
11
+ :nosignatures:
12
+
13
+ walk_forward
14
+ walk_forward_panel
15
+ walk_forward_forecast
16
+ walk_forward_pricing
17
+ pricing_in_sample
18
+ config_hash
19
+ WeightsOutput
20
+ PanelWeightsOutput
21
+ ForecastOutput
22
+ PricingOutput
23
+ ```
@@ -0,0 +1,23 @@
1
+ # numeraire.core.evaluators
2
+
3
+ ```{eval-rst}
4
+ .. currentmodule:: numeraire.core.evaluators
5
+
6
+ .. automodule:: numeraire.core.evaluators
7
+ :no-members:
8
+
9
+ .. autosummary::
10
+ :toctree: generated
11
+ :nosignatures:
12
+
13
+ SharpeEvaluator
14
+ MeanReturnEvaluator
15
+ CEQEvaluator
16
+ AlphaEvaluator
17
+ StrategyReturnEvaluator
18
+ OOSR2Evaluator
19
+ SquaredErrorDiffEvaluator
20
+ ClarkWestEvaluator
21
+ CrossSectionalR2Evaluator
22
+ AverageAbsAlphaEvaluator
23
+ ```
@@ -0,0 +1,21 @@
1
+ # numeraire.core.protocols
2
+
3
+ ```{eval-rst}
4
+ .. currentmodule:: numeraire.core.protocols
5
+
6
+ .. automodule:: numeraire.core.protocols
7
+ :no-members:
8
+
9
+ .. autosummary::
10
+ :toctree: generated
11
+ :nosignatures:
12
+
13
+ DataView
14
+ Model
15
+ Estimator
16
+ Splitter
17
+ Evaluator
18
+ SupportsWeights
19
+ SupportsForecast
20
+ SupportsPricing
21
+ ```
@@ -0,0 +1,16 @@
1
+ # numeraire.core.registry
2
+
3
+ ```{eval-rst}
4
+ .. currentmodule:: numeraire.core.registry
5
+
6
+ .. automodule:: numeraire.core.registry
7
+ :no-members:
8
+
9
+ .. autosummary::
10
+ :toctree: generated
11
+ :nosignatures:
12
+
13
+ register_evaluator
14
+ get_evaluator
15
+ available_evaluators
16
+ ```
@@ -0,0 +1,6 @@
1
+ # numeraire.core.schema
2
+
3
+ ```{eval-rst}
4
+ .. automodule:: numeraire.core.schema
5
+ :members:
6
+ ```