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.
- numeraire-0.2.0/.github/workflows/ci.yml +91 -0
- numeraire-0.2.0/.github/workflows/docs.yml +51 -0
- numeraire-0.2.0/.github/workflows/publish.yml +37 -0
- numeraire-0.2.0/.gitignore +29 -0
- numeraire-0.2.0/.pre-commit-config.yaml +24 -0
- numeraire-0.2.0/.python-version +1 -0
- numeraire-0.2.0/CHANGELOG.md +50 -0
- numeraire-0.2.0/LICENSE +28 -0
- numeraire-0.2.0/PKG-INFO +105 -0
- numeraire-0.2.0/README.md +57 -0
- numeraire-0.2.0/docs/.gitignore +5 -0
- numeraire-0.2.0/docs/_static/.gitkeep +0 -0
- numeraire-0.2.0/docs/_templates/.gitkeep +0 -0
- numeraire-0.2.0/docs/api/adapters.skfolio.md +14 -0
- numeraire-0.2.0/docs/api/baselines.md +20 -0
- numeraire-0.2.0/docs/api/comparison.md +15 -0
- numeraire-0.2.0/docs/api/core.capabilities.md +6 -0
- numeraire-0.2.0/docs/api/core.data.md +20 -0
- numeraire-0.2.0/docs/api/core.engine.md +23 -0
- numeraire-0.2.0/docs/api/core.evaluators.md +23 -0
- numeraire-0.2.0/docs/api/core.protocols.md +21 -0
- numeraire-0.2.0/docs/api/core.registry.md +16 -0
- numeraire-0.2.0/docs/api/core.schema.md +6 -0
- numeraire-0.2.0/docs/api/core.simulate.md +16 -0
- numeraire-0.2.0/docs/api/core.sorts.md +15 -0
- numeraire-0.2.0/docs/api/core.splitter.md +15 -0
- numeraire-0.2.0/docs/api/core.stats.md +27 -0
- numeraire-0.2.0/docs/api/index.md +91 -0
- numeraire-0.2.0/docs/api/numeraire.md +9 -0
- numeraire-0.2.0/docs/api/reference.md +7 -0
- numeraire-0.2.0/docs/api/testing.md +19 -0
- numeraire-0.2.0/docs/architecture.md +177 -0
- numeraire-0.2.0/docs/changelog.md +2 -0
- numeraire-0.2.0/docs/comparison.md +112 -0
- numeraire-0.2.0/docs/conf.py +77 -0
- numeraire-0.2.0/docs/extending.md +212 -0
- numeraire-0.2.0/docs/index.md +91 -0
- numeraire-0.2.0/docs/quickstart.md +169 -0
- numeraire-0.2.0/pyproject.toml +116 -0
- numeraire-0.2.0/src/numeraire/__init__.py +118 -0
- numeraire-0.2.0/src/numeraire/adapters/__init__.py +6 -0
- numeraire-0.2.0/src/numeraire/adapters/skfolio_adapter.py +105 -0
- numeraire-0.2.0/src/numeraire/baselines/__init__.py +39 -0
- numeraire-0.2.0/src/numeraire/baselines/forecast.py +64 -0
- numeraire-0.2.0/src/numeraire/baselines/weights.py +218 -0
- numeraire-0.2.0/src/numeraire/comparison.py +216 -0
- numeraire-0.2.0/src/numeraire/core/__init__.py +13 -0
- numeraire-0.2.0/src/numeraire/core/_ingest.py +63 -0
- numeraire-0.2.0/src/numeraire/core/capabilities.py +25 -0
- numeraire-0.2.0/src/numeraire/core/data.py +823 -0
- numeraire-0.2.0/src/numeraire/core/engine.py +610 -0
- numeraire-0.2.0/src/numeraire/core/evaluators.py +348 -0
- numeraire-0.2.0/src/numeraire/core/protocols.py +120 -0
- numeraire-0.2.0/src/numeraire/core/registry.py +32 -0
- numeraire-0.2.0/src/numeraire/core/schema.py +40 -0
- numeraire-0.2.0/src/numeraire/core/simulate.py +231 -0
- numeraire-0.2.0/src/numeraire/core/sorts.py +101 -0
- numeraire-0.2.0/src/numeraire/core/splitter.py +113 -0
- numeraire-0.2.0/src/numeraire/core/stats.py +385 -0
- numeraire-0.2.0/src/numeraire/methods/__init__.py +5 -0
- numeraire-0.2.0/src/numeraire/py.typed +0 -0
- numeraire-0.2.0/src/numeraire/reference.py +225 -0
- numeraire-0.2.0/src/numeraire/testing.py +401 -0
- numeraire-0.2.0/tests/conftest.py +203 -0
- numeraire-0.2.0/tests/test_baselines.py +188 -0
- numeraire-0.2.0/tests/test_char_blocks.py +131 -0
- numeraire-0.2.0/tests/test_comparison.py +259 -0
- numeraire-0.2.0/tests/test_cross_section_view.py +165 -0
- numeraire-0.2.0/tests/test_data.py +157 -0
- numeraire-0.2.0/tests/test_economic_value.py +121 -0
- numeraire-0.2.0/tests/test_engine.py +120 -0
- numeraire-0.2.0/tests/test_evaluators.py +179 -0
- numeraire-0.2.0/tests/test_ingest_seam.py +100 -0
- numeraire-0.2.0/tests/test_input_ingestion.py +219 -0
- numeraire-0.2.0/tests/test_multiblock_view.py +78 -0
- numeraire-0.2.0/tests/test_no_lookahead.py +150 -0
- numeraire-0.2.0/tests/test_no_lookahead_engine.py +119 -0
- numeraire-0.2.0/tests/test_panel_internals.py +163 -0
- numeraire-0.2.0/tests/test_parallel.py +152 -0
- numeraire-0.2.0/tests/test_pricing.py +296 -0
- numeraire-0.2.0/tests/test_reference.py +211 -0
- numeraire-0.2.0/tests/test_refit_and_validation.py +150 -0
- numeraire-0.2.0/tests/test_simulate.py +145 -0
- numeraire-0.2.0/tests/test_skfolio_adapter.py +109 -0
- numeraire-0.2.0/tests/test_sorts.py +93 -0
- numeraire-0.2.0/tests/test_spine.py +63 -0
- numeraire-0.2.0/tests/test_splitter.py +55 -0
- numeraire-0.2.0/tests/test_stats.py +258 -0
- numeraire-0.2.0/tests/test_testing.py +304 -0
- numeraire-0.2.0/tests/test_view_combinations.py +206 -0
- numeraire-0.2.0/tests/test_vintaged_block.py +70 -0
- numeraire-0.2.0/tests/test_walk_forward_panel.py +118 -0
- 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
|
numeraire-0.2.0/LICENSE
ADDED
|
@@ -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.
|
numeraire-0.2.0/PKG-INFO
ADDED
|
@@ -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).
|
|
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,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
|
+
```
|