py-alpha-lib 0.1.0__cp311-abi3-musllinux_1_2_x86_64.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 ADDED
@@ -0,0 +1,8 @@
1
+ from .algo import *
2
+ from .lang import *
3
+
4
+
5
+ # skip nan values during computations
6
+ FLAG_SKIP_NAN: int = 1
7
+ # strictly cycle over the data
8
+ FLAG_STRICTLY_CYCLE: int = 2
alpha/algo/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ from .algo import EMA
2
+ from .algo_gen import *
3
+ from ._algo import set_ctx
Binary file
alpha/algo/algo.md ADDED
@@ -0,0 +1,98 @@
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
+
alpha/algo/algo.py ADDED
@@ -0,0 +1,29 @@
1
+ import numpy as np
2
+ from . import _algo
3
+
4
+
5
+ def EMA(
6
+ input: np.ndarray | list[np.ndarray], period: int
7
+ ) -> np.ndarray | list[np.ndarray]:
8
+ """
9
+ Exponential Moving Average (variant of EMA)
10
+
11
+ alpha = 2 / (n + 1)
12
+
13
+ https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average
14
+
15
+ Args:
16
+ input: input array
17
+ period: period
18
+
19
+ Returns:
20
+ output array
21
+ """
22
+ if isinstance(input, list):
23
+ r = [np.empty_like(x) for x in input]
24
+ _algo.ema(r, input, period)
25
+ return r
26
+ else:
27
+ r = np.empty_like(input)
28
+ _algo.ema(r, input, period)
29
+ return r
alpha/algo/algo_gen.py ADDED
@@ -0,0 +1,456 @@
1
+ # THIS FILE IS AUTO-GENERATED, DO NOT EDIT
2
+
3
+ import numpy as np
4
+ from . import _algo
5
+
6
+ def BARSLAST(
7
+ input: np.ndarray | list[np.ndarray]
8
+ ) -> np.ndarray | list[np.ndarray]:
9
+ """
10
+ Calculate number of bars since last condition true
11
+
12
+ Ref: https://www.amibroker.com/guide/afl/barslast.html
13
+ """
14
+ if isinstance(input, list):
15
+ r = [np.empty_like(x, dtype=float) for x in input]
16
+ input = [x.astype(bool) for x in input]
17
+ _algo.barslast(r, input)
18
+ return r
19
+ else:
20
+ r = np.empty_like(input, dtype=float)
21
+ input = input.astype(bool)
22
+ _algo.barslast(r, input)
23
+ return r
24
+
25
+ def BARSSINCE(
26
+ input: np.ndarray | list[np.ndarray]
27
+ ) -> np.ndarray | list[np.ndarray]:
28
+ """
29
+ Calculate number of bars since first condition true
30
+
31
+ Ref: https://www.amibroker.com/guide/afl/barssince.html
32
+ """
33
+ if isinstance(input, list):
34
+ r = [np.empty_like(x, dtype=float) for x in input]
35
+ input = [x.astype(bool) for x in input]
36
+ _algo.barssince(r, input)
37
+ return r
38
+ else:
39
+ r = np.empty_like(input, dtype=float)
40
+ input = input.astype(bool)
41
+ _algo.barssince(r, input)
42
+ return r
43
+
44
+ def CORR(
45
+ x: np.ndarray | list[np.ndarray], y: np.ndarray | list[np.ndarray], periods: int
46
+ ) -> np.ndarray | list[np.ndarray]:
47
+ """
48
+ Calculate Correlation over a moving window
49
+
50
+ Correlation = Cov(X, Y) / (StdDev(X) * StdDev(Y))
51
+ """
52
+ if isinstance(x, list) and isinstance(y, list):
53
+ r = [np.empty_like(x) for x in x]
54
+ x = [x.astype(float) for x in x]
55
+ y = [x.astype(float) for x in y]
56
+ _algo.corr(r, x, y, periods)
57
+ return r
58
+ else:
59
+ r = np.empty_like(x)
60
+ x = x.astype(float)
61
+ y = y.astype(float)
62
+ _algo.corr(r, x, y, periods)
63
+ return r
64
+
65
+ def COUNT(
66
+ input: np.ndarray | list[np.ndarray], periods: int
67
+ ) -> np.ndarray | list[np.ndarray]:
68
+ """
69
+ Calculate number of periods where condition is true in passed `periods` window
70
+
71
+ Ref: https://www.amibroker.com/guide/afl/count.html
72
+ """
73
+ if isinstance(input, list):
74
+ r = [np.empty_like(x, dtype=float) for x in input]
75
+ input = [x.astype(bool) for x in input]
76
+ _algo.count(r, input, periods)
77
+ return r
78
+ else:
79
+ r = np.empty_like(input, dtype=float)
80
+ input = input.astype(bool)
81
+ _algo.count(r, input, periods)
82
+ return r
83
+
84
+ def COV(
85
+ x: np.ndarray | list[np.ndarray], y: np.ndarray | list[np.ndarray], periods: int
86
+ ) -> np.ndarray | list[np.ndarray]:
87
+ """
88
+ Calculate Covariance over a moving window
89
+
90
+ Covariance = (SumXY - (SumX * SumY) / N) / (N - 1)
91
+ """
92
+ if isinstance(x, list) and isinstance(y, list):
93
+ r = [np.empty_like(x) for x in x]
94
+ x = [x.astype(float) for x in x]
95
+ y = [x.astype(float) for x in y]
96
+ _algo.cov(r, x, y, periods)
97
+ return r
98
+ else:
99
+ r = np.empty_like(x)
100
+ x = x.astype(float)
101
+ y = y.astype(float)
102
+ _algo.cov(r, x, y, periods)
103
+ return r
104
+
105
+ def CROSS(
106
+ a: np.ndarray | list[np.ndarray], b: np.ndarray | list[np.ndarray]
107
+ ) -> np.ndarray | list[np.ndarray]:
108
+ """
109
+ For 2 arrays A and B, return true if A[i-1] < B[i-1] and A[i] >= B[i]
110
+ alias: golden_cross, cross_ge
111
+ """
112
+ if isinstance(a, list) and isinstance(b, list):
113
+ r = [np.empty_like(x, dtype=bool) for x in a]
114
+ a = [x.astype(float) for x in a]
115
+ b = [x.astype(float) for x in b]
116
+ _algo.cross(r, a, b)
117
+ return r
118
+ else:
119
+ r = np.empty_like(a, dtype=bool)
120
+ a = a.astype(float)
121
+ b = b.astype(float)
122
+ _algo.cross(r, a, b)
123
+ return r
124
+
125
+ def DMA(
126
+ input: np.ndarray | list[np.ndarray], weight: float
127
+ ) -> np.ndarray | list[np.ndarray]:
128
+ """
129
+ Exponential Moving Average
130
+ current = weight * current + (1 - weight) * previous
131
+
132
+ Ref: https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average
133
+ """
134
+ if isinstance(input, list):
135
+ r = [np.empty_like(x) for x in input]
136
+ _algo.dma(r, input, weight)
137
+ return r
138
+ else:
139
+ r = np.empty_like(input)
140
+ _algo.dma(r, input, weight)
141
+ return r
142
+
143
+ def HHV(
144
+ input: np.ndarray | list[np.ndarray], periods: int
145
+ ) -> np.ndarray | list[np.ndarray]:
146
+ """
147
+ Find highest value in a preceding `periods` window
148
+
149
+ Ref: https://www.amibroker.com/guide/afl/hhv.html
150
+ """
151
+ if isinstance(input, list):
152
+ r = [np.empty_like(x) for x in input]
153
+ _algo.hhv(r, input, periods)
154
+ return r
155
+ else:
156
+ r = np.empty_like(input)
157
+ _algo.hhv(r, input, periods)
158
+ return r
159
+
160
+ def HHVBARS(
161
+ input: np.ndarray | list[np.ndarray], periods: int
162
+ ) -> np.ndarray | list[np.ndarray]:
163
+ """
164
+ The number of periods that have passed since the array reached its `periods` period high
165
+
166
+ Ref: https://www.amibroker.com/guide/afl/hhvbars.html
167
+ """
168
+ if isinstance(input, list):
169
+ r = [np.empty_like(x) for x in input]
170
+ _algo.hhvbars(r, input, periods)
171
+ return r
172
+ else:
173
+ r = np.empty_like(input)
174
+ _algo.hhvbars(r, input, periods)
175
+ return r
176
+
177
+ def LLV(
178
+ input: np.ndarray | list[np.ndarray], periods: int
179
+ ) -> np.ndarray | list[np.ndarray]:
180
+ """
181
+ Find lowest value in a preceding `periods` window
182
+
183
+ Ref: https://www.amibroker.com/guide/afl/llv.html
184
+ """
185
+ if isinstance(input, list):
186
+ r = [np.empty_like(x) for x in input]
187
+ _algo.llv(r, input, periods)
188
+ return r
189
+ else:
190
+ r = np.empty_like(input)
191
+ _algo.llv(r, input, periods)
192
+ return r
193
+
194
+ def LLVBARS(
195
+ input: np.ndarray | list[np.ndarray], periods: int
196
+ ) -> np.ndarray | list[np.ndarray]:
197
+ """
198
+ The number of periods that have passed since the array reached its periods period low
199
+
200
+ Ref: https://www.amibroker.com/guide/afl/llvbars.html
201
+ """
202
+ if isinstance(input, list):
203
+ r = [np.empty_like(x) for x in input]
204
+ _algo.llvbars(r, input, periods)
205
+ return r
206
+ else:
207
+ r = np.empty_like(input)
208
+ _algo.llvbars(r, input, periods)
209
+ return r
210
+
211
+ def LONGCROSS(
212
+ a: np.ndarray | list[np.ndarray], b: np.ndarray | list[np.ndarray], n: int
213
+ ) -> np.ndarray | list[np.ndarray]:
214
+ """
215
+ For 2 arrays A and B, return true if previous N periods A < B, Current A >= B
216
+ """
217
+ if isinstance(a, list) and isinstance(b, list):
218
+ r = [np.empty_like(x, dtype=bool) for x in a]
219
+ a = [x.astype(float) for x in a]
220
+ b = [x.astype(float) for x in b]
221
+ _algo.longcross(r, a, b, n)
222
+ return r
223
+ else:
224
+ r = np.empty_like(a, dtype=bool)
225
+ a = a.astype(float)
226
+ b = b.astype(float)
227
+ _algo.longcross(r, a, b, n)
228
+ return r
229
+
230
+ def LWMA(
231
+ input: np.ndarray | list[np.ndarray], periods: int
232
+ ) -> np.ndarray | list[np.ndarray]:
233
+ """
234
+ Linear Weighted Moving Average
235
+
236
+ LWMA = SUM(Price * Weight) / SUM(Weight)
237
+ """
238
+ if isinstance(input, list):
239
+ r = [np.empty_like(x) for x in input]
240
+ _algo.lwma(r, input, periods)
241
+ return r
242
+ else:
243
+ r = np.empty_like(input)
244
+ _algo.lwma(r, input, periods)
245
+ return r
246
+
247
+ def MA(
248
+ input: np.ndarray | list[np.ndarray], periods: int
249
+ ) -> np.ndarray | list[np.ndarray]:
250
+ """
251
+ Simple Moving Average, also known as arithmetic moving average
252
+
253
+ Ref: https://en.wikipedia.org/wiki/Moving_average#Simple_moving_average
254
+ """
255
+ if isinstance(input, list):
256
+ r = [np.empty_like(x) for x in input]
257
+ _algo.ma(r, input, periods)
258
+ return r
259
+ else:
260
+ r = np.empty_like(input)
261
+ _algo.ma(r, input, periods)
262
+ return r
263
+
264
+ def PRODUCT(
265
+ input: np.ndarray | list[np.ndarray], periods: int
266
+ ) -> np.ndarray | list[np.ndarray]:
267
+ """
268
+ Calculate product of values in preceding `periods` window
269
+
270
+ If periods is 0, it calculates the cumulative product from the first valid value.
271
+
272
+ Ref: https://www.amibroker.com/guide/afl/product.html
273
+ """
274
+ if isinstance(input, list):
275
+ r = [np.empty_like(x) for x in input]
276
+ _algo.product(r, input, periods)
277
+ return r
278
+ else:
279
+ r = np.empty_like(input)
280
+ _algo.product(r, input, periods)
281
+ return r
282
+
283
+ def RANK(
284
+ input: np.ndarray | list[np.ndarray]
285
+ ) -> np.ndarray | list[np.ndarray]:
286
+ """
287
+ Calculate rank percentage cross group dimension, the ctx.groups() is the number of groups
288
+ Same value are averaged
289
+ """
290
+ if isinstance(input, list):
291
+ r = [np.empty_like(x) for x in input]
292
+ _algo.rank(r, input)
293
+ return r
294
+ else:
295
+ r = np.empty_like(input)
296
+ _algo.rank(r, input)
297
+ return r
298
+
299
+ def RCROSS(
300
+ a: np.ndarray | list[np.ndarray], b: np.ndarray | list[np.ndarray]
301
+ ) -> np.ndarray | list[np.ndarray]:
302
+ """
303
+ For 2 arrays A and B, return true if A[i-1] > B[i-1] and A[i] <= B[i]
304
+ alias: death_cross, cross_le
305
+ """
306
+ if isinstance(a, list) and isinstance(b, list):
307
+ r = [np.empty_like(x, dtype=bool) for x in a]
308
+ a = [x.astype(float) for x in a]
309
+ b = [x.astype(float) for x in b]
310
+ _algo.rcross(r, a, b)
311
+ return r
312
+ else:
313
+ r = np.empty_like(a, dtype=bool)
314
+ a = a.astype(float)
315
+ b = b.astype(float)
316
+ _algo.rcross(r, a, b)
317
+ return r
318
+
319
+ def REF(
320
+ input: np.ndarray | list[np.ndarray], periods: int
321
+ ) -> np.ndarray | list[np.ndarray]:
322
+ """
323
+ Right shift input array by `periods`, r[i] = input[i - periods]
324
+
325
+ Ref: https://www.amibroker.com/guide/afl/ref.html
326
+ """
327
+ if isinstance(input, list):
328
+ r = [np.empty_like(x) for x in input]
329
+ _algo.ref(r, input, periods)
330
+ return r
331
+ else:
332
+ r = np.empty_like(input)
333
+ _algo.ref(r, input, periods)
334
+ return r
335
+
336
+ def RLONGCROSS(
337
+ a: np.ndarray | list[np.ndarray], b: np.ndarray | list[np.ndarray], n: int
338
+ ) -> np.ndarray | list[np.ndarray]:
339
+ """
340
+ For 2 arrays A and B, return true if previous N periods A > B, Current A <= B
341
+ """
342
+ if isinstance(a, list) and isinstance(b, list):
343
+ r = [np.empty_like(x, dtype=bool) for x in a]
344
+ a = [x.astype(float) for x in a]
345
+ b = [x.astype(float) for x in b]
346
+ _algo.rlongcross(r, a, b, n)
347
+ return r
348
+ else:
349
+ r = np.empty_like(a, dtype=bool)
350
+ a = a.astype(float)
351
+ b = b.astype(float)
352
+ _algo.rlongcross(r, a, b, n)
353
+ return r
354
+
355
+ def SMA(
356
+ input: np.ndarray | list[np.ndarray], n: int, m: int
357
+ ) -> np.ndarray | list[np.ndarray]:
358
+ """
359
+ Exponential Moving Average (variant of well-known EMA) weight = m / n
360
+
361
+ Ref: https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average
362
+ """
363
+ if isinstance(input, list):
364
+ r = [np.empty_like(x) for x in input]
365
+ _algo.sma(r, input, n, m)
366
+ return r
367
+ else:
368
+ r = np.empty_like(input)
369
+ _algo.sma(r, input, n, m)
370
+ return r
371
+
372
+ def STDDEV(
373
+ input: np.ndarray | list[np.ndarray], periods: int
374
+ ) -> np.ndarray | list[np.ndarray]:
375
+ """
376
+ Calculate Standard Deviation over a moving window
377
+
378
+ Ref: https://en.wikipedia.org/wiki/Standard_deviation
379
+ """
380
+ if isinstance(input, list):
381
+ r = [np.empty_like(x) for x in input]
382
+ _algo.stddev(r, input, periods)
383
+ return r
384
+ else:
385
+ r = np.empty_like(input)
386
+ _algo.stddev(r, input, periods)
387
+ return r
388
+
389
+ def SUM(
390
+ input: np.ndarray | list[np.ndarray], periods: int
391
+ ) -> np.ndarray | list[np.ndarray]:
392
+ """
393
+ Calculate sum of values in preceding `periods` window
394
+
395
+ If periods is 0, it calculates the cumulative sum from the first valid value.
396
+
397
+ Ref: https://www.amibroker.com/guide/afl/sum.html
398
+ """
399
+ if isinstance(input, list):
400
+ r = [np.empty_like(x) for x in input]
401
+ _algo.sum(r, input, periods)
402
+ return r
403
+ else:
404
+ r = np.empty_like(input)
405
+ _algo.sum(r, input, periods)
406
+ return r
407
+
408
+ def SUMBARS(
409
+ input: np.ndarray | list[np.ndarray], amount: float
410
+ ) -> np.ndarray | list[np.ndarray]:
411
+ """
412
+ Calculate number of periods (bars) backwards until the sum of values is greater than or equal to `amount`
413
+
414
+ Ref: https://www.amibroker.com/guide/afl/sumbars.html
415
+ """
416
+ if isinstance(input, list):
417
+ r = [np.empty_like(x) for x in input]
418
+ _algo.sumbars(r, input, amount)
419
+ return r
420
+ else:
421
+ r = np.empty_like(input)
422
+ _algo.sumbars(r, input, amount)
423
+ return r
424
+
425
+ def TS_RANK(
426
+ input: np.ndarray | list[np.ndarray], periods: int
427
+ ) -> np.ndarray | list[np.ndarray]:
428
+ """
429
+ Calculate rank in a sliding window with size `periods`
430
+ """
431
+ if isinstance(input, list):
432
+ r = [np.empty_like(x) for x in input]
433
+ _algo.ts_rank(r, input, periods)
434
+ return r
435
+ else:
436
+ r = np.empty_like(input)
437
+ _algo.ts_rank(r, input, periods)
438
+ return r
439
+
440
+ def VAR(
441
+ input: np.ndarray | list[np.ndarray], periods: int
442
+ ) -> np.ndarray | list[np.ndarray]:
443
+ """
444
+ Calculate Variance over a moving window
445
+
446
+ Variance = (SumSq - (Sum^2)/N) / (N - 1)
447
+ """
448
+ if isinstance(input, list):
449
+ r = [np.empty_like(x) for x in input]
450
+ _algo.var(r, input, periods)
451
+ return r
452
+ else:
453
+ r = np.empty_like(input)
454
+ _algo.var(r, input, periods)
455
+ return r
456
+
alpha/algo.md ADDED
@@ -0,0 +1,30 @@
1
+ List of available functions with python type hints:
2
+
3
+ the `np.ndarray` is `ndarray` type in `numpy` package
4
+
5
+ - BARSLAST(input: np.ndarray[bool]): Calculate number of bars since last condition true
6
+ - BARSSINCE(input: np.ndarray[bool]): Calculate number of bars since first condition true
7
+ - 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
+ - COUNT(input: np.ndarray[bool], periods: int): Calculate number of periods where condition is true in passed `periods` window
9
+ - 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
+ - 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
+ - DMA(input: np.ndarray[float], weight: float): Exponential Moving Average current = weight * current + (1 - weight) * previous
12
+ - EMA(input: np.ndarray[float], periods: int): Exponential Moving Average (variant of well-known EMA) weight = 2 / (n + 1)
13
+ - HHV(input: np.ndarray[float], periods: int): Find highest value in a preceding `periods` window
14
+ - HHVBARS(input: np.ndarray[float], periods: int): The number of periods that have passed since the array reached its `periods` period high
15
+ - LLV(input: np.ndarray[float], periods: int): Find lowest value in a preceding `periods` window
16
+ - LLVBARS(input: np.ndarray[float], periods: int): The number of periods that have passed since the array reached its periods period low
17
+ - 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
+ - LWMA(input: np.ndarray[float], periods: int): Linear Weighted Moving Average LWMA = SUM(Price * Weight) / SUM(Weight)
19
+ - MA(input: np.ndarray[float], periods: int): Simple Moving Average, also known as arithmetic moving average
20
+ - 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
+ - RANK(input: np.ndarray[float]): Calculate rank percentage cross group dimension, the ctx.groups() is the number of groups Same value are averaged
22
+ - 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
+ - REF(input: np.ndarray[float], periods: int): Right shift input array by `periods`, r[i] = input[i - periods]
24
+ - 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
25
+ - SMA(input: np.ndarray[float], n: int, m: int): Exponential Moving Average (variant of well-known EMA) weight = m / n
26
+ - STDDEV(input: np.ndarray[float], periods: int): Calculate Standard Deviation over a moving window
27
+ - 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
+ - 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`
29
+ - TS_RANK(input: np.ndarray[float], periods: int): Calculate rank in a sliding window with size `periods`
30
+ - VAR(input: np.ndarray[float], periods: int): Calculate Variance over a moving window Variance = (SumSq - (Sum^2)/N) / (N - 1)
alpha/lang/__init__.py ADDED
@@ -0,0 +1 @@
1
+ from .to_python import to_python, to_python_file
alpha/lang/__main__.py ADDED
@@ -0,0 +1,17 @@
1
+ from .to_python import to_python_file
2
+
3
+ if __name__ == "__main__":
4
+ import sys
5
+ import pathlib
6
+
7
+ if len(sys.argv) < 2:
8
+ print("Usage: python -m alpha.lang <file | code>")
9
+ sys.exit(1)
10
+
11
+ file_path = pathlib.Path(sys.argv[1])
12
+ if file_path.exists():
13
+ codes = file_path.read_text().splitlines()
14
+ to_python_file(codes, name_convertor=lambda x: x.upper())
15
+ else:
16
+ code = "\n".join(sys.argv[1:])
17
+ to_python_file([code], name_convertor=lambda x: x.upper())
alpha/lang/alpha.lark ADDED
@@ -0,0 +1,49 @@
1
+ start: expression
2
+
3
+ ?expression: ternary_expr
4
+
5
+ ?ternary_expr: logical_or_expr "?" ternary_expr ":" ternary_expr
6
+ | logical_or_expr
7
+
8
+ ?logical_or_expr: logical_and_expr ("||" logical_and_expr)*
9
+
10
+ ?logical_and_expr: comparison_expr ("&&" comparison_expr)*
11
+
12
+ ?comparison_expr: sum "==" sum -> eq
13
+ | sum "!=" sum -> ne
14
+ | sum "<" sum -> lt
15
+ | sum ">" sum -> gt
16
+ | sum "<=" sum -> le
17
+ | sum ">=" sum -> ge
18
+ | sum
19
+
20
+ ?sum: product (add_op product)*
21
+
22
+ ?product: power (mul_op power)*
23
+
24
+ ?power: atom (POWER atom)*
25
+
26
+ ?atom: MINUS atom -> neg
27
+ | func_call
28
+ | NUMBER
29
+ | NAME
30
+ | NAME "." NAME -> dotted_name
31
+ | "(" expression ")"
32
+
33
+ !add_op: PLUS | MINUS
34
+ !mul_op: STAR | DIV
35
+
36
+ func_call: NAME "(" [arguments] ")"
37
+ arguments: expression ("," expression)*
38
+
39
+ // Terminals
40
+ PLUS: "+"
41
+ MINUS: "-"
42
+ STAR: "*"
43
+ DIV: "/"
44
+ POWER: "^"
45
+ NUMBER: /\d+(\.\d*)?|\.\d+/
46
+ NAME: /[a-zA-Z_]\w*/
47
+
48
+ %import common.WS
49
+ %ignore WS