Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
25 changes: 23 additions & 2 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,34 @@
- [ ] 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/`)

## 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 -->
11 changes: 7 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ Numerical changes are marked with [NUMERICAL].

## [Unreleased]

### Changed
- [NUMERICAL] Removed arbitrary `1e-10` zero guards across all operators. Pure divisions (divide, inverse) now flow through Factor constructor (Inf → null). Statistical and regression operators use exact zero checks for degenerate cases (constant series). No more silent data loss from legitimate small values.

## [0.3.0] - 2026-03-24

### Fixed
Expand All @@ -16,22 +19,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 +45,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