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.
Files changed (63) hide show
  1. py_alpha_lib-0.1.2/CHANGELOG.md +24 -0
  2. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/Cargo.lock +1 -1
  3. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/Cargo.toml +1 -1
  4. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/PKG-INFO +1 -1
  5. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/python/alpha/algo/algo_gen.py +17 -0
  6. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/python/alpha/algo.md +1 -0
  7. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/algo/slope.rs +50 -6
  8. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/tests/usage.py +7 -0
  9. py_alpha_lib-0.1.1/CHANGELOG.md +0 -15
  10. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/.agent/skills/add_algo.md +0 -0
  11. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/.github/workflows/CI.yml +0 -0
  12. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/.gitignore +0 -0
  13. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/.nwa-config.yaml +0 -0
  14. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/LICENSE +0 -0
  15. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/README.md +0 -0
  16. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/articles/001.md +0 -0
  17. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/build.rs +0 -0
  18. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/examples/gtja191/al/__init__.py +0 -0
  19. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/examples/gtja191/al/alpha191.py +0 -0
  20. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/examples/gtja191/al/alpha191_context.py +0 -0
  21. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/examples/gtja191/alpha191.txt +0 -0
  22. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/examples/gtja191/main.py +0 -0
  23. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/examples/wq101/al/__init__.py +0 -0
  24. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/examples/wq101/al/alpha101.py +0 -0
  25. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/examples/wq101/al/alpha101_context.py +0 -0
  26. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/examples/wq101/alpha101.txt +0 -0
  27. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/examples/wq101/main.py +0 -0
  28. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/examples/wq101/pd_/__init__.py +0 -0
  29. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/examples/wq101/pd_/alpha101_adjusted.py +0 -0
  30. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/examples/wq101/result.md +0 -0
  31. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/pyproject.toml +0 -0
  32. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/python/alpha/__init__.py +0 -0
  33. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/python/alpha/algo/__init__.py +0 -0
  34. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/python/alpha/algo/algo.py +0 -0
  35. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/python/alpha/lang/__init__.py +0 -0
  36. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/python/alpha/lang/__main__.py +0 -0
  37. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/python/alpha/lang/alpha.lark +0 -0
  38. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/python/alpha/lang/parser.py +0 -0
  39. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/python/alpha/lang/to_python.py +0 -0
  40. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/python/conftest.py +0 -0
  41. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/python/tests/test_grammar.py +0 -0
  42. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/python/tests/test_rank.py +0 -0
  43. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/python/tests/test_talib.py +0 -0
  44. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/python/tests/test_to_python.py +0 -0
  45. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/rustfmt.toml +0 -0
  46. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/algo/context.rs +0 -0
  47. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/algo/cross.rs +0 -0
  48. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/algo/ema.rs +0 -0
  49. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/algo/error.rs +0 -0
  50. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/algo/extremum.rs +0 -0
  51. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/algo/ma.rs +0 -0
  52. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/algo/mod.rs +0 -0
  53. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/algo/neutralize.rs +0 -0
  54. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/algo/rank.rs +0 -0
  55. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/algo/returns.rs +0 -0
  56. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/algo/series.rs +0 -0
  57. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/algo/skip_nan_window.rs +0 -0
  58. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/algo/stats.rs +0 -0
  59. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/algo/stddev.rs +0 -0
  60. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/algo/sum.rs +0 -0
  61. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/src/lib.rs +0 -0
  62. {py_alpha_lib-0.1.1 → py_alpha_lib-0.1.2}/tests/rank.py +0 -0
  63. {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!
@@ -4,7 +4,7 @@ version = 4
4
4
 
5
5
  [[package]]
6
6
  name = "alpha"
7
- version = "0.1.1"
7
+ version = "0.1.2"
8
8
  dependencies = [
9
9
  "anyhow",
10
10
  "log",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "alpha"
3
- version = "0.1.1"
3
+ version = "0.1.2"
4
4
  edition = "2024"
5
5
  authors = ["ElseJJ"]
6
6
  readme = "README.md"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: py-alpha-lib
3
- Version: 0.1.1
3
+ Version: 0.1.2
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Classifier: Programming Language :: Python :: Implementation :: PyPy
@@ -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 ta_linear_reg_core<NumT, F>(
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
- ta_linear_reg_core(ctx, r, input, periods, |n, sum_x, sum_x2, sum_y, sum_xy| {
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
- ta_linear_reg_core(ctx, r, input, periods, |n, sum_x, sum_x2, sum_y, sum_xy| {
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)
@@ -1,15 +0,0 @@
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.
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes