py-alpha-lib 0.1.0__tar.gz → 0.1.1__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.
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/.gitignore +2 -1
- py_alpha_lib-0.1.1/.nwa-config.yaml +20 -0
- py_alpha_lib-0.1.1/CHANGELOG.md +15 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/Cargo.lock +13 -13
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/Cargo.toml +3 -2
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/PKG-INFO +57 -22
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/README.md +53 -20
- py_alpha_lib-0.1.1/articles/001.md +157 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/build.rs +327 -74
- py_alpha_lib-0.1.1/examples/gtja191/al/__init__.py +78 -0
- py_alpha_lib-0.1.1/examples/gtja191/al/alpha191.py +2239 -0
- py_alpha_lib-0.1.1/examples/gtja191/al/alpha191_context.py +152 -0
- py_alpha_lib-0.1.1/examples/gtja191/alpha191.txt +191 -0
- py_alpha_lib-0.1.1/examples/gtja191/main.py +95 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/examples/wq101/al/__init__.py +2 -2
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/examples/wq101/pd_/__init__.py +2 -2
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/pyproject.toml +8 -1
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/python/alpha/__init__.py +3 -0
- py_alpha_lib-0.1.1/python/alpha/algo/__init__.py +6 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/python/alpha/algo/algo.py +3 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/python/alpha/algo/algo_gen.py +164 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/python/alpha/algo.md +8 -0
- py_alpha_lib-0.1.1/python/alpha/lang/__init__.py +4 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/python/alpha/lang/__main__.py +3 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/python/alpha/lang/to_python.py +4 -4
- py_alpha_lib-0.1.1/python/conftest.py +3 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/python/tests/test_grammar.py +3 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/python/tests/test_rank.py +3 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/python/tests/test_talib.py +3 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/python/tests/test_to_python.py +3 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/src/algo/context.rs +3 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/src/algo/cross.rs +3 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/src/algo/ema.rs +3 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/src/algo/error.rs +3 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/src/algo/extremum.rs +3 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/src/algo/ma.rs +3 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/src/algo/mod.rs +9 -0
- py_alpha_lib-0.1.1/src/algo/neutralize.rs +226 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/src/algo/rank.rs +128 -0
- py_alpha_lib-0.1.1/src/algo/returns.rs +137 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/src/algo/series.rs +3 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/src/algo/skip_nan_window.rs +3 -0
- py_alpha_lib-0.1.1/src/algo/slope.rs +284 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/src/algo/stats.rs +389 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/src/algo/stddev.rs +3 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/src/algo/sum.rs +197 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/src/lib.rs +3 -0
- py_alpha_lib-0.1.1/tests/usage.py +99 -0
- py_alpha_lib-0.1.1/tests/verify_sumif.py +45 -0
- py_alpha_lib-0.1.0/python/alpha/algo/__init__.py +0 -3
- py_alpha_lib-0.1.0/python/alpha/algo/algo.md +0 -98
- py_alpha_lib-0.1.0/python/alpha/lang/__init__.py +0 -1
- py_alpha_lib-0.1.0/python/conftest.py +0 -0
- py_alpha_lib-0.1.0/tests/usage.py +0 -24
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/.agent/skills/add_algo.md +0 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/.github/workflows/CI.yml +0 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/LICENSE +0 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/examples/wq101/al/alpha101.py +0 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/examples/wq101/al/alpha101_context.py +0 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/examples/wq101/alpha101.txt +0 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/examples/wq101/main.py +0 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/examples/wq101/pd_/alpha101_adjusted.py +0 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/examples/wq101/result.md +0 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/python/alpha/lang/alpha.lark +0 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/python/alpha/lang/parser.py +0 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/rustfmt.toml +0 -0
- {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/tests/rank.py +0 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
nwa:
|
|
2
|
+
# basic
|
|
3
|
+
cmd: "add" # Default: "add"; Can be overwritten by --command (-c) flag; Optional: "add", "check", "remove", "update"
|
|
4
|
+
holder: "MSD-RS Project LiJia" # Default: "<COPYRIGHT HOLDER>"
|
|
5
|
+
year: "2026" # Default: Current Year
|
|
6
|
+
license: "BSD-2-Clause" # Default: "apache"
|
|
7
|
+
spdxids: "BSD-2-Clause" # Default: ""
|
|
8
|
+
skip: # Default: []
|
|
9
|
+
- ".venv/**"
|
|
10
|
+
path: # Default: []
|
|
11
|
+
- "src/**/*.rs"
|
|
12
|
+
- "python/**/*.py"
|
|
13
|
+
# advanced
|
|
14
|
+
mute: false # Default: false (unspecified)
|
|
15
|
+
verbose: false # Default: false (unspecified)
|
|
16
|
+
fuzzy: false # Default: false (unspecified); Used for "check" and "remove" commands
|
|
17
|
+
tmpltype: "" # Default: ""; Optional: "live", "static", "raw"
|
|
18
|
+
tmpl: "" # Default: ""
|
|
19
|
+
keyword: [] # Default: []; Used for "add" and "update" commands
|
|
20
|
+
style: []
|
|
@@ -4,7 +4,7 @@ version = 4
|
|
|
4
4
|
|
|
5
5
|
[[package]]
|
|
6
6
|
name = "alpha"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.1"
|
|
8
8
|
dependencies = [
|
|
9
9
|
"anyhow",
|
|
10
10
|
"log",
|
|
@@ -180,24 +180,24 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
|
|
180
180
|
|
|
181
181
|
[[package]]
|
|
182
182
|
name = "portable-atomic"
|
|
183
|
-
version = "1.13.
|
|
183
|
+
version = "1.13.1"
|
|
184
184
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
185
|
-
checksum = "
|
|
185
|
+
checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
|
|
186
186
|
|
|
187
187
|
[[package]]
|
|
188
188
|
name = "portable-atomic-util"
|
|
189
|
-
version = "0.2.
|
|
189
|
+
version = "0.2.5"
|
|
190
190
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
191
|
-
checksum = "
|
|
191
|
+
checksum = "7a9db96d7fa8782dd8c15ce32ffe8680bbd1e978a43bf51a34d39483540495f5"
|
|
192
192
|
dependencies = [
|
|
193
193
|
"portable-atomic",
|
|
194
194
|
]
|
|
195
195
|
|
|
196
196
|
[[package]]
|
|
197
197
|
name = "proc-macro2"
|
|
198
|
-
version = "1.0.
|
|
198
|
+
version = "1.0.106"
|
|
199
199
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
200
|
-
checksum = "
|
|
200
|
+
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
|
201
201
|
dependencies = [
|
|
202
202
|
"unicode-ident",
|
|
203
203
|
]
|
|
@@ -276,9 +276,9 @@ dependencies = [
|
|
|
276
276
|
|
|
277
277
|
[[package]]
|
|
278
278
|
name = "quote"
|
|
279
|
-
version = "1.0.
|
|
279
|
+
version = "1.0.44"
|
|
280
280
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
281
|
-
checksum = "
|
|
281
|
+
checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4"
|
|
282
282
|
dependencies = [
|
|
283
283
|
"proc-macro2",
|
|
284
284
|
]
|
|
@@ -340,18 +340,18 @@ checksum = "b1dd07eb858a2067e2f3c7155d54e929265c264e6f37efe3ee7a8d1b5a1dd0ba"
|
|
|
340
340
|
|
|
341
341
|
[[package]]
|
|
342
342
|
name = "thiserror"
|
|
343
|
-
version = "2.0.
|
|
343
|
+
version = "2.0.18"
|
|
344
344
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
345
|
-
checksum = "
|
|
345
|
+
checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
|
|
346
346
|
dependencies = [
|
|
347
347
|
"thiserror-impl",
|
|
348
348
|
]
|
|
349
349
|
|
|
350
350
|
[[package]]
|
|
351
351
|
name = "thiserror-impl"
|
|
352
|
-
version = "2.0.
|
|
352
|
+
version = "2.0.18"
|
|
353
353
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
354
|
-
checksum = "
|
|
354
|
+
checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
|
|
355
355
|
dependencies = [
|
|
356
356
|
"proc-macro2",
|
|
357
357
|
"quote",
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "alpha"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.1"
|
|
4
4
|
edition = "2024"
|
|
5
|
+
authors = ["ElseJJ"]
|
|
5
6
|
readme = "README.md"
|
|
6
7
|
|
|
7
8
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
@@ -10,7 +11,7 @@ name = "alpha"
|
|
|
10
11
|
crate-type = ["cdylib", "rlib"]
|
|
11
12
|
|
|
12
13
|
[dependencies]
|
|
13
|
-
pyo3 = {version = "0.27.0", features = ["abi3"]}
|
|
14
|
+
pyo3 = { version = "0.27.0", features = ["abi3"] }
|
|
14
15
|
pyo3-log = "0.13"
|
|
15
16
|
thiserror = "2"
|
|
16
17
|
numpy = "0.27.0"
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: py-alpha-lib
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Classifier: Programming Language :: Rust
|
|
5
5
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
6
6
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
7
7
|
Requires-Dist: numpy>=2
|
|
8
8
|
License-File: LICENSE
|
|
9
9
|
Summary: Alpha Library: A high-performance rolling window calculation library implemented in Rust with Python bindings. Used for financial data analysis and factor research.
|
|
10
|
-
|
|
10
|
+
Keywords: financial data analysis,factor research,technical indicator calculation
|
|
11
|
+
Author: ElseJJ
|
|
11
12
|
Requires-Python: >=3.11
|
|
12
13
|
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
14
|
+
Project-URL: repository, https://github.com/msd-rs/py-alpha-lib
|
|
13
15
|
|
|
14
16
|
# Introduction
|
|
15
17
|
|
|
@@ -21,25 +23,40 @@ For financial data analysis, there are many algorithms required a rolling window
|
|
|
21
23
|
|
|
22
24
|
| Name | Description | Ref Link |
|
|
23
25
|
| ---------- | ------------------------------------------------------------ | ----------------------------------------------------------------------- |
|
|
24
|
-
| BARSLAST |
|
|
25
|
-
| BARSSINCE |
|
|
26
|
-
|
|
|
27
|
-
|
|
|
28
|
-
|
|
|
29
|
-
|
|
|
30
|
-
|
|
|
31
|
-
|
|
|
32
|
-
|
|
|
33
|
-
|
|
|
34
|
-
|
|
|
35
|
-
|
|
|
36
|
-
|
|
|
37
|
-
|
|
|
38
|
-
|
|
|
39
|
-
|
|
|
40
|
-
|
|
|
41
|
-
|
|
|
42
|
-
|
|
|
26
|
+
| BARSLAST | Calculate number of bars since last condition true | https://www.amibroker.com/guide/afl/barslast.html |
|
|
27
|
+
| BARSSINCE | Calculate number of bars since first condition true | https://www.amibroker.com/guide/afl/barssince.html |
|
|
28
|
+
| BINS | Discretize the input into n bins, the ctx.groups() is the number of groups Bins are 0-based index. Same value are assigned to the same bin. | |
|
|
29
|
+
| CORR | Calculate Correlation over a moving window Correlation = Cov(X, Y) / (StdDev(X) * StdDev(Y)) | |
|
|
30
|
+
| COUNT | Calculate number of periods where condition is true in passed `periods` window | https://www.amibroker.com/guide/afl/count.html |
|
|
31
|
+
| COV | Calculate Covariance over a moving window Covariance = (SumXY - (SumX * SumY) / N) / (N - 1) | |
|
|
32
|
+
| CROSS | For 2 arrays A and B, return true if A[i-1] < B[i-1] and A[i] >= B[i] alias: golden_cross, cross_ge | https://www.amibroker.com/guide/afl/cross.html |
|
|
33
|
+
| DMA | Exponential Moving Average current = weight * current + (1 - weight) * previous | https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average |
|
|
34
|
+
| EMA | Exponential Moving Average (variant of well-known EMA) weight = 2 / (n + 1) | https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average |
|
|
35
|
+
| FRET | Future Return Calculates the return from the open price of the delayed day (t+delay) to the close price of the future day (t+delay+periods-1). Return = (Close[t+delay+periods-1] - Open[t+delay]) / Open[t+delay] If n=1, delay=1, it calculates (Close[t+1] - Open[t+1]) / Open[t+1]. If `is_calc[t+delay]` is 0, returns NaN. | |
|
|
36
|
+
| HHV | Find highest value in a preceding `periods` window | https://www.amibroker.com/guide/afl/hhv.html |
|
|
37
|
+
| HHVBARS | The number of periods that have passed since the array reached its `periods` period high | https://www.amibroker.com/guide/afl/hhvbars.html |
|
|
38
|
+
| INTERCEPT | Linear Regression Intercept Calculates the intercept of the linear regression line for a moving window. | |
|
|
39
|
+
| LLV | Find lowest value in a preceding `periods` window | https://www.amibroker.com/guide/afl/llv.html |
|
|
40
|
+
| LLVBARS | The number of periods that have passed since the array reached its periods period low | https://www.amibroker.com/guide/afl/llvbars.html |
|
|
41
|
+
| LONGCROSS | For 2 arrays A and B, return true if previous N periods A < B, Current A >= B | |
|
|
42
|
+
| LWMA | Linear Weighted Moving Average LWMA = SUM(Price * Weight) / SUM(Weight) | |
|
|
43
|
+
| MA | Simple Moving Average, also known as arithmetic moving average | https://en.wikipedia.org/wiki/Moving_average#Simple_moving_average |
|
|
44
|
+
| NEUTRALIZE | Neutralize the effect of a categorical variable on a numeric variable | |
|
|
45
|
+
| PRODUCT | Calculate product of values in preceding `periods` window If periods is 0, it calculates the cumulative product from the first valid value. | |
|
|
46
|
+
| RANK | Calculate rank percentage cross group dimension, the ctx.groups() is the number of groups Same value are averaged | |
|
|
47
|
+
| RCROSS | For 2 arrays A and B, return true if A[i-1] > B[i-1] and A[i] <= B[i] alias: death_cross, cross_le | |
|
|
48
|
+
| REF | Right shift input array by `periods`, r[i] = input[i - periods] | https://www.amibroker.com/guide/afl/ref.html |
|
|
49
|
+
| REGBETA | Calculate Regression Coefficient (Beta) of Y on X over a moving window Beta = Cov(X, Y) / Var(X) | |
|
|
50
|
+
| REGRESI | Calculate Regression Residual of Y on X over a moving window Returns the residual of the last point: epsilon = Y - (alpha + beta * X) | |
|
|
51
|
+
| RLONGCROSS | For 2 arrays A and B, return true if previous N periods A > B, Current A <= B | |
|
|
52
|
+
| SLOPE | Linear Regression Slope Calculates the slope of the linear regression line for a moving window. | |
|
|
53
|
+
| SMA | Exponential Moving Average (variant of well-known EMA) weight = m / n | https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average |
|
|
54
|
+
| STDDEV | Calculate Standard Deviation over a moving window | |
|
|
55
|
+
| SUM | Calculate sum of values in preceding `periods` window If periods is 0, it calculates the cumulative sum from the first valid value. | https://www.amibroker.com/guide/afl/sum.html |
|
|
56
|
+
| SUMBARS | Calculate number of periods (bars) backwards until the sum of values is greater than or equal to `amount` | https://www.amibroker.com/guide/afl/sumbars.html |
|
|
57
|
+
| SUMIF | Calculate sum of values in preceding `periods` window where `condition` is true | |
|
|
58
|
+
| TS_RANK | Calculate rank in a sliding window with size `periods` | |
|
|
59
|
+
| VAR | Calculate Variance over a moving window Variance = (SumSq - (Sum^2)/N) / (N - 1) | |
|
|
43
60
|
|
|
44
61
|
# Usage
|
|
45
62
|
|
|
@@ -72,7 +89,7 @@ print(result)
|
|
|
72
89
|
|
|
73
90
|
# Calculate 3-period exponential moving average, skipping NaN values
|
|
74
91
|
al.set_ctx(flags=al.FLAG_SKIP_NAN)
|
|
75
|
-
data_with_nan = [1, 2, None, 4, 5, 6, 7, 8, 9, 10]
|
|
92
|
+
data_with_nan = np.array([1, 2, None, 4, 5, 6, 7, 8, 9, 10], dtype=np.float64)
|
|
76
93
|
result = al.MA(data_with_nan, 3)
|
|
77
94
|
print(result)
|
|
78
95
|
# Output: [1. 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5]
|
|
@@ -94,6 +111,10 @@ You may notice that some functions have different behaviors based on the context
|
|
|
94
111
|
- `FLAG_STRICTLY_CYCLE`: When this flag is set, functions will strictly cycle over the data, meaning that initial periods that do not have enough data will be filled with NaN.
|
|
95
112
|
- You can combine multiple flags using bitwise OR operation, e.g., `flags=FLAG_SKIP_NAN | FLAG_STRICTLY_CYCLE`.
|
|
96
113
|
|
|
114
|
+
## Vibe Coding
|
|
115
|
+
|
|
116
|
+
When you need LLM to help you implement new factor in python, you can let LLM known which functions are available in `alpha-lib` by providing [the list of supported functions](python/alpha/algo.md) as context.
|
|
117
|
+
|
|
97
118
|
## Factor expression to Python code
|
|
98
119
|
|
|
99
120
|
You can convert factor expressions to Python code using the `lang` module. For example:
|
|
@@ -186,3 +207,17 @@ The hardware/soft environment is:
|
|
|
186
207
|
| #013 | 446 | 9 | 49 | 8 | -0.58 | -0.58 |
|
|
187
208
|
| #014 | 398 | 8 | 49 | 18 | 0.095449 | 0.095449 |
|
|
188
209
|
|
|
210
|
+
# Development
|
|
211
|
+
|
|
212
|
+
To contribute to the development of `alpha-lib`, you can clone the repository and set up a development environment.
|
|
213
|
+
|
|
214
|
+
Toolchain requirements:
|
|
215
|
+
|
|
216
|
+
- Rust (latest stable)
|
|
217
|
+
- Python (3.11+)
|
|
218
|
+
- [maturin](https://github.com/PyO3/maturin) (for building Python bindings)
|
|
219
|
+
|
|
220
|
+
## Vibe Coding
|
|
221
|
+
|
|
222
|
+
This project is co-created with `Gemini-3.0-Pro` , when you want add new algo, use skill [add_algo.md](.agent/skills/add_algo.md) let AI to do correct code change for you.
|
|
223
|
+
|
|
@@ -8,25 +8,40 @@ For financial data analysis, there are many algorithms required a rolling window
|
|
|
8
8
|
|
|
9
9
|
| Name | Description | Ref Link |
|
|
10
10
|
| ---------- | ------------------------------------------------------------ | ----------------------------------------------------------------------- |
|
|
11
|
-
| BARSLAST |
|
|
12
|
-
| BARSSINCE |
|
|
13
|
-
|
|
|
14
|
-
|
|
|
15
|
-
|
|
|
16
|
-
|
|
|
17
|
-
|
|
|
18
|
-
|
|
|
19
|
-
|
|
|
20
|
-
|
|
|
21
|
-
|
|
|
22
|
-
|
|
|
23
|
-
|
|
|
24
|
-
|
|
|
25
|
-
|
|
|
26
|
-
|
|
|
27
|
-
|
|
|
28
|
-
|
|
|
29
|
-
|
|
|
11
|
+
| BARSLAST | Calculate number of bars since last condition true | https://www.amibroker.com/guide/afl/barslast.html |
|
|
12
|
+
| BARSSINCE | Calculate number of bars since first condition true | https://www.amibroker.com/guide/afl/barssince.html |
|
|
13
|
+
| BINS | Discretize the input into n bins, the ctx.groups() is the number of groups Bins are 0-based index. Same value are assigned to the same bin. | |
|
|
14
|
+
| CORR | Calculate Correlation over a moving window Correlation = Cov(X, Y) / (StdDev(X) * StdDev(Y)) | |
|
|
15
|
+
| COUNT | Calculate number of periods where condition is true in passed `periods` window | https://www.amibroker.com/guide/afl/count.html |
|
|
16
|
+
| COV | Calculate Covariance over a moving window Covariance = (SumXY - (SumX * SumY) / N) / (N - 1) | |
|
|
17
|
+
| CROSS | For 2 arrays A and B, return true if A[i-1] < B[i-1] and A[i] >= B[i] alias: golden_cross, cross_ge | https://www.amibroker.com/guide/afl/cross.html |
|
|
18
|
+
| DMA | Exponential Moving Average current = weight * current + (1 - weight) * previous | https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average |
|
|
19
|
+
| EMA | Exponential Moving Average (variant of well-known EMA) weight = 2 / (n + 1) | https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average |
|
|
20
|
+
| FRET | Future Return Calculates the return from the open price of the delayed day (t+delay) to the close price of the future day (t+delay+periods-1). Return = (Close[t+delay+periods-1] - Open[t+delay]) / Open[t+delay] If n=1, delay=1, it calculates (Close[t+1] - Open[t+1]) / Open[t+1]. If `is_calc[t+delay]` is 0, returns NaN. | |
|
|
21
|
+
| HHV | Find highest value in a preceding `periods` window | https://www.amibroker.com/guide/afl/hhv.html |
|
|
22
|
+
| HHVBARS | The number of periods that have passed since the array reached its `periods` period high | https://www.amibroker.com/guide/afl/hhvbars.html |
|
|
23
|
+
| INTERCEPT | Linear Regression Intercept Calculates the intercept of the linear regression line for a moving window. | |
|
|
24
|
+
| LLV | Find lowest value in a preceding `periods` window | https://www.amibroker.com/guide/afl/llv.html |
|
|
25
|
+
| LLVBARS | The number of periods that have passed since the array reached its periods period low | https://www.amibroker.com/guide/afl/llvbars.html |
|
|
26
|
+
| LONGCROSS | For 2 arrays A and B, return true if previous N periods A < B, Current A >= B | |
|
|
27
|
+
| LWMA | Linear Weighted Moving Average LWMA = SUM(Price * Weight) / SUM(Weight) | |
|
|
28
|
+
| MA | Simple Moving Average, also known as arithmetic moving average | https://en.wikipedia.org/wiki/Moving_average#Simple_moving_average |
|
|
29
|
+
| NEUTRALIZE | Neutralize the effect of a categorical variable on a numeric variable | |
|
|
30
|
+
| PRODUCT | Calculate product of values in preceding `periods` window If periods is 0, it calculates the cumulative product from the first valid value. | |
|
|
31
|
+
| RANK | Calculate rank percentage cross group dimension, the ctx.groups() is the number of groups Same value are averaged | |
|
|
32
|
+
| RCROSS | For 2 arrays A and B, return true if A[i-1] > B[i-1] and A[i] <= B[i] alias: death_cross, cross_le | |
|
|
33
|
+
| REF | Right shift input array by `periods`, r[i] = input[i - periods] | https://www.amibroker.com/guide/afl/ref.html |
|
|
34
|
+
| REGBETA | Calculate Regression Coefficient (Beta) of Y on X over a moving window Beta = Cov(X, Y) / Var(X) | |
|
|
35
|
+
| REGRESI | Calculate Regression Residual of Y on X over a moving window Returns the residual of the last point: epsilon = Y - (alpha + beta * X) | |
|
|
36
|
+
| RLONGCROSS | For 2 arrays A and B, return true if previous N periods A > B, Current A <= B | |
|
|
37
|
+
| SLOPE | Linear Regression Slope Calculates the slope of the linear regression line for a moving window. | |
|
|
38
|
+
| SMA | Exponential Moving Average (variant of well-known EMA) weight = m / n | https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average |
|
|
39
|
+
| STDDEV | Calculate Standard Deviation over a moving window | |
|
|
40
|
+
| SUM | Calculate sum of values in preceding `periods` window If periods is 0, it calculates the cumulative sum from the first valid value. | https://www.amibroker.com/guide/afl/sum.html |
|
|
41
|
+
| SUMBARS | Calculate number of periods (bars) backwards until the sum of values is greater than or equal to `amount` | https://www.amibroker.com/guide/afl/sumbars.html |
|
|
42
|
+
| SUMIF | Calculate sum of values in preceding `periods` window where `condition` is true | |
|
|
43
|
+
| TS_RANK | Calculate rank in a sliding window with size `periods` | |
|
|
44
|
+
| VAR | Calculate Variance over a moving window Variance = (SumSq - (Sum^2)/N) / (N - 1) | |
|
|
30
45
|
|
|
31
46
|
# Usage
|
|
32
47
|
|
|
@@ -59,7 +74,7 @@ print(result)
|
|
|
59
74
|
|
|
60
75
|
# Calculate 3-period exponential moving average, skipping NaN values
|
|
61
76
|
al.set_ctx(flags=al.FLAG_SKIP_NAN)
|
|
62
|
-
data_with_nan = [1, 2, None, 4, 5, 6, 7, 8, 9, 10]
|
|
77
|
+
data_with_nan = np.array([1, 2, None, 4, 5, 6, 7, 8, 9, 10], dtype=np.float64)
|
|
63
78
|
result = al.MA(data_with_nan, 3)
|
|
64
79
|
print(result)
|
|
65
80
|
# Output: [1. 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5]
|
|
@@ -81,6 +96,10 @@ You may notice that some functions have different behaviors based on the context
|
|
|
81
96
|
- `FLAG_STRICTLY_CYCLE`: When this flag is set, functions will strictly cycle over the data, meaning that initial periods that do not have enough data will be filled with NaN.
|
|
82
97
|
- You can combine multiple flags using bitwise OR operation, e.g., `flags=FLAG_SKIP_NAN | FLAG_STRICTLY_CYCLE`.
|
|
83
98
|
|
|
99
|
+
## Vibe Coding
|
|
100
|
+
|
|
101
|
+
When you need LLM to help you implement new factor in python, you can let LLM known which functions are available in `alpha-lib` by providing [the list of supported functions](python/alpha/algo.md) as context.
|
|
102
|
+
|
|
84
103
|
## Factor expression to Python code
|
|
85
104
|
|
|
86
105
|
You can convert factor expressions to Python code using the `lang` module. For example:
|
|
@@ -172,3 +191,17 @@ The hardware/soft environment is:
|
|
|
172
191
|
| #012 | 4 | 4 | 1 | 0.7 | -17.012321 | -17.012321 |
|
|
173
192
|
| #013 | 446 | 9 | 49 | 8 | -0.58 | -0.58 |
|
|
174
193
|
| #014 | 398 | 8 | 49 | 18 | 0.095449 | 0.095449 |
|
|
194
|
+
|
|
195
|
+
# Development
|
|
196
|
+
|
|
197
|
+
To contribute to the development of `alpha-lib`, you can clone the repository and set up a development environment.
|
|
198
|
+
|
|
199
|
+
Toolchain requirements:
|
|
200
|
+
|
|
201
|
+
- Rust (latest stable)
|
|
202
|
+
- Python (3.11+)
|
|
203
|
+
- [maturin](https://github.com/PyO3/maturin) (for building Python bindings)
|
|
204
|
+
|
|
205
|
+
## Vibe Coding
|
|
206
|
+
|
|
207
|
+
This project is co-created with `Gemini-3.0-Pro` , when you want add new algo, use skill [add_algo.md](.agent/skills/add_algo.md) let AI to do correct code change for you.
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# 告别 Pandas 性能焦虑:基于 Rust 的高性能量化因子库 py-alpha-lib 推荐
|
|
2
|
+
|
|
3
|
+
在量化投资研究中,**因子计算(Factor Research)** 是最耗时也最核心的环节之一。
|
|
4
|
+
|
|
5
|
+
大多数宽客(Quant)习惯使用 Pandas 来编写因子逻辑,但当你面对日频、分钟频甚至高频数据时,Pandas 的滚动窗口(Rolling Window)计算速度往往会成为瓶颈。虽然 DolphinDB 很快,但它有学习成本且部署相对重头。
|
|
6
|
+
|
|
7
|
+
最近在 GitHub 上发现了一个非常惊艳的开源库:**[py-alpha-lib](https://github.com/msd-rs/py-alpha-lib)**。它用 **Rust** 重新实现了底层的滚动窗口算法,并通过 Python 绑定供我们调用。实测性能比 Pandas 快了几个数量级.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
### 一、 核心亮点:为什么选它?
|
|
12
|
+
|
|
13
|
+
#### 1. 极致的性能(Rust 驱动)
|
|
14
|
+
|
|
15
|
+
`py-alpha-lib` 的底层逻辑全部由 Rust 编写。Rust 天生具备极致的内存安全和并行能力。根据 README 披露的 Benchmark,在 4000 只股票、261 个交易日(共约 104 万个数据点)的测试中:
|
|
16
|
+
|
|
17
|
+
- **Alpha #001:** Pandas 耗时 14231ms,而 `alpha-lib` 仅需 **7ms**(提速 2000+ 倍)。
|
|
18
|
+
- **Alpha #004:** Pandas 耗时 55107ms,而 `alpha-lib` 仅需 **6ms**(提速 9000+ 倍)。
|
|
19
|
+
|
|
20
|
+
这种性能提升意味着,原本需要跑一个小时的因子回测,现在几秒钟就能出结果。
|
|
21
|
+
|
|
22
|
+
#### 2. 丰富的量化算法库
|
|
23
|
+
|
|
24
|
+
它实现了一些类似 AmiBroker (AFL) 或 DolphinDB 中的经典金融计算函数, 并会持续扩充:
|
|
25
|
+
|
|
26
|
+
- **趋势类:** `MA`, `EMA`, `SMA`, `DMA`
|
|
27
|
+
- **极值类:** `HHV` (最高值), `LLV` (最低值), `HHVBARS`
|
|
28
|
+
- **逻辑类:** `CROSS` (金叉/死叉), `BARSLAST` (自上次条件成立以来的周期数)
|
|
29
|
+
- **截面/分组:** 支持 `RANK` (截面排序) 和 `TS_RANK` (时序排序)
|
|
30
|
+
|
|
31
|
+
#### 3. 原生支持多股并行(Context 机制)
|
|
32
|
+
|
|
33
|
+
在处理多只股票的数据时,使用 Pandas 往往需要 `pivot` 或 `groupby`,这中数据的准备是比较耗时和消耗内存的, 然后在计算时又无法充分利用多核 CPU。
|
|
34
|
+
|
|
35
|
+
`py-alpha-lib` 使用一个长数组, 这是多只股票数据最高效的数据结构。然后通过 `set_ctx` :
|
|
36
|
+
|
|
37
|
+
- 你可以设置 `groups`,库会自动将大数组切分成多个并行任务。
|
|
38
|
+
- 每个股票(Group)独立计算,互不干扰,完美利用多核 CPU。
|
|
39
|
+
|
|
40
|
+
#### 4. 因子表达式编译器
|
|
41
|
+
|
|
42
|
+
这是我觉得最酷的功能。它自带一个 `alpha.lang` 模块,可以将 WorldQuant 101 等因子表达式直接编译成 Python 代码。
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
python -m alpha.lang alpha101.txt
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
这对于批量复现论文因子简直是神器。
|
|
50
|
+
|
|
51
|
+
例如, 对于因子 #001:`(rank(Ts_ArgMax(SignedPower(((returns < 0) ? stddev(returns, 20) : close), 2.), 5)) -0.5)`,编译后会生成如下 Python 代码:
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
import numpy as np
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
# (rank(Ts_ArgMax(SignedPower(((returns < 0) ? stddev(returns, 20) : close), 2.), 5)) -0.5)
|
|
58
|
+
def alpha_001(ctx):
|
|
59
|
+
_RETURNS = ctx("RETURNS")
|
|
60
|
+
return (
|
|
61
|
+
ctx.RANK(
|
|
62
|
+
ctx.TS_ARGMAX(
|
|
63
|
+
ctx.SIGNEDPOWER(
|
|
64
|
+
np.where(_RETURNS < 0, ctx.STDDEV(_RETURNS, 20), ctx("CLOSE")), 2.0
|
|
65
|
+
),
|
|
66
|
+
5,
|
|
67
|
+
)
|
|
68
|
+
)
|
|
69
|
+
- 0.5
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
生成的代码并不依赖除了 `numpy` 以外的第三方库,只需要通过 `ctx` 传入数据和函数,就能直接调用。
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
### 二、 快速上手
|
|
79
|
+
|
|
80
|
+
安装非常简单:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
pip install py-alpha-lib
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
写一个简单的移动平均(MA)计算:
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
import alpha as al
|
|
91
|
+
import numpy as np
|
|
92
|
+
|
|
93
|
+
# 准备数据
|
|
94
|
+
data = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], dtype=np.float64)
|
|
95
|
+
|
|
96
|
+
# 计算 3 周期均值
|
|
97
|
+
result = al.MA(data, 3)
|
|
98
|
+
print(result)
|
|
99
|
+
# 输出: [1. 1.5 2. 3. 4. 5. 6. 7. 8. 9. ]
|
|
100
|
+
|
|
101
|
+
# 处理 NaN 值:可以设置 Context 标志
|
|
102
|
+
# 计算时会自动跳过 NaN 干扰
|
|
103
|
+
data_with_nan = [1, 2, None, 4, 5, 6, 7, 8, 9, 10]
|
|
104
|
+
result = al.MA(data_with_nan, 3)
|
|
105
|
+
print(result)
|
|
106
|
+
# 输出: [1. 1.5 nan 2.333 3.667 5. 6. 7. 8. 9.]
|
|
107
|
+
# (4+2+1)/3 = 2.333
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
### 三、 实战:复现 WorldQuant 101 Alpha
|
|
113
|
+
|
|
114
|
+
项目库中已经内置了 WorldQuant 101 因子的完整实现示例。如果你正在做因子挖掘,可以直接参考 `examples/wq101` 目录。
|
|
115
|
+
|
|
116
|
+
它不仅提供了高效的实现,还附带了与 Pandas 版本的正确性比对,确保计算结果既快又准。其中 DolphinDB 相关的数据从其[官方仓库获取](https://github.com/dolphindb/DolphinDBModules/blob/master/wq101alpha/README.md)。
|
|
117
|
+
|
|
118
|
+
以下是一些实测结果:
|
|
119
|
+
| 因子编号 | Pandas 耗时 (ms) | PyAlphaLib 耗时 (ms) | PyAlphaLib 提速倍数 | DolphinDB 提速倍数 |
|
|
120
|
+
|----------|------------------|------------------------|-----------|-----------|
|
|
121
|
+
| 加载数据 | 11396 | 718 | 15 | | | |
|
|
122
|
+
| #001 | 14231 | 7 | 2033 | 800 |
|
|
123
|
+
| #002 | 465 | 14 | 33 | 9 |
|
|
124
|
+
| #003 | 430 | 8 | 53 | 14 |
|
|
125
|
+
| #004 | 55107 | 6 | 9184 |
|
|
126
|
+
| #005 | 105 | 9 | 11 | 5 |
|
|
127
|
+
| #006 | 351 | 2 | 175 | 84 |
|
|
128
|
+
| #007 | 43816 | 17 | 2577 | 486 |
|
|
129
|
+
| #008 | 222 | 9 | 24 | 14 |
|
|
130
|
+
| #009 | 97 | 9 | 10 | 14 |
|
|
131
|
+
| #010 | 145 | 11 | 13 | 6 |
|
|
132
|
+
| #011 | 158 | 10 | 15 | 6 |
|
|
133
|
+
| #012 | 4 | 4 | 1 | 0.7 |
|
|
134
|
+
| #013 | 446 | 9 | 49 | 8 |
|
|
135
|
+
| #014 | 398 | 8 | 49 | 18 |
|
|
136
|
+
|
|
137
|
+
你可以在一个[云端的机器上复现这些结果](https://cnb.cool/elsejj/bench-of-alpha),感受一下 `py-alpha-lib` 带来的性能飞跃。请注意, 由于机器的配置不同, 实际的提速倍数可能会有所差异。
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
### 四、 总结
|
|
142
|
+
|
|
143
|
+
如果你目前正面临以下困扰:
|
|
144
|
+
|
|
145
|
+
1. **Pandas 滚动计算太慢**,回测一次要等半天。
|
|
146
|
+
2. **不想为了性能去学 DolphinDB** 或其他复杂的数据库语言。
|
|
147
|
+
3. **需要处理海量历史数据**,希望利用多核 CPU 优势。
|
|
148
|
+
|
|
149
|
+
那么 `py-alpha-lib` 绝对是你工具箱里的新宠。它保持了 Python 的简洁,同时注入了 Rust 的灵魂。
|
|
150
|
+
|
|
151
|
+
**项目地址:** [https://github.com/msd-rs/py-alpha-lib](https://github.com/msd-rs/py-alpha-lib)
|
|
152
|
+
|
|
153
|
+
如果你觉得这个项目有用,记得去 GitHub 点个 **Star** 支持一下开发者!
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
_#量化交易 #Python #Rust #数据分析 #因子研究 #量化投资_
|