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 +3 -0
- alpha/algo/__init__.py +3 -0
- alpha/algo/_algo.pyd +0 -0
- alpha/algo/algo.py +3 -0
- alpha/algo/algo_gen.py +164 -0
- alpha/algo.md +8 -0
- alpha/lang/__init__.py +3 -0
- alpha/lang/__main__.py +3 -0
- alpha/lang/to_python.py +4 -4
- {py_alpha_lib-0.1.0.dist-info → py_alpha_lib-0.1.1.dist-info}/METADATA +57 -22
- py_alpha_lib-0.1.1.dist-info/RECORD +15 -0
- alpha/algo/algo.md +0 -98
- py_alpha_lib-0.1.0.dist-info/RECORD +0 -16
- {py_alpha_lib-0.1.0.dist-info → py_alpha_lib-0.1.1.dist-info}/WHEEL +0 -0
- {py_alpha_lib-0.1.0.dist-info → py_alpha_lib-0.1.1.dist-info}/licenses/LICENSE +0 -0
alpha/__init__.py
CHANGED
alpha/algo/__init__.py
CHANGED
alpha/algo/_algo.pyd
CHANGED
|
Binary file
|
alpha/algo/algo.py
CHANGED
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
alpha/lang/__main__.py
CHANGED
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
|
-
|
|
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.
|
|
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:
|
|
@@ -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,,
|
|
File without changes
|
|
File without changes
|