|
4 | 4 |
|
5 | 5 | [](https://opensource.org/licenses/MIT) |
6 | 6 | [](https://www.python.org/downloads/) |
7 | | -[](https://pola.rs/) |
| 7 | +[](https://pola.rs/) |
8 | 8 |
|
9 | 9 | </div> |
10 | 10 |
|
11 | | -High-performance multi-factor quantitative framework built on Polars. |
| 11 | +**ELVERS** is a high-performance, strictly typed multi-factor alpha research engine powered by [Polars](https://pola.rs/). |
12 | 12 |
|
13 | | -Named after **ELVES**, the atmospheric lightning phenomenon that occurs at extreme speed. |
14 | 13 |
|
15 | | -## Features |
| 14 | +## Design Philosophy |
| 15 | + |
| 16 | +Quantitative research requires rapid iteration over large universe panels without compromising execution speed. Legacy pandas-based pipelines are interpretable but inherently scale poorly. elvers addresses this through a robust two-layer abstraction: |
| 17 | + |
| 18 | +- **`Panel`** — A continuous, balanced panel container enforcing strict `(timestamp, symbol)` alignment. It mitigates look-ahead bias and standardizes index integrity across all transformations. |
| 19 | +- **`Factor`** — A fully evaluated, eagerly executed vector of signal exposures. Bound directly to the global panel, factors resolve native Polars expressions instantaneously utilizing highly-parallelized core routines underneath Rust and C. |
| 20 | + |
| 21 | +The architecture guarantees that complex computational graphs—from primitive time-series aggregations to complex cross-sectional neutralizations—are resolved at theoretical hardware peaks with virtually zero Python interpreter overhead in the hot path. |
| 22 | + |
16 | 23 |
|
17 | | -- Pure Polars-based lazy evaluation |
18 | | -- Expression-based factor computation |
19 | | -- ~80x faster than pandas-based alternatives |
20 | | -- Professional-grade operators (time-series, cross-sectional, neutralization) |
21 | 24 |
|
22 | 25 | ## Installation |
23 | 26 |
|
24 | 27 | ```bash |
25 | 28 | pip install elvers |
26 | 29 | ``` |
27 | 30 |
|
| 31 | + |
| 32 | + |
28 | 33 | ## Quick Start |
| 34 | +Compose factors exactly as intuitively as they are expressed mathematically: |
29 | 35 |
|
30 | 36 | ```python |
31 | | -from elvers import load |
32 | | -from elvers import ts_rank, rank, zscore, group_neutralize |
| 37 | +from elvers import load, ts_rank, zscore |
33 | 38 |
|
34 | | -# 1. Load data into a managed Panel |
35 | | -panel = load("crypto_data.csv") |
| 39 | +# Load your own data |
| 40 | +# panel = load("your_ohlcv.csv") |
| 41 | + |
| 42 | +# Load built-in sample dataset |
| 43 | +panel = load() |
36 | 44 |
|
37 | | -# 2. Access factors via panel indexing |
38 | 45 | close = panel["close"] |
39 | 46 | volume = panel["volume"] |
40 | 47 |
|
41 | | -# 3. Define factors using professional operators |
| 48 | +# Define and execute expressions instantly |
42 | 49 | momentum = ts_rank(close, 20) |
43 | | -alpha = zscore(rank(momentum)) |
44 | | - |
45 | | -# 4. Advanced: Neutralization |
46 | | -# Neutralize alpha against volume groups |
47 | | -final_alpha = group_neutralize(alpha, panel["group"]) |
| 50 | +alpha = zscore(momentum) |
48 | 51 |
|
49 | | -# 5. Compute results |
50 | | -result = panel.collect(final_alpha) |
| 52 | +# Extract native Polars DataFrame |
| 53 | +result = alpha.df |
51 | 54 | print(result) |
52 | 55 | ``` |
53 | 56 |
|
54 | | -## License |
| 57 | +Both `Panel` and `Factor` expose a `.df` property that returns the underlying `pl.DataFrame`: |
| 58 | + |
| 59 | +- **`panel.df`** — Full panel frame with all OHLCV columns intact. |
| 60 | +- **`factor.df`** — Flat `(T_days * N_symbols, 3)` frame aligned to the original spatial coordinates: |
| 61 | + |
| 62 | +```text |
| 63 | +shape: (T_days * N_symbols, 3) |
| 64 | +┌────────────┬────────┬───────────┐ |
| 65 | +│ timestamp ┆ symbol ┆ factor │ |
| 66 | +│ --- ┆ --- ┆ --- │ |
| 67 | +│ date ┆ str ┆ f64 │ |
| 68 | +╞════════════╪════════╪═══════════╡ |
| 69 | +│ 2024-01-01 ┆ BTC ┆ null │ |
| 70 | +│ ... ┆ ... ┆ ... │ |
| 71 | +│ 2024-12-31 ┆ ETH ┆ 1.243 │ |
| 72 | +└────────────┴────────┴───────────┘ |
| 73 | +``` |
| 74 | + |
| 75 | +Rows are ordered by `timestamp` (ascending), then `symbol` (ascending). |
| 76 | + |
| 77 | +> **Note**: Rolling window operators naturally yield `null` for the initial `window - 1` periods per symbol. The full dense panel shape is preserved throughout all operations. |
55 | 78 |
|
56 | | -MIT License - see [LICENSE](LICENSE) for details. |
57 | 79 |
|
58 | | -## Author |
| 80 | +## Operator Library |
59 | 81 |
|
60 | | -quantbai |
| 82 | +| Category | Supported Operators | |
| 83 | +| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | |
| 84 | +| **Time-Series** | `ts_delay`, `ts_delta`, `ts_mean`, `ts_sum`, `ts_std_dev`, `ts_min`, `ts_max`, `ts_median`, `ts_rank`, `ts_skewness`, `ts_kurtosis`, `ts_zscore`, `ts_corr`, `ts_covariance`, `ts_product`, `ts_decay_linear`, `ts_av_diff`, `ts_scale`, `ts_quantile`, `ts_cv`, `ts_autocorr`, `ts_count_nans`, `ts_backfill` | |
| 85 | +| **Cross-Sectional** | `rank`, `zscore`, `mean`, `median`, `scale`, `normalize`, `signal` | |
| 86 | +| **Neutralization** | `vector_neut`, `regression_neut`, `group_neutralize`, `group_rank`, `group_zscore`, `group_scale`, `group_normalize` | |
| 87 | +| **Math** | `log`, `ln`, `sqrt`, `sign`, `power`, `signed_power`, `inverse`, `s_log_1p`, `maximum`, `minimum`, `where`, standard operators (`+`, `-`, `*`, `/`, `**`, `abs`) | |
61 | 88 |
|
62 | 89 |
|
0 commit comments