Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
1d3f7b6
feat(meta): add show_versions() for environment diagnostics
quantbai Mar 24, 2026
79c1b7a
docs: add community templates and policies
quantbai Mar 24, 2026
eaaea03
docs: restructure documentation with clear separation of concerns
quantbai Mar 24, 2026
7e90d49
fix(ops): remove arbitrary 1e-10 zero guards
quantbai Mar 24, 2026
6d6d017
refactor(io): replace interval-based skeleton with union-based skeleton
quantbai Mar 24, 2026
095b4bb
fix(ci): correct import sort order in __init__.py
quantbai Mar 24, 2026
1e43a84
Merge pull request #5 from quantbai/feature/docs-and-zero-guard-removal
quantbai Mar 24, 2026
598b78d
feat: docs restructure, show_versions, pyright CI, remove 1e-10 zero …
quantbai Mar 24, 2026
dc87e8f
feat: docs restructure, show_versions, pyright CI, remove 1e-10 zero …
quantbai Mar 24, 2026
0180723
test: add oracle snapshot for column-factor refactor verification
quantbai Mar 25, 2026
7f1030b
refactor(core): rewrite Factor and Panel for column-based architecture
quantbai Mar 25, 2026
a7553a1
refactor(ops): migrate base.py to column-based architecture
quantbai Mar 25, 2026
cfd4c15
refactor(ops): migrate cross_sectional.py to column-based architecture
quantbai Mar 25, 2026
f99f947
refactor(ops): migrate math.py to column-based architecture
quantbai Mar 25, 2026
f69d034
refactor(ops): migrate timeseries.py to column-based architecture
quantbai Mar 25, 2026
7c04421
refactor(ops): migrate neutralization.py to column-based architecture
quantbai Mar 25, 2026
1c36344
refactor(ops): migrate _dev.py to column-based architecture
quantbai Mar 25, 2026
ed02c64
test: migrate all tests to column-based architecture
quantbai Mar 25, 2026
122c92a
fix(ops): include edge count in bucket column name to avoid collision
quantbai Mar 25, 2026
dbb5b4d
docs: update documentation for column-based Factor architecture
quantbai Mar 25, 2026
0bc9988
perf(core): add column-level memoization in Panel._add_col
quantbai Mar 25, 2026
26b318a
ci: add mypy/pytest/ruff cache dirs to .gitignore
quantbai Mar 25, 2026
41fc52e
release: bump version to 0.4.0
quantbai Mar 25, 2026
e348d4c
refactor: restructure for full 12-step quant pipeline
quantbai Mar 25, 2026
5361cd0
docs: update all documentation for 12-step pipeline architecture
quantbai Mar 25, 2026
3425fa9
docs(claude): add detailed next-steps roadmap for session continuity
quantbai Mar 25, 2026
96e9471
feat: column-based Factor architecture, 12-step pipeline, pyright CI …
quantbai Mar 25, 2026
06e2e64
docs: update project description
quantbai Mar 26, 2026
1fd92be
release: v0.4.0
quantbai Mar 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: Bug Report
description: Report incorrect behavior or numerical errors
labels: ["bug"]
body:
- type: textarea
id: description
attributes:
label: What happened?
description: Describe the bug. Include expected vs actual behavior.
placeholder: |
ts_mean([1, 2, 3], window=2) returns [None, None, 2.5]
Expected: [None, 1.5, 2.5]
validations:
required: true

- type: textarea
id: reproduction
attributes:
label: Reproducible Example
render: python
placeholder: |
from elvers import load, ts_mean

panel = load()
result = ts_mean(panel["close"], 5)
print(result.df)
validations:
required: true

- type: dropdown
id: numerical
attributes:
label: Does this affect numerical output?
options:
- "Yes -- incorrect numerical values"
- "No -- crash, wrong type, or other non-numerical issue"
validations:
required: true

- type: textarea
id: environment
attributes:
label: Environment
description: "Paste the output of: python -c \"import elvers; elvers.show_versions()\""
render: text
placeholder: |
--------Elvers---------
Elvers: 0.3.0
Polars: 1.37.0
Python: 3.12.0
Platform: Linux-6.1.0-x86_64
Architecture: x86_64
validations:
required: true
5 changes: 5 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Question
url: https://github.com/quantbai/elvers/discussions/new?category=q-a
about: Ask a question or start a discussion.
26 changes: 26 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Feature Request
description: Suggest an improvement or new capability
labels: ["enhancement"]
body:
- type: textarea
id: use_case
attributes:
label: Use Case
description: What problem does this solve?
placeholder: |
Computing returns requires verbose composition every time:
divide(ts_delta(close, 1), ts_delay(close, 1))
validations:
required: true

- type: textarea
id: proposed_api
attributes:
label: Proposed API
description: Show how it should work.
render: python
placeholder: |
from elvers import returns
ret = returns(close, window=1)
validations:
required: false
50 changes: 50 additions & 0 deletions .github/ISSUE_TEMPLATE/new_operator.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: New Operator
description: Propose a new operator
labels: ["new operator"]
body:
- type: input
id: name
attributes:
label: Operator Name
description: "Naming: ts_ for time-series, group_ for group ops, no prefix for cross-sectional."
placeholder: "ts_entropy"
validations:
required: true

- type: dropdown
id: module
attributes:
label: Module
options:
- "timeseries -- per-symbol rolling window"
- "cross_sectional -- across symbols per timestamp"
- "neutralization -- group operations"
- "math -- element-wise transforms"
- "base -- arithmetic and structural"
validations:
required: true

- type: textarea
id: definition
attributes:
label: Definition and Use Case
description: Mathematical formula and why this operator is useful.
placeholder: |
H(X) = -sum(p_i * log(p_i))
Measures randomness in a rolling window. Low entropy often precedes breakouts.
validations:
required: true

- type: textarea
id: example
attributes:
label: Example
description: Input and expected output.
render: python
placeholder: |
from elvers import load
panel = load()
result = ts_entropy(panel["close"], window=3)
print(result.df.head())
validations:
required: false
26 changes: 24 additions & 2 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,35 @@
- [ ] Bug fix (corrects incorrect behavior)
- [ ] New feature (new operator or functionality)
- [ ] Refactor (no behavior change)
- [ ] Numerical change (alters factor computation results) [BREAKING]
- [ ] Documentation only
- [ ] Numerical change (alters factor computation results) **[BREAKING]**

## Numerical Impact
<!-- If this changes numerical output, provide before/after factor statistics -->
<!-- If this changes numerical output, provide before/after comparison: -->
<!-- Before: ts_example([1,2,3], window=2) -> [None, 1.5, 2.5] -->
<!-- After: ts_example([1,2,3], window=2) -> [None, 1.0, 2.0] -->
<!-- If no numerical impact, write "No numerical impact" -->

## Testing
- [ ] Added or updated tests
- [ ] All tests pass (`pytest tests/ -v`)
- [ ] Lint passes (`ruff check elvers/`)
- [ ] Type check passes (`pyright elvers/`)

## New Operator Checklist
<!-- Delete this section if not adding a new operator -->
- [ ] Operator added to `ops/__init__.py` imports and `__all__`
- [ ] Docstring includes: description, parameters, return type, null behavior, warmup
- [ ] Divisions handle zero denominators (exact zero check or Inf → null via Factor)
- [ ] No Python loops in computation (Polars expressions only)
- [ ] Uses `ddof=0` for std/variance (population statistics)
- [ ] Uses `min_samples=window` for rolling operations
- [ ] Tests cover: basic correctness, null handling, edge cases
- [ ] `OPERATORS.md` updated with the new operator

## Reviewer Notes
<!-- For reviewers: -->
<!-- 1. Manually verify at least one expected value from the tests -->
<!-- 2. Check division-by-zero handling (exact zero check or Inf->null via Factor) -->
<!-- 3. Confirm no implicit Inf-to-null reliance -->
<!-- 4. For numerical changes: verify the before/after comparison above -->
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ jobs:
python-version: ${{ matrix.python-version }}
- run: pip install -e ".[dev]"
- run: ruff check elvers/
- run: pyright elvers/
- run: pytest tests/ -v
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,6 @@ venv/
*.swo
.DS_Store
.claude/
.mypy_cache/
.pytest_cache/
.ruff_cache/
30 changes: 25 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,27 @@ All notable changes to this project will be documented in this file.
Format follows [Keep a Changelog](https://keepachangelog.com/).
Numerical changes are marked with [NUMERICAL].

## [Unreleased]
## [0.4.0] - 2026-03-26

### Added
- `show_versions()` for environment diagnostics in bug reports
- Pyright static type checking in CI pipeline
- Community templates: issue templates (bug, feature, new operator), CODE_OF_CONDUCT, SECURITY
- CONTRIBUTING.md with workflow, numerical invariants, and design rationale
- Timestamp type validation in loader (must be pl.Date or pl.Datetime)
- `_check_intervals()` warns about irregular timestamp spacing
- `Panel.gc()` to drop intermediate columns
- `Panel.select()` to export specific factors

### Changed
- **Column-based Factor architecture.** Factor stores a column name + Panel reference instead of a full DataFrame. Eliminates all hash joins (24 removed), reduces memory by ~60% per Factor, ~2x faster on large panels. All data lives in Panel._df.
- [NUMERICAL] Removed arbitrary `1e-10` zero guards across all operators. Pure divisions (divide, inverse) now produce Inf → null via Panel._add_col. Statistical and regression operators use exact zero checks for degenerate cases (constant series).
- Replaced interval-based panel skeleton with union-based skeleton (no frequency inference)
- Restructured documentation: CLAUDE.md (AI memo), CONTRIBUTING.md (human guide), no duplication
- Removed `interval` parameter from `load()`
- Restructured into 12-step pipeline: core/, ops/, data/, universe/, analysis/, synthesis/, portfolio/, backtest/, risk/, execution/, monitor/
- Panel moved from io/ to core/. Loader moved from io/ to data/. Sample data moved to data/sample/
- Column-level memoization: _add_col skips computation if column already exists

## [0.3.0] - 2026-03-24

Expand All @@ -16,22 +36,22 @@ Numerical changes are marked with [NUMERICAL].

### Changed
- OPERATORS.md rewritten as pure operator reference manual (signatures, behavior, edge cases)
- Design rationale moved to CLAUDE.md Section 4.1 (developer-facing)
- Design rationale moved to CONTRIBUTING.md (Numerical Invariants section)
- Fixed incorrect signatures in docs: `trade_when`, `scale`, `bucket`
- Fixed README example code to use only columns present in sample data

## [0.2.0] - 2026-03-23

### Added
- CLAUDE.md development standards (12 sections covering full workflow)
- CLAUDE.md development memo (architecture map, conduct rules, known limitations)
- CI pipeline (GitHub Actions, pytest across Python 3.10-3.13)
- Automated release pipeline (tag-triggered PyPI publish + GitHub Release)
- Pre-commit hooks (ruff lint + format, pytest)
- PR template with numerical impact checklist
- Dev dependencies (pytest, ruff, pre-commit)
- `elvers/ops/_dev.py` for experimental operators
- `elvers/ops/_validation.py` input validation helpers
- `load()` now accepts `interval` parameter for sub-daily data (e.g., "1h", "5m")
- `load()` supports any time frequency; panel skeleton built from timestamps present in data
- Factor constructor validates required columns [timestamp, symbol, factor]
- Tests for `divide()`, `reverse()`, `ts_product` (negative/zero), `ts_regression` (lag>0)

Expand All @@ -42,7 +62,7 @@ Numerical changes are marked with [NUMERICAL].
- [NUMERICAL] `inverse()`: no zero protection; now returns null where abs(x) < 1e-10
- `ts_regression` rettype=7 (MSE): implicit Inf-to-null on window=2; now has explicit guard
- `ts_count_nans`: used min_samples=1 unlike all other ts_* operators; aligned to min_samples=window
- `_balance()`: hardcoded daily frequency; now accepts interval parameter
- `_balance()`: replaced generated-range skeleton with union-based skeleton (no frequency inference)

### Changed
- DEV operators (hump, ts_arg_max, ts_arg_min) moved from public API to `_dev.py`
Expand Down
Loading
Loading