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.
Files changed (67) hide show
  1. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/.gitignore +2 -1
  2. py_alpha_lib-0.1.1/.nwa-config.yaml +20 -0
  3. py_alpha_lib-0.1.1/CHANGELOG.md +15 -0
  4. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/Cargo.lock +13 -13
  5. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/Cargo.toml +3 -2
  6. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/PKG-INFO +57 -22
  7. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/README.md +53 -20
  8. py_alpha_lib-0.1.1/articles/001.md +157 -0
  9. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/build.rs +327 -74
  10. py_alpha_lib-0.1.1/examples/gtja191/al/__init__.py +78 -0
  11. py_alpha_lib-0.1.1/examples/gtja191/al/alpha191.py +2239 -0
  12. py_alpha_lib-0.1.1/examples/gtja191/al/alpha191_context.py +152 -0
  13. py_alpha_lib-0.1.1/examples/gtja191/alpha191.txt +191 -0
  14. py_alpha_lib-0.1.1/examples/gtja191/main.py +95 -0
  15. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/examples/wq101/al/__init__.py +2 -2
  16. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/examples/wq101/pd_/__init__.py +2 -2
  17. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/pyproject.toml +8 -1
  18. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/python/alpha/__init__.py +3 -0
  19. py_alpha_lib-0.1.1/python/alpha/algo/__init__.py +6 -0
  20. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/python/alpha/algo/algo.py +3 -0
  21. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/python/alpha/algo/algo_gen.py +164 -0
  22. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/python/alpha/algo.md +8 -0
  23. py_alpha_lib-0.1.1/python/alpha/lang/__init__.py +4 -0
  24. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/python/alpha/lang/__main__.py +3 -0
  25. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/python/alpha/lang/to_python.py +4 -4
  26. py_alpha_lib-0.1.1/python/conftest.py +3 -0
  27. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/python/tests/test_grammar.py +3 -0
  28. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/python/tests/test_rank.py +3 -0
  29. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/python/tests/test_talib.py +3 -0
  30. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/python/tests/test_to_python.py +3 -0
  31. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/src/algo/context.rs +3 -0
  32. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/src/algo/cross.rs +3 -0
  33. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/src/algo/ema.rs +3 -0
  34. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/src/algo/error.rs +3 -0
  35. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/src/algo/extremum.rs +3 -0
  36. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/src/algo/ma.rs +3 -0
  37. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/src/algo/mod.rs +9 -0
  38. py_alpha_lib-0.1.1/src/algo/neutralize.rs +226 -0
  39. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/src/algo/rank.rs +128 -0
  40. py_alpha_lib-0.1.1/src/algo/returns.rs +137 -0
  41. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/src/algo/series.rs +3 -0
  42. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/src/algo/skip_nan_window.rs +3 -0
  43. py_alpha_lib-0.1.1/src/algo/slope.rs +284 -0
  44. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/src/algo/stats.rs +389 -0
  45. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/src/algo/stddev.rs +3 -0
  46. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/src/algo/sum.rs +197 -0
  47. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/src/lib.rs +3 -0
  48. py_alpha_lib-0.1.1/tests/usage.py +99 -0
  49. py_alpha_lib-0.1.1/tests/verify_sumif.py +45 -0
  50. py_alpha_lib-0.1.0/python/alpha/algo/__init__.py +0 -3
  51. py_alpha_lib-0.1.0/python/alpha/algo/algo.md +0 -98
  52. py_alpha_lib-0.1.0/python/alpha/lang/__init__.py +0 -1
  53. py_alpha_lib-0.1.0/python/conftest.py +0 -0
  54. py_alpha_lib-0.1.0/tests/usage.py +0 -24
  55. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/.agent/skills/add_algo.md +0 -0
  56. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/.github/workflows/CI.yml +0 -0
  57. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/LICENSE +0 -0
  58. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/examples/wq101/al/alpha101.py +0 -0
  59. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/examples/wq101/al/alpha101_context.py +0 -0
  60. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/examples/wq101/alpha101.txt +0 -0
  61. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/examples/wq101/main.py +0 -0
  62. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/examples/wq101/pd_/alpha101_adjusted.py +0 -0
  63. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/examples/wq101/result.md +0 -0
  64. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/python/alpha/lang/alpha.lark +0 -0
  65. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/python/alpha/lang/parser.py +0 -0
  66. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/rustfmt.toml +0 -0
  67. {py_alpha_lib-0.1.0 → py_alpha_lib-0.1.1}/tests/rank.py +0 -0
@@ -74,4 +74,5 @@ docs/_build/
74
74
  uv.lock
75
75
  dataPerformance.*
76
76
 
77
- .cargo/
77
+ .cargo/
78
+ cargo.lock
@@ -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: []
@@ -0,0 +1,15 @@
1
+ # ChangeLog
2
+
3
+ ## [0.1.1] - 2026-02-02
4
+
5
+ ### Added
6
+
7
+ - BINS
8
+ - FRET
9
+ - INTERCEPT
10
+ - NEUTRALIZE
11
+ - REGBETA
12
+ - REGRESI
13
+ - SUMIF
14
+
15
+ See [algo.md](python/alpha/algo.md) for details.
@@ -4,7 +4,7 @@ version = 4
4
4
 
5
5
  [[package]]
6
6
  name = "alpha"
7
- version = "0.1.0"
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.0"
183
+ version = "1.13.1"
184
184
  source = "registry+https://github.com/rust-lang/crates.io-index"
185
- checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950"
185
+ checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
186
186
 
187
187
  [[package]]
188
188
  name = "portable-atomic-util"
189
- version = "0.2.4"
189
+ version = "0.2.5"
190
190
  source = "registry+https://github.com/rust-lang/crates.io-index"
191
- checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
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.105"
198
+ version = "1.0.106"
199
199
  source = "registry+https://github.com/rust-lang/crates.io-index"
200
- checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7"
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.43"
279
+ version = "1.0.44"
280
280
  source = "registry+https://github.com/rust-lang/crates.io-index"
281
- checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a"
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.17"
343
+ version = "2.0.18"
344
344
  source = "registry+https://github.com/rust-lang/crates.io-index"
345
- checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8"
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.17"
352
+ version = "2.0.18"
353
353
  source = "registry+https://github.com/rust-lang/crates.io-index"
354
- checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
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.0"
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.0
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
- Author: LiJia
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 | Bars since last condition true | https://www.amibroker.com/guide/afl/barslast.html |
25
- | BARSSINCE | Bars since first condition true | https://www.amibroker.com/guide/afl/barssince.html |
26
- | COUNT | Count periods where condition is true | https://www.amibroker.com/guide/afl/count.html |
27
- | CROSS | CROSS(A, B): Previous A < B, Current A >= B | https://www.amibroker.com/guide/afl/cross.html |
28
- | DMA | Exponential Moving Average | https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average |
29
- | HHV | Highest High Value | https://www.amibroker.com/guide/afl/hhv.html |
30
- | HHVBARS | Bars since Highest High Value | https://www.amibroker.com/guide/afl/hhvbars.html |
31
- | LLV | Lowest Low Value | https://www.amibroker.com/guide/afl/llv.html |
32
- | LLVBARS | Bars since Lowest Low Value | https://www.amibroker.com/guide/afl/llvbars.html |
33
- | LONGCROSS | LONGCROSS(A,B,N): Previous N A < B, Current A >= B | |
34
- | MA | Moving Average | https://en.wikipedia.org/wiki/Moving_average#Simple_moving_average |
35
- | RANK | rank by group dim | |
36
- | RCROSS | RCROSE(A, B): Previous A > B, Current A <= B | |
37
- | REF | Reference to value N periods ago | https://www.amibroker.com/guide/afl/ref.html |
38
- | RLONGCROSS | RLONGCROSS(A,B,N): Previous N A > B, Current A <= B | |
39
- | SMA | Exponential Moving Average (variant of EMA) | https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average |
40
- | SUM | Sum of value N periods ago | https://www.amibroker.com/guide/afl/sum.html |
41
- | SUMBARS | Sums X backwards until the sum is greater than or equal to A | https://www.amibroker.com/guide/afl/sumbars.html |
42
- | TS_RANK | rank by ts dim |
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 | Bars since last condition true | https://www.amibroker.com/guide/afl/barslast.html |
12
- | BARSSINCE | Bars since first condition true | https://www.amibroker.com/guide/afl/barssince.html |
13
- | COUNT | Count periods where condition is true | https://www.amibroker.com/guide/afl/count.html |
14
- | CROSS | CROSS(A, B): Previous A < B, Current A >= B | https://www.amibroker.com/guide/afl/cross.html |
15
- | DMA | Exponential Moving Average | https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average |
16
- | HHV | Highest High Value | https://www.amibroker.com/guide/afl/hhv.html |
17
- | HHVBARS | Bars since Highest High Value | https://www.amibroker.com/guide/afl/hhvbars.html |
18
- | LLV | Lowest Low Value | https://www.amibroker.com/guide/afl/llv.html |
19
- | LLVBARS | Bars since Lowest Low Value | https://www.amibroker.com/guide/afl/llvbars.html |
20
- | LONGCROSS | LONGCROSS(A,B,N): Previous N A < B, Current A >= B | |
21
- | MA | Moving Average | https://en.wikipedia.org/wiki/Moving_average#Simple_moving_average |
22
- | RANK | rank by group dim | |
23
- | RCROSS | RCROSE(A, B): Previous A > B, Current A <= B | |
24
- | REF | Reference to value N periods ago | https://www.amibroker.com/guide/afl/ref.html |
25
- | RLONGCROSS | RLONGCROSS(A,B,N): Previous N A > B, Current A <= B | |
26
- | SMA | Exponential Moving Average (variant of EMA) | https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average |
27
- | SUM | Sum of value N periods ago | https://www.amibroker.com/guide/afl/sum.html |
28
- | SUMBARS | Sums X backwards until the sum is greater than or equal to A | https://www.amibroker.com/guide/afl/sumbars.html |
29
- | TS_RANK | rank by ts dim |
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 #数据分析 #因子研究 #量化投资_