py-alpha-lib 0.1.1__tar.gz → 0.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- py_alpha_lib-0.1.2/CHANGELOG.md +24 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/Cargo.lock +1 -1
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/Cargo.toml +1 -1
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/PKG-INFO +1 -1
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/python/alpha/algo/algo_gen.py +17 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/python/alpha/algo.md +1 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/algo/slope.rs +50 -6
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/tests/usage.py +7 -0
- py_alpha_lib-0.1.1/CHANGELOG.md +0 -15
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/.agent/skills/add_algo.md +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/.github/workflows/CI.yml +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/.gitignore +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/.nwa-config.yaml +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/LICENSE +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/README.md +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/articles/001.md +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/build.rs +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/examples/gtja191/al/__init__.py +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/examples/gtja191/al/alpha191.py +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/examples/gtja191/al/alpha191_context.py +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/examples/gtja191/alpha191.txt +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/examples/gtja191/main.py +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/examples/wq101/al/__init__.py +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/examples/wq101/al/alpha101.py +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/examples/wq101/al/alpha101_context.py +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/examples/wq101/alpha101.txt +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/examples/wq101/main.py +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/examples/wq101/pd_/__init__.py +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/examples/wq101/pd_/alpha101_adjusted.py +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/examples/wq101/result.md +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/pyproject.toml +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/python/alpha/__init__.py +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/python/alpha/algo/__init__.py +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/python/alpha/algo/algo.py +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/python/alpha/lang/__init__.py +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/python/alpha/lang/__main__.py +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/python/alpha/lang/alpha.lark +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/python/alpha/lang/parser.py +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/python/alpha/lang/to_python.py +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/python/conftest.py +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/python/tests/test_grammar.py +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/python/tests/test_rank.py +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/python/tests/test_talib.py +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/python/tests/test_to_python.py +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/rustfmt.toml +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/algo/context.rs +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/algo/cross.rs +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/algo/ema.rs +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/algo/error.rs +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/algo/extremum.rs +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/algo/ma.rs +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/algo/mod.rs +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/algo/neutralize.rs +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/algo/rank.rs +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/algo/returns.rs +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/algo/series.rs +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/algo/skip_nan_window.rs +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/algo/stats.rs +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/algo/stddev.rs +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/algo/sum.rs +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/lib.rs +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/tests/rank.py +0 -0
- {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/tests/verify_sumif.py +0 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# ChangeLog
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
## [0.1.2] - 2026-02-04
|
|
5
|
+
|
|
6
|
+
### Added
|
|
7
|
+
|
|
8
|
+
- TS_CORR @zhaojun6969
|
|
9
|
+
|
|
10
|
+
## [0.1.1] - 2026-02-02
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- BINS @zhaojun6969
|
|
15
|
+
- FRET @zhaojun6969
|
|
16
|
+
- INTERCEPT @zhaojun6969
|
|
17
|
+
- NEUTRALIZE @zhaojun6969
|
|
18
|
+
- REGBETA
|
|
19
|
+
- REGRESI
|
|
20
|
+
- SUMIF
|
|
21
|
+
|
|
22
|
+
See [algo.md](python/alpha/algo.md) for details.
|
|
23
|
+
|
|
24
|
+
Thanks @zhaojun6969, our first contributor!
|
|
@@ -586,6 +586,23 @@ def SUMIF(
|
|
|
586
586
|
_algo.sumif(r, input, condition, periods)
|
|
587
587
|
return r
|
|
588
588
|
|
|
589
|
+
def TS_CORR(
|
|
590
|
+
input: np.ndarray | list[np.ndarray], periods: int
|
|
591
|
+
) -> np.ndarray | list[np.ndarray]:
|
|
592
|
+
"""
|
|
593
|
+
Time Series Correlation
|
|
594
|
+
|
|
595
|
+
Calculates the correlation coefficient between the input series and the time index.
|
|
596
|
+
"""
|
|
597
|
+
if isinstance(input, list):
|
|
598
|
+
r = [np.empty_like(x) for x in input]
|
|
599
|
+
_algo.ts_corr(r, input, periods)
|
|
600
|
+
return r
|
|
601
|
+
else:
|
|
602
|
+
r = np.empty_like(input)
|
|
603
|
+
_algo.ts_corr(r, input, periods)
|
|
604
|
+
return r
|
|
605
|
+
|
|
589
606
|
def TS_RANK(
|
|
590
607
|
input: np.ndarray | list[np.ndarray], periods: int
|
|
591
608
|
) -> np.ndarray | list[np.ndarray]:
|
|
@@ -34,5 +34,6 @@ the `np.ndarray` is `ndarray` type in `numpy` package
|
|
|
34
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.
|
|
35
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
36
|
- SUMIF(input: np.ndarray[float], condition: np.ndarray[bool], periods: int): Calculate sum of values in preceding `periods` window where `condition` is true
|
|
37
|
+
- TS_CORR(input: np.ndarray[float], periods: int): Time Series Correlation Calculates the correlation coefficient between the input series and the time index.
|
|
37
38
|
- TS_RANK(input: np.ndarray[float], periods: int): Calculate rank in a sliding window with size `periods`
|
|
38
39
|
- VAR(input: np.ndarray[float], periods: int): Calculate Variance over a moving window Variance = (SumSq - (Sum^2)/N) / (N - 1)
|
|
@@ -6,7 +6,7 @@ use rayon::prelude::*;
|
|
|
6
6
|
|
|
7
7
|
use crate::algo::{Context, Error, is_normal, skip_nan_window::SkipNanWindow};
|
|
8
8
|
|
|
9
|
-
fn
|
|
9
|
+
fn linear_reg_core<NumT, F>(
|
|
10
10
|
ctx: &Context,
|
|
11
11
|
r: &mut [NumT],
|
|
12
12
|
input: &[NumT],
|
|
@@ -15,7 +15,7 @@ fn ta_linear_reg_core<NumT, F>(
|
|
|
15
15
|
) -> Result<(), Error>
|
|
16
16
|
where
|
|
17
17
|
NumT: Float + Send + Sync,
|
|
18
|
-
F: Fn(NumT, NumT, NumT, NumT, NumT) -> NumT + Sync + Send + Copy,
|
|
18
|
+
F: Fn(NumT, NumT, NumT, NumT, NumT, NumT) -> NumT + Sync + Send + Copy,
|
|
19
19
|
{
|
|
20
20
|
if r.len() != input.len() {
|
|
21
21
|
return Err(Error::LengthMismatch(r.len(), input.len()));
|
|
@@ -35,6 +35,7 @@ where
|
|
|
35
35
|
if ctx.is_skip_nan() {
|
|
36
36
|
let iter = SkipNanWindow::new(x, periods, start);
|
|
37
37
|
let mut sum_y = NumT::zero();
|
|
38
|
+
let mut sum_y2 = NumT::zero();
|
|
38
39
|
let mut sum_xy_1based = NumT::zero();
|
|
39
40
|
let mut count = 0;
|
|
40
41
|
|
|
@@ -44,6 +45,7 @@ where
|
|
|
44
45
|
if old.is_normal() {
|
|
45
46
|
sum_xy_1based = sum_xy_1based - sum_y;
|
|
46
47
|
sum_y = sum_y - old;
|
|
48
|
+
sum_y2 = sum_y2 - old * old;
|
|
47
49
|
count -= 1;
|
|
48
50
|
}
|
|
49
51
|
}
|
|
@@ -53,6 +55,7 @@ where
|
|
|
53
55
|
count += 1;
|
|
54
56
|
let n_t = NumT::from(count).unwrap();
|
|
55
57
|
sum_y = sum_y + val;
|
|
58
|
+
sum_y2 = sum_y2 + val * val;
|
|
56
59
|
sum_xy_1based = sum_xy_1based + n_t * val;
|
|
57
60
|
}
|
|
58
61
|
|
|
@@ -74,11 +77,12 @@ where
|
|
|
74
77
|
|
|
75
78
|
let sum_xy = sum_xy_1based - sum_y;
|
|
76
79
|
|
|
77
|
-
r[i.end] = op(n, sum_x, sum_x2, sum_y, sum_xy);
|
|
80
|
+
r[i.end] = op(n, sum_x, sum_x2, sum_y, sum_y2, sum_xy);
|
|
78
81
|
}
|
|
79
82
|
}
|
|
80
83
|
} else {
|
|
81
84
|
let mut sum_y = NumT::zero();
|
|
85
|
+
let mut sum_y2 = NumT::zero();
|
|
82
86
|
let mut sum_xy_1based = NumT::zero();
|
|
83
87
|
let mut count = 0;
|
|
84
88
|
let mut nan_in_window = 0;
|
|
@@ -90,6 +94,7 @@ where
|
|
|
90
94
|
count += 1;
|
|
91
95
|
let n_t = NumT::from(count).unwrap();
|
|
92
96
|
sum_y = sum_y + val;
|
|
97
|
+
sum_y2 = sum_y2 + val * val;
|
|
93
98
|
sum_xy_1based = sum_xy_1based + n_t * val;
|
|
94
99
|
} else {
|
|
95
100
|
count += 1;
|
|
@@ -109,6 +114,7 @@ where
|
|
|
109
114
|
|
|
110
115
|
if c.is_normal() {
|
|
111
116
|
sum_y = sum_y + *c;
|
|
117
|
+
sum_y2 = sum_y2 + *c * *c;
|
|
112
118
|
sum_xy_1based = sum_xy_1based + n_t * *c;
|
|
113
119
|
} else {
|
|
114
120
|
nan_in_window += 1;
|
|
@@ -121,6 +127,7 @@ where
|
|
|
121
127
|
sum_xy_1based = sum_xy_1based - sum_y;
|
|
122
128
|
if old.is_normal() {
|
|
123
129
|
sum_y = sum_y - old;
|
|
130
|
+
sum_y2 = sum_y2 - old * old;
|
|
124
131
|
} else {
|
|
125
132
|
nan_in_window -= 1;
|
|
126
133
|
}
|
|
@@ -139,7 +146,7 @@ where
|
|
|
139
146
|
|
|
140
147
|
let sum_xy = sum_xy_1based - sum_y;
|
|
141
148
|
|
|
142
|
-
*r = op(n_val, sum_x, sum_x2, sum_y, sum_xy);
|
|
149
|
+
*r = op(n_val, sum_x, sum_x2, sum_y, sum_y2, sum_xy);
|
|
143
150
|
}
|
|
144
151
|
} else {
|
|
145
152
|
*r = NumT::nan();
|
|
@@ -160,7 +167,7 @@ pub fn ta_slope<NumT: Float + Send + Sync>(
|
|
|
160
167
|
input: &[NumT],
|
|
161
168
|
periods: usize,
|
|
162
169
|
) -> Result<(), Error> {
|
|
163
|
-
|
|
170
|
+
linear_reg_core(ctx, r, input, periods, |n, sum_x, sum_x2, sum_y, _sum_y2, sum_xy| {
|
|
164
171
|
// slope = (n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x^2)
|
|
165
172
|
let numerator = n * sum_xy - sum_x * sum_y;
|
|
166
173
|
let denominator = n * sum_x2 - sum_x * sum_x;
|
|
@@ -183,7 +190,7 @@ pub fn ta_intercept<NumT: Float + Send + Sync>(
|
|
|
183
190
|
input: &[NumT],
|
|
184
191
|
periods: usize,
|
|
185
192
|
) -> Result<(), Error> {
|
|
186
|
-
|
|
193
|
+
linear_reg_core(ctx, r, input, periods, |n, sum_x, sum_x2, sum_y, _sum_y2, sum_xy| {
|
|
187
194
|
// Intercept: b = (sum_y * sum_x2 - sum_x * sum_xy) / (n * sum_x2 - sum_x^2)
|
|
188
195
|
let numerator = sum_y * sum_x2 - sum_x * sum_xy;
|
|
189
196
|
let denominator = n * sum_x2 - sum_x * sum_x;
|
|
@@ -196,6 +203,31 @@ pub fn ta_intercept<NumT: Float + Send + Sync>(
|
|
|
196
203
|
})
|
|
197
204
|
}
|
|
198
205
|
|
|
206
|
+
/// Time Series Correlation
|
|
207
|
+
///
|
|
208
|
+
/// Calculates the correlation coefficient between the input series and the time index.
|
|
209
|
+
///
|
|
210
|
+
pub fn ta_ts_corr<NumT: Float + Send + Sync>(
|
|
211
|
+
ctx: &Context,
|
|
212
|
+
r: &mut [NumT],
|
|
213
|
+
input: &[NumT],
|
|
214
|
+
periods: usize,
|
|
215
|
+
) -> Result<(), Error> {
|
|
216
|
+
linear_reg_core(ctx, r, input, periods, |n, sum_x, sum_x2, sum_y, sum_y2, sum_xy| {
|
|
217
|
+
// r = (n * sum_xy - sum_x * sum_y) / sqrt( (n * sum_x2 - sum_x^2) * (n * sum_y2 - sum_y^2) )
|
|
218
|
+
let numerator = n * sum_xy - sum_x * sum_y;
|
|
219
|
+
let var_x = n * sum_x2 - sum_x * sum_x;
|
|
220
|
+
let var_y = n * sum_y2 - sum_y * sum_y;
|
|
221
|
+
|
|
222
|
+
let denominator_sq = var_x * var_y;
|
|
223
|
+
if denominator_sq > NumT::zero() {
|
|
224
|
+
numerator / denominator_sq.sqrt()
|
|
225
|
+
} else {
|
|
226
|
+
NumT::nan()
|
|
227
|
+
}
|
|
228
|
+
})
|
|
229
|
+
}
|
|
230
|
+
|
|
199
231
|
#[cfg(test)]
|
|
200
232
|
mod tests {
|
|
201
233
|
use crate::algo::{
|
|
@@ -281,4 +313,16 @@ mod tests {
|
|
|
281
313
|
|
|
282
314
|
assert_vec_eq_nan(&r, &vec![f64::NAN, f64::NAN, 1.0, 3.0, 5.0]);
|
|
283
315
|
}
|
|
316
|
+
|
|
317
|
+
#[test]
|
|
318
|
+
fn test_ta_ts_corr() {
|
|
319
|
+
let input = vec![1.0, 2.0, 3.0, 3.0, 2.0, 1.0];
|
|
320
|
+
let periods = 3;
|
|
321
|
+
let mut r = vec![0.0; input.len()];
|
|
322
|
+
let ctx = Context::new(0, 0, 0);
|
|
323
|
+
ta_ts_corr(&ctx, &mut r, &input, periods).unwrap();
|
|
324
|
+
|
|
325
|
+
let expected = vec![f64::NAN, f64::NAN, 1.0, 0.8660254037844386, -0.8660254037844386, -1.0];
|
|
326
|
+
assert_vec_eq_nan(&r, &expected);
|
|
327
|
+
}
|
|
284
328
|
}
|
|
@@ -97,3 +97,10 @@ print("NEUTRALIZE:", result_neutralize)
|
|
|
97
97
|
df = df.assign(neutralize=result_neutralize)
|
|
98
98
|
print(df.pivot_table(index="time", columns="stock", values="neutralize"))
|
|
99
99
|
|
|
100
|
+
# Calculate Time Series Correlation
|
|
101
|
+
al.set_ctx(flags=0, groups=1)
|
|
102
|
+
data_corr = np.array([1, 2, 3, 4, 5, 5, 4, 3, 2, 1], dtype=np.float64)
|
|
103
|
+
# First 5: Correlation should be 1.0 (perfectly increasing)
|
|
104
|
+
# Next part: decreasing.
|
|
105
|
+
result_corr = al.TS_CORR(data_corr, 5)
|
|
106
|
+
print("TS_CORR(5):", result_corr)
|
py_alpha_lib-0.1.1/CHANGELOG.md
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|