Skip to content

Commit 2b32772

Browse files
authored
Merge pull request #8 from quantbai/dev
Dev
2 parents efcfc0f + 1fd92be commit 2b32772

48 files changed

Lines changed: 1373 additions & 964 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
name: Bug Report
2+
description: Report incorrect behavior or numerical errors
3+
labels: ["bug"]
4+
body:
5+
- type: textarea
6+
id: description
7+
attributes:
8+
label: What happened?
9+
description: Describe the bug. Include expected vs actual behavior.
10+
placeholder: |
11+
ts_mean([1, 2, 3], window=2) returns [None, None, 2.5]
12+
Expected: [None, 1.5, 2.5]
13+
validations:
14+
required: true
15+
16+
- type: textarea
17+
id: reproduction
18+
attributes:
19+
label: Reproducible Example
20+
render: python
21+
placeholder: |
22+
from elvers import load, ts_mean
23+
24+
panel = load()
25+
result = ts_mean(panel["close"], 5)
26+
print(result.df)
27+
validations:
28+
required: true
29+
30+
- type: dropdown
31+
id: numerical
32+
attributes:
33+
label: Does this affect numerical output?
34+
options:
35+
- "Yes -- incorrect numerical values"
36+
- "No -- crash, wrong type, or other non-numerical issue"
37+
validations:
38+
required: true
39+
40+
- type: textarea
41+
id: environment
42+
attributes:
43+
label: Environment
44+
description: "Paste the output of: python -c \"import elvers; elvers.show_versions()\""
45+
render: text
46+
placeholder: |
47+
--------Elvers---------
48+
Elvers: 0.3.0
49+
Polars: 1.37.0
50+
Python: 3.12.0
51+
Platform: Linux-6.1.0-x86_64
52+
Architecture: x86_64
53+
validations:
54+
required: true

.github/ISSUE_TEMPLATE/config.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
blank_issues_enabled: false
2+
contact_links:
3+
- name: Question
4+
url: https://github.com/quantbai/elvers/discussions/new?category=q-a
5+
about: Ask a question or start a discussion.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: Feature Request
2+
description: Suggest an improvement or new capability
3+
labels: ["enhancement"]
4+
body:
5+
- type: textarea
6+
id: use_case
7+
attributes:
8+
label: Use Case
9+
description: What problem does this solve?
10+
placeholder: |
11+
Computing returns requires verbose composition every time:
12+
divide(ts_delta(close, 1), ts_delay(close, 1))
13+
validations:
14+
required: true
15+
16+
- type: textarea
17+
id: proposed_api
18+
attributes:
19+
label: Proposed API
20+
description: Show how it should work.
21+
render: python
22+
placeholder: |
23+
from elvers import returns
24+
ret = returns(close, window=1)
25+
validations:
26+
required: false
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
name: New Operator
2+
description: Propose a new operator
3+
labels: ["new operator"]
4+
body:
5+
- type: input
6+
id: name
7+
attributes:
8+
label: Operator Name
9+
description: "Naming: ts_ for time-series, group_ for group ops, no prefix for cross-sectional."
10+
placeholder: "ts_entropy"
11+
validations:
12+
required: true
13+
14+
- type: dropdown
15+
id: module
16+
attributes:
17+
label: Module
18+
options:
19+
- "timeseries -- per-symbol rolling window"
20+
- "cross_sectional -- across symbols per timestamp"
21+
- "neutralization -- group operations"
22+
- "math -- element-wise transforms"
23+
- "base -- arithmetic and structural"
24+
validations:
25+
required: true
26+
27+
- type: textarea
28+
id: definition
29+
attributes:
30+
label: Definition and Use Case
31+
description: Mathematical formula and why this operator is useful.
32+
placeholder: |
33+
H(X) = -sum(p_i * log(p_i))
34+
Measures randomness in a rolling window. Low entropy often precedes breakouts.
35+
validations:
36+
required: true
37+
38+
- type: textarea
39+
id: example
40+
attributes:
41+
label: Example
42+
description: Input and expected output.
43+
render: python
44+
placeholder: |
45+
from elvers import load
46+
panel = load()
47+
result = ts_entropy(panel["close"], window=3)
48+
print(result.df.head())
49+
validations:
50+
required: false

.github/pull_request_template.md

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,35 @@
55
- [ ] Bug fix (corrects incorrect behavior)
66
- [ ] New feature (new operator or functionality)
77
- [ ] Refactor (no behavior change)
8-
- [ ] Numerical change (alters factor computation results) [BREAKING]
8+
- [ ] Documentation only
9+
- [ ] Numerical change (alters factor computation results) **[BREAKING]**
910

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

1417
## Testing
1518
- [ ] Added or updated tests
1619
- [ ] All tests pass (`pytest tests/ -v`)
1720
- [ ] Lint passes (`ruff check elvers/`)
21+
- [ ] Type check passes (`pyright elvers/`)
22+
23+
## New Operator Checklist
24+
<!-- Delete this section if not adding a new operator -->
25+
- [ ] Operator added to `ops/__init__.py` imports and `__all__`
26+
- [ ] Docstring includes: description, parameters, return type, null behavior, warmup
27+
- [ ] Divisions handle zero denominators (exact zero check or Inf → null via Factor)
28+
- [ ] No Python loops in computation (Polars expressions only)
29+
- [ ] Uses `ddof=0` for std/variance (population statistics)
30+
- [ ] Uses `min_samples=window` for rolling operations
31+
- [ ] Tests cover: basic correctness, null handling, edge cases
32+
- [ ] `OPERATORS.md` updated with the new operator
33+
34+
## Reviewer Notes
35+
<!-- For reviewers: -->
36+
<!-- 1. Manually verify at least one expected value from the tests -->
37+
<!-- 2. Check division-by-zero handling (exact zero check or Inf->null via Factor) -->
38+
<!-- 3. Confirm no implicit Inf-to-null reliance -->
39+
<!-- 4. For numerical changes: verify the before/after comparison above -->

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,5 @@ jobs:
1919
python-version: ${{ matrix.python-version }}
2020
- run: pip install -e ".[dev]"
2121
- run: ruff check elvers/
22+
- run: pyright elvers/
2223
- run: pytest tests/ -v

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,6 @@ venv/
2828
*.swo
2929
.DS_Store
3030
.claude/
31+
.mypy_cache/
32+
.pytest_cache/
33+
.ruff_cache/

CHANGELOG.md

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,27 @@ All notable changes to this project will be documented in this file.
55
Format follows [Keep a Changelog](https://keepachangelog.com/).
66
Numerical changes are marked with [NUMERICAL].
77

8-
## [Unreleased]
8+
## [0.4.0] - 2026-03-26
9+
10+
### Added
11+
- `show_versions()` for environment diagnostics in bug reports
12+
- Pyright static type checking in CI pipeline
13+
- Community templates: issue templates (bug, feature, new operator), CODE_OF_CONDUCT, SECURITY
14+
- CONTRIBUTING.md with workflow, numerical invariants, and design rationale
15+
- Timestamp type validation in loader (must be pl.Date or pl.Datetime)
16+
- `_check_intervals()` warns about irregular timestamp spacing
17+
- `Panel.gc()` to drop intermediate columns
18+
- `Panel.select()` to export specific factors
19+
20+
### Changed
21+
- **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.
22+
- [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).
23+
- Replaced interval-based panel skeleton with union-based skeleton (no frequency inference)
24+
- Restructured documentation: CLAUDE.md (AI memo), CONTRIBUTING.md (human guide), no duplication
25+
- Removed `interval` parameter from `load()`
26+
- Restructured into 12-step pipeline: core/, ops/, data/, universe/, analysis/, synthesis/, portfolio/, backtest/, risk/, execution/, monitor/
27+
- Panel moved from io/ to core/. Loader moved from io/ to data/. Sample data moved to data/sample/
28+
- Column-level memoization: _add_col skips computation if column already exists
929

1030
## [0.3.0] - 2026-03-24
1131

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

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

2343
## [0.2.0] - 2026-03-23
2444

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

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

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

0 commit comments

Comments
 (0)