py-alpha-lib 0.1.0__cp314-abi3-win_amd64.whl → 0.1.1__cp314-abi3-win_amd64.whl

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.
alpha/__init__.py CHANGED
@@ -1,3 +1,6 @@
1
+ # Copyright 2026 MSD-RS Project LiJia
2
+ # SPDX-License-Identifier: BSD-2-Clause
3
+
1
4
  from .algo import *
2
5
  from .lang import *
3
6
 
alpha/algo/__init__.py CHANGED
@@ -1,3 +1,6 @@
1
+ # Copyright 2026 MSD-RS Project LiJia
2
+ # SPDX-License-Identifier: BSD-2-Clause
3
+
1
4
  from .algo import EMA
2
5
  from .algo_gen import *
3
6
  from ._algo import set_ctx
alpha/algo/_algo.pyd CHANGED
Binary file
alpha/algo/algo.py CHANGED
@@ -1,3 +1,6 @@
1
+ # Copyright 2026 MSD-RS Project LiJia
2
+ # SPDX-License-Identifier: BSD-2-Clause
3
+
1
4
  import numpy as np
2
5
  from . import _algo
3
6
 
alpha/algo/algo_gen.py CHANGED
@@ -1,3 +1,6 @@
1
+ # Copyright 2026 MSD-RS Project LiJia
2
+ # SPDX-License-Identifier: BSD-2-Clause
3
+
1
4
  # THIS FILE IS AUTO-GENERATED, DO NOT EDIT
2
5
 
3
6
  import numpy as np
@@ -41,6 +44,24 @@ def BARSSINCE(
41
44
  _algo.barssince(r, input)
42
45
  return r
43
46
 
47
+ def BINS(
48
+ input: np.ndarray | list[np.ndarray], bins: int
49
+ ) -> np.ndarray | list[np.ndarray]:
50
+ """
51
+ Discretize the input into n bins, the ctx.groups() is the number of groups
52
+
53
+ Bins are 0-based index.
54
+ Same value are assigned to the same bin.
55
+ """
56
+ if isinstance(input, list):
57
+ r = [np.empty_like(x) for x in input]
58
+ _algo.bins(r, input, bins)
59
+ return r
60
+ else:
61
+ r = np.empty_like(input)
62
+ _algo.bins(r, input, bins)
63
+ return r
64
+
44
65
  def CORR(
45
66
  x: np.ndarray | list[np.ndarray], y: np.ndarray | list[np.ndarray], periods: int
46
67
  ) -> np.ndarray | list[np.ndarray]:
@@ -140,6 +161,33 @@ def DMA(
140
161
  _algo.dma(r, input, weight)
141
162
  return r
142
163
 
164
+ def FRET(
165
+ open: np.ndarray | list[np.ndarray], close: np.ndarray | list[np.ndarray], is_calc: np.ndarray | list[np.ndarray], delay: int, periods: int
166
+ ) -> np.ndarray | list[np.ndarray]:
167
+ """
168
+ Future Return
169
+
170
+ 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).
171
+ Return = (Close[t+delay+periods-1] - Open[t+delay]) / Open[t+delay]
172
+
173
+ If n=1, delay=1, it calculates (Close[t+1] - Open[t+1]) / Open[t+1].
174
+ If `is_calc[t+delay]` is 0, returns NaN.
175
+ """
176
+ if isinstance(open, list) and isinstance(close, list) and isinstance(is_calc, list):
177
+ r = [np.empty_like(x) for x in open]
178
+ open = [x.astype(float) for x in open]
179
+ close = [x.astype(float) for x in close]
180
+ is_calc = [x.astype(float) for x in is_calc]
181
+ _algo.fret(r, open, close, is_calc, delay, periods)
182
+ return r
183
+ else:
184
+ r = np.empty_like(open)
185
+ open = open.astype(float)
186
+ close = close.astype(float)
187
+ is_calc = is_calc.astype(float)
188
+ _algo.fret(r, open, close, is_calc, delay, periods)
189
+ return r
190
+
143
191
  def HHV(
144
192
  input: np.ndarray | list[np.ndarray], periods: int
145
193
  ) -> np.ndarray | list[np.ndarray]:
@@ -174,6 +222,23 @@ def HHVBARS(
174
222
  _algo.hhvbars(r, input, periods)
175
223
  return r
176
224
 
225
+ def INTERCEPT(
226
+ input: np.ndarray | list[np.ndarray], periods: int
227
+ ) -> np.ndarray | list[np.ndarray]:
228
+ """
229
+ Linear Regression Intercept
230
+
231
+ Calculates the intercept of the linear regression line for a moving window.
232
+ """
233
+ if isinstance(input, list):
234
+ r = [np.empty_like(x) for x in input]
235
+ _algo.intercept(r, input, periods)
236
+ return r
237
+ else:
238
+ r = np.empty_like(input)
239
+ _algo.intercept(r, input, periods)
240
+ return r
241
+
177
242
  def LLV(
178
243
  input: np.ndarray | list[np.ndarray], periods: int
179
244
  ) -> np.ndarray | list[np.ndarray]:
@@ -261,6 +326,25 @@ def MA(
261
326
  _algo.ma(r, input, periods)
262
327
  return r
263
328
 
329
+ def NEUTRALIZE(
330
+ category: np.ndarray | list[np.ndarray], input: np.ndarray | list[np.ndarray]
331
+ ) -> np.ndarray | list[np.ndarray]:
332
+ """
333
+ Neutralize the effect of a categorical variable on a numeric variable
334
+ """
335
+ if isinstance(category, list) and isinstance(input, list):
336
+ r = [np.empty_like(x) for x in category]
337
+ category = [x.astype(float) for x in category]
338
+ input = [x.astype(float) for x in input]
339
+ _algo.neutralize(r, category, input)
340
+ return r
341
+ else:
342
+ r = np.empty_like(category)
343
+ category = category.astype(float)
344
+ input = input.astype(float)
345
+ _algo.neutralize(r, category, input)
346
+ return r
347
+
264
348
  def PRODUCT(
265
349
  input: np.ndarray | list[np.ndarray], periods: int
266
350
  ) -> np.ndarray | list[np.ndarray]:
@@ -333,6 +417,48 @@ def REF(
333
417
  _algo.ref(r, input, periods)
334
418
  return r
335
419
 
420
+ def REGBETA(
421
+ y: np.ndarray | list[np.ndarray], x: np.ndarray | list[np.ndarray], periods: int
422
+ ) -> np.ndarray | list[np.ndarray]:
423
+ """
424
+ Calculate Regression Coefficient (Beta) of Y on X over a moving window
425
+
426
+ Beta = Cov(X, Y) / Var(X)
427
+ """
428
+ if isinstance(y, list) and isinstance(x, list):
429
+ r = [np.empty_like(x) for x in y]
430
+ y = [x.astype(float) for x in y]
431
+ x = [x.astype(float) for x in x]
432
+ _algo.regbeta(r, y, x, periods)
433
+ return r
434
+ else:
435
+ r = np.empty_like(y)
436
+ y = y.astype(float)
437
+ x = x.astype(float)
438
+ _algo.regbeta(r, y, x, periods)
439
+ return r
440
+
441
+ def REGRESI(
442
+ y: np.ndarray | list[np.ndarray], x: np.ndarray | list[np.ndarray], periods: int
443
+ ) -> np.ndarray | list[np.ndarray]:
444
+ """
445
+ Calculate Regression Residual of Y on X over a moving window
446
+
447
+ Returns the residual of the last point: epsilon = Y - (alpha + beta * X)
448
+ """
449
+ if isinstance(y, list) and isinstance(x, list):
450
+ r = [np.empty_like(x) for x in y]
451
+ y = [x.astype(float) for x in y]
452
+ x = [x.astype(float) for x in x]
453
+ _algo.regresi(r, y, x, periods)
454
+ return r
455
+ else:
456
+ r = np.empty_like(y)
457
+ y = y.astype(float)
458
+ x = x.astype(float)
459
+ _algo.regresi(r, y, x, periods)
460
+ return r
461
+
336
462
  def RLONGCROSS(
337
463
  a: np.ndarray | list[np.ndarray], b: np.ndarray | list[np.ndarray], n: int
338
464
  ) -> np.ndarray | list[np.ndarray]:
@@ -352,6 +478,23 @@ def RLONGCROSS(
352
478
  _algo.rlongcross(r, a, b, n)
353
479
  return r
354
480
 
481
+ def SLOPE(
482
+ input: np.ndarray | list[np.ndarray], periods: int
483
+ ) -> np.ndarray | list[np.ndarray]:
484
+ """
485
+ Linear Regression Slope
486
+
487
+ Calculates the slope of the linear regression line for a moving window.
488
+ """
489
+ if isinstance(input, list):
490
+ r = [np.empty_like(x) for x in input]
491
+ _algo.slope(r, input, periods)
492
+ return r
493
+ else:
494
+ r = np.empty_like(input)
495
+ _algo.slope(r, input, periods)
496
+ return r
497
+
355
498
  def SMA(
356
499
  input: np.ndarray | list[np.ndarray], n: int, m: int
357
500
  ) -> np.ndarray | list[np.ndarray]:
@@ -422,6 +565,27 @@ def SUMBARS(
422
565
  _algo.sumbars(r, input, amount)
423
566
  return r
424
567
 
568
+ def SUMIF(
569
+ input: np.ndarray | list[np.ndarray], condition: np.ndarray | list[np.ndarray], periods: int
570
+ ) -> np.ndarray | list[np.ndarray]:
571
+ """
572
+ Calculate sum of values in preceding `periods` window where `condition` is true
573
+
574
+ Ref: Custom extension
575
+ """
576
+ if isinstance(input, list) and isinstance(condition, list):
577
+ r = [np.empty_like(x) for x in input]
578
+ input = [x.astype(float) for x in input]
579
+ condition = [x.astype(float) for x in condition]
580
+ _algo.sumif(r, input, condition, periods)
581
+ return r
582
+ else:
583
+ r = np.empty_like(input)
584
+ input = input.astype(float)
585
+ condition = condition.astype(float)
586
+ _algo.sumif(r, input, condition, periods)
587
+ return r
588
+
425
589
  def TS_RANK(
426
590
  input: np.ndarray | list[np.ndarray], periods: int
427
591
  ) -> np.ndarray | list[np.ndarray]:
alpha/algo.md CHANGED
@@ -4,27 +4,35 @@ the `np.ndarray` is `ndarray` type in `numpy` package
4
4
 
5
5
  - BARSLAST(input: np.ndarray[bool]): Calculate number of bars since last condition true
6
6
  - BARSSINCE(input: np.ndarray[bool]): Calculate number of bars since first condition true
7
+ - BINS(input: np.ndarray[float], bins: int): 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.
7
8
  - CORR(x: np.ndarray[float], y: np.ndarray[float], periods: int): Calculate Correlation over a moving window Correlation = Cov(X, Y) / (StdDev(X) * StdDev(Y))
8
9
  - COUNT(input: np.ndarray[bool], periods: int): Calculate number of periods where condition is true in passed `periods` window
9
10
  - COV(x: np.ndarray[float], y: np.ndarray[float], periods: int): Calculate Covariance over a moving window Covariance = (SumXY - (SumX * SumY) / N) / (N - 1)
10
11
  - CROSS(a: np.ndarray[float], b: np.ndarray[float]): 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
11
12
  - DMA(input: np.ndarray[float], weight: float): Exponential Moving Average current = weight * current + (1 - weight) * previous
12
13
  - EMA(input: np.ndarray[float], periods: int): Exponential Moving Average (variant of well-known EMA) weight = 2 / (n + 1)
14
+ - FRET(open: np.ndarray[float], close: np.ndarray[float], is_calc: np.ndarray[float], delay: int, periods: int): 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.
13
15
  - HHV(input: np.ndarray[float], periods: int): Find highest value in a preceding `periods` window
14
16
  - HHVBARS(input: np.ndarray[float], periods: int): The number of periods that have passed since the array reached its `periods` period high
17
+ - INTERCEPT(input: np.ndarray[float], periods: int): Linear Regression Intercept Calculates the intercept of the linear regression line for a moving window.
15
18
  - LLV(input: np.ndarray[float], periods: int): Find lowest value in a preceding `periods` window
16
19
  - LLVBARS(input: np.ndarray[float], periods: int): The number of periods that have passed since the array reached its periods period low
17
20
  - LONGCROSS(a: np.ndarray[float], b: np.ndarray[float], n: int): For 2 arrays A and B, return true if previous N periods A < B, Current A >= B
18
21
  - LWMA(input: np.ndarray[float], periods: int): Linear Weighted Moving Average LWMA = SUM(Price * Weight) / SUM(Weight)
19
22
  - MA(input: np.ndarray[float], periods: int): Simple Moving Average, also known as arithmetic moving average
23
+ - NEUTRALIZE(category: np.ndarray[float], input: np.ndarray[float]): Neutralize the effect of a categorical variable on a numeric variable
20
24
  - PRODUCT(input: np.ndarray[float], periods: int): Calculate product of values in preceding `periods` window If periods is 0, it calculates the cumulative product from the first valid value.
21
25
  - RANK(input: np.ndarray[float]): Calculate rank percentage cross group dimension, the ctx.groups() is the number of groups Same value are averaged
22
26
  - RCROSS(a: np.ndarray[float], b: np.ndarray[float]): 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
23
27
  - REF(input: np.ndarray[float], periods: int): Right shift input array by `periods`, r[i] = input[i - periods]
28
+ - REGBETA(y: np.ndarray[float], x: np.ndarray[float], periods: int): Calculate Regression Coefficient (Beta) of Y on X over a moving window Beta = Cov(X, Y) / Var(X)
29
+ - REGRESI(y: np.ndarray[float], x: np.ndarray[float], periods: int): Calculate Regression Residual of Y on X over a moving window Returns the residual of the last point: epsilon = Y - (alpha + beta * X)
24
30
  - RLONGCROSS(a: np.ndarray[float], b: np.ndarray[float], n: int): For 2 arrays A and B, return true if previous N periods A > B, Current A <= B
31
+ - SLOPE(input: np.ndarray[float], periods: int): Linear Regression Slope Calculates the slope of the linear regression line for a moving window.
25
32
  - SMA(input: np.ndarray[float], n: int, m: int): Exponential Moving Average (variant of well-known EMA) weight = m / n
26
33
  - STDDEV(input: np.ndarray[float], periods: int): Calculate Standard Deviation over a moving window
27
34
  - SUM(input: np.ndarray[float], periods: int): Calculate sum of values in preceding `periods` window If periods is 0, it calculates the cumulative sum from the first valid value.
28
35
  - SUMBARS(input: np.ndarray[float], amount: float): Calculate number of periods (bars) backwards until the sum of values is greater than or equal to `amount`
36
+ - SUMIF(input: np.ndarray[float], condition: np.ndarray[bool], periods: int): Calculate sum of values in preceding `periods` window where `condition` is true
29
37
  - TS_RANK(input: np.ndarray[float], periods: int): Calculate rank in a sliding window with size `periods`
30
38
  - VAR(input: np.ndarray[float], periods: int): Calculate Variance over a moving window Variance = (SumSq - (Sum^2)/N) / (N - 1)
alpha/lang/__init__.py CHANGED
@@ -1 +1,4 @@
1
+ # Copyright 2026 MSD-RS Project LiJia
2
+ # SPDX-License-Identifier: BSD-2-Clause
3
+
1
4
  from .to_python import to_python, to_python_file
alpha/lang/__main__.py CHANGED
@@ -1,3 +1,6 @@
1
+ # Copyright 2026 MSD-RS Project LiJia
2
+ # SPDX-License-Identifier: BSD-2-Clause
3
+
1
4
  from .to_python import to_python_file
2
5
 
3
6
  if __name__ == "__main__":
alpha/lang/to_python.py CHANGED
@@ -1,3 +1,6 @@
1
+ # Copyright 2026 MSD-RS Project LiJia
2
+ # SPDX-License-Identifier: BSD-2-Clause
3
+
1
4
  import sys
2
5
  from typing import Callable
3
6
  from .parser import Lark_StandAlone, Transformer, v_args
@@ -167,10 +170,7 @@ def to_python(
167
170
  if not code.strip():
168
171
  return ""
169
172
 
170
- try:
171
- tree = parser.parse(code)
172
- except Exception as e:
173
- raise ValueError(f"Failed to parse code: {code}") from e
173
+ tree = parser.parse(code)
174
174
 
175
175
  transformer = AlphaTransformer(name_convertor=name_convertor)
176
176
  converted_expr = transformer.transform(tree)
@@ -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:
@@ -185,4 +206,18 @@ The hardware/soft environment is:
185
206
  | #012 | 4 | 4 | 1 | 0.7 | -17.012321 | -17.012321 |
186
207
  | #013 | 446 | 9 | 49 | 8 | -0.58 | -0.58 |
187
208
  | #014 | 398 | 8 | 49 | 18 | 0.095449 | 0.095449 |
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.
188
223
 
@@ -0,0 +1,15 @@
1
+ alpha\__init__.py,sha256=it34OBlXnf1KxXsG3S7gOTo7VUf_29NjYrf5HkyTiBQ,253
2
+ alpha\algo\__init__.py,sha256=AwglMcMEn0P_Stdlr9oUYwFNVDtJ7JRh48LCHnZNRA8,158
3
+ alpha\algo\_algo.pyd,sha256=Mk7q09s63T1J_aL7dTw28n34WXuz0qZUD-m3Y95scQc,2494464
4
+ alpha\algo\algo.py,sha256=48jGJGSypFgGnih-XgIxW2QUnzGsTWq00TGNuDxKHE4,684
5
+ alpha\algo\algo_gen.py,sha256=KlMKCnTZH9jotIW3wmsx2dXWRCejMWeJ6nd-vlzyhG8,17287
6
+ alpha\algo.md,sha256=jh8-TXh5moTmnexFQWKfrtS4xy5oe3n40CXfdGyCX38,5115
7
+ alpha\lang\__init__.py,sha256=2dLimPixRh5vF3PvgF-aJ8DBZ0SuDaHrrkQecmBTC_4,132
8
+ alpha\lang\__main__.py,sha256=wa5DHGSmhL8dswN3v160RXs1qG6_dIr0W1qe_u4b3C8,572
9
+ alpha\lang\alpha.lark,sha256=qqMXJ--F3ErYikNdRs1vwHGKoJe_aRUeNmpo87NaTXs,1046
10
+ alpha\lang\parser.py,sha256=WBpwEUYzGJ1nM7iUh_mEimGLhHzVZXS8BAzF58ZRagU,156846
11
+ alpha\lang\to_python.py,sha256=4i8km91EejlzrIt5QxHrZWtq-A3zlDwRJwlAUew54-8,6563
12
+ py_alpha_lib-0.1.1.dist-info\METADATA,sha256=5Mgzjgy9wEQQVexGOZrmjpAXaUouWlZAW5W152XoFCY,16272
13
+ py_alpha_lib-0.1.1.dist-info\WHEEL,sha256=dsg5IA1tFdLNsJihRQJCX59s7GKfDG9N_2EOwwysnks,96
14
+ py_alpha_lib-0.1.1.dist-info\licenses\LICENSE,sha256=3D2Y67XRAnMSiByf02r4DaFv92CdDLw5U6xHyUVkdI4,1289
15
+ py_alpha_lib-0.1.1.dist-info\RECORD,,
alpha/algo/algo.md DELETED
@@ -1,98 +0,0 @@
1
- # Algo
2
- ## barslast
3
- Bars since last condition true
4
-
5
- Ref: https://www.amibroker.com/guide/afl/barslast.html
6
-
7
- ## barssince
8
- Bars since first condition true
9
-
10
- Ref: https://www.amibroker.com/guide/afl/barssince.html
11
-
12
- ## count
13
- Count periods where condition is true
14
-
15
- Ref: https://www.amibroker.com/guide/afl/count.html
16
-
17
- ## cross
18
- CROSS(A, B): Previous A < B, Current A >= B
19
-
20
- Ref: https://www.amibroker.com/guide/afl/cross.html
21
-
22
- ## dma
23
- Exponential Moving Average
24
-
25
- https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average
26
-
27
- current = alpha * current + (1 - alpha) * previous
28
-
29
-
30
- ## hhv
31
- Highest High Value
32
-
33
- Ref: https://www.amibroker.com/guide/afl/hhv.html
34
-
35
- ## hhvbars
36
- Bars since Highest High Value
37
-
38
- Ref: https://www.amibroker.com/guide/afl/hhvbars.html
39
-
40
- ## llv
41
- Lowest Low Value
42
-
43
- Ref: https://www.amibroker.com/guide/afl/llv.html
44
-
45
- ## llvbars
46
- Bars since Lowest Low Value
47
-
48
- Ref: https://www.amibroker.com/guide/afl/llvbars.html
49
-
50
- ## longcross
51
- LONGCROSS(A,B,N): Previous N A < B, Current A >= B
52
-
53
- ## ma
54
- Moving Average
55
-
56
- https://en.wikipedia.org/wiki/Moving_average#Simple_moving_average
57
-
58
-
59
-
60
- ## rank
61
- rank by group dim
62
-
63
- ## rcross
64
- RCROSE(A, B): Previous A > B, Current A <= B
65
-
66
- ## ref
67
- Reference to value N periods ago
68
-
69
- Ref: https://www.amibroker.com/guide/afl/ref.html
70
-
71
- ## rlongcross
72
- RLONGCROSS(A,B,N): Previous N A > B, Current A <= B
73
-
74
- ## sma
75
- Exponential Moving Average (variant of EMA)
76
-
77
- alpha = m / n
78
-
79
- https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average
80
-
81
-
82
- ## sum
83
- Sum of value N periods ago
84
-
85
- If periods is 0, it calculates the cumulative sum from the first valid value.
86
-
87
- Ref: https://www.amibroker.com/guide/afl/sum.html
88
-
89
- ## sumbars
90
- Sums X backwards until the sum is greater than or equal to A
91
-
92
- Returns the number of periods (bars) passed.
93
-
94
- Ref: https://www.amibroker.com/guide/afl/sumbars.html
95
-
96
- ## ts_rank
97
- rank by ts dim
98
-
@@ -1,16 +0,0 @@
1
- alpha\__init__.py,sha256=rZE0P-d0AT7YG624RuE_EPdwIGKOHz2RMPn6Z-nTu9o,171
2
- alpha\algo\__init__.py,sha256=F8t1XUjla37_0x-fjGL4HXTZASmSYLotWQbfdOhdfh0,76
3
- alpha\algo\_algo.pyd,sha256=MK1Nk-4xQngkixcZcQiLLzmKLC5NPE3ZTmDXa3XF4LU,2076672
4
- alpha\algo\algo.md,sha256=KZjYakkAkTLx4iPDj7hcVZEVv7Fc7Ye9h-zdz7JB7rI,1929
5
- alpha\algo\algo.py,sha256=Y0R13cZ7uigtsobYd4wo9vtMlPJRwL0ktwPp6GPl0xc,602
6
- alpha\algo\algo_gen.py,sha256=hSc8c8yJrGcNnZohc56TgJj_7V6Bcxnf_7K04mOiSYc,12269
7
- alpha\algo.md,sha256=Av1UP0Tj7RHaksHD-0kM4uvppXyvDMlyEQZ6CG7PNYY,3521
8
- alpha\lang\__init__.py,sha256=JdMw9vZv-4CQgChVfMxIYwpb5pQsYc9d_GleocYfFg4,50
9
- alpha\lang\__main__.py,sha256=aemLHkuKarwc2x8aejCWBpFsYY49NzQOUhHcUFf19BE,490
10
- alpha\lang\alpha.lark,sha256=qqMXJ--F3ErYikNdRs1vwHGKoJe_aRUeNmpo87NaTXs,1046
11
- alpha\lang\parser.py,sha256=WBpwEUYzGJ1nM7iUh_mEimGLhHzVZXS8BAzF58ZRagU,156846
12
- alpha\lang\to_python.py,sha256=G-bcISR1ItW6AxfccuEZo-xwukl-TtVLgmo3n2nnrPE,6579
13
- py_alpha_lib-0.1.0.dist-info\METADATA,sha256=clwi8ljMxqv3YKDgmCaufgZ6-jPOpwnndEKSY8jI7vw,11880
14
- py_alpha_lib-0.1.0.dist-info\WHEEL,sha256=dsg5IA1tFdLNsJihRQJCX59s7GKfDG9N_2EOwwysnks,96
15
- py_alpha_lib-0.1.0.dist-info\licenses\LICENSE,sha256=3D2Y67XRAnMSiByf02r4DaFv92CdDLw5U6xHyUVkdI4,1289
16
- py_alpha_lib-0.1.0.dist-info\RECORD,,