polars-ta 0.4.7__py3-none-any.whl → 0.5.1__py3-none-any.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.
- polars_ta/__init__.py +4 -1
- polars_ta/_version.py +1 -1
- polars_ta/talib/__init__.py +98 -98
- polars_ta/utils/numba_.py +88 -7
- polars_ta/utils/pandas_.py +4 -4
- polars_ta/wq/_nb.py +147 -123
- polars_ta/wq/time_series.py +146 -90
- {polars_ta-0.4.7.dist-info → polars_ta-0.5.1.dist-info}/METADATA +41 -54
- {polars_ta-0.4.7.dist-info → polars_ta-0.5.1.dist-info}/RECORD +12 -12
- {polars_ta-0.4.7.dist-info → polars_ta-0.5.1.dist-info}/WHEEL +1 -1
- {polars_ta-0.4.7.dist-info → polars_ta-0.5.1.dist-info}/licenses/LICENSE +0 -0
- {polars_ta-0.4.7.dist-info → polars_ta-0.5.1.dist-info}/top_level.txt +0 -0
polars_ta/wq/time_series.py
CHANGED
@@ -1,14 +1,17 @@
|
|
1
|
+
from typing import Optional
|
2
|
+
|
1
3
|
import polars_ols as pls
|
2
4
|
from polars import Expr, UInt16, struct, when, Struct, Field, Float64, Boolean, UInt32
|
3
5
|
from polars import rolling_corr, rolling_cov
|
4
6
|
from polars_ols import RollingKwargs
|
5
7
|
|
6
|
-
|
8
|
+
import polars_ta
|
9
|
+
from polars_ta.utils.numba_ import batches_i1_o1, batches_i2_o1, batches_i2_o2, struct_to_numpy
|
7
10
|
from polars_ta.utils.pandas_ import roll_kurt, roll_rank
|
8
|
-
from polars_ta.wq._nb import roll_argmax, roll_argmin,
|
11
|
+
from polars_ta.wq._nb import roll_argmax, roll_argmin, roll_co_kurtosis, roll_co_skewness, roll_moment, roll_partial_corr, roll_triple_corr, _cum_prod_by, _cum_sum_by, _signals_to_size, _cum_sum_reset, _sum_split_by, roll_decay_linear, roll_decay_exp_window, roll_prod
|
9
12
|
|
10
13
|
|
11
|
-
def ts_arg_max(x: Expr, d: int = 5, reverse: bool = True) -> Expr:
|
14
|
+
def ts_arg_max(x: Expr, d: int = 5, reverse: bool = True, min_samples: Optional[int] = None) -> Expr:
|
12
15
|
"""Returns the relative index of the max value in the time series for the past d days.
|
13
16
|
If the current day has the max value for the past d days, it returns 0.
|
14
17
|
If previous day has the max value for the past d days, it returns 1.
|
@@ -19,6 +22,7 @@ def ts_arg_max(x: Expr, d: int = 5, reverse: bool = True) -> Expr:
|
|
19
22
|
d
|
20
23
|
reverse
|
21
24
|
反向
|
25
|
+
min_samples
|
22
26
|
|
23
27
|
See Also
|
24
28
|
--------
|
@@ -52,10 +56,11 @@ def ts_arg_max(x: Expr, d: int = 5, reverse: bool = True) -> Expr:
|
|
52
56
|
https://platform.worldquantbrain.com/learn/operators/detailed-operator-descriptions#ts_arg_maxx-d
|
53
57
|
|
54
58
|
"""
|
55
|
-
|
59
|
+
minp = min_samples or polars_ta.MIN_SAMPLES or d
|
60
|
+
return x.map_batches(lambda x1: batches_i1_o1(x1.to_numpy(), roll_argmax, d, minp, reverse, dtype=UInt16))
|
56
61
|
|
57
62
|
|
58
|
-
def ts_arg_min(x: Expr, d: int = 5, reverse: bool = True) -> Expr:
|
63
|
+
def ts_arg_min(x: Expr, d: int = 5, reverse: bool = True, min_samples: Optional[int] = None) -> Expr:
|
59
64
|
"""
|
60
65
|
|
61
66
|
Parameters
|
@@ -64,6 +69,7 @@ def ts_arg_min(x: Expr, d: int = 5, reverse: bool = True) -> Expr:
|
|
64
69
|
d
|
65
70
|
reverse
|
66
71
|
反向
|
72
|
+
min_samples
|
67
73
|
|
68
74
|
See Also
|
69
75
|
--------
|
@@ -74,18 +80,21 @@ def ts_arg_min(x: Expr, d: int = 5, reverse: bool = True) -> Expr:
|
|
74
80
|
https://platform.worldquantbrain.com/learn/operators/detailed-operator-descriptions#ts_arg_minx-d
|
75
81
|
|
76
82
|
"""
|
77
|
-
|
83
|
+
minp = min_samples or polars_ta.MIN_SAMPLES or d
|
84
|
+
return x.map_batches(lambda x1: batches_i1_o1(x1.to_numpy(), roll_argmin, d, minp, reverse, dtype=UInt16))
|
78
85
|
|
79
86
|
|
80
|
-
def ts_co_kurtosis(x: Expr, y: Expr, d: int = 5, ddof: int = 0) -> Expr:
|
81
|
-
|
87
|
+
def ts_co_kurtosis(x: Expr, y: Expr, d: int = 5, ddof: int = 0, min_samples: Optional[int] = None) -> Expr:
|
88
|
+
minp = min_samples or polars_ta.MIN_SAMPLES or d
|
89
|
+
return struct([x, y]).map_batches(lambda xx: batches_i2_o1(struct_to_numpy(xx, 2), roll_co_kurtosis, d, minp))
|
82
90
|
|
83
91
|
|
84
|
-
def ts_co_skewness(x: Expr, y: Expr, d: int = 5, ddof: int = 0) -> Expr:
|
85
|
-
|
92
|
+
def ts_co_skewness(x: Expr, y: Expr, d: int = 5, ddof: int = 0, min_samples: Optional[int] = None) -> Expr:
|
93
|
+
minp = min_samples or polars_ta.MIN_SAMPLES or d
|
94
|
+
return struct([x, y]).map_batches(lambda xx: batches_i2_o1(struct_to_numpy(xx, 2), roll_co_skewness, d, minp))
|
86
95
|
|
87
96
|
|
88
|
-
def ts_corr(x: Expr, y: Expr, d: int = 5, ddof: int = 1) -> Expr:
|
97
|
+
def ts_corr(x: Expr, y: Expr, d: int = 5, ddof: int = 1, min_samples: Optional[int] = None) -> Expr:
|
89
98
|
"""rolling correlation between two columns
|
90
99
|
|
91
100
|
时序滚动相关系数
|
@@ -97,22 +106,25 @@ def ts_corr(x: Expr, y: Expr, d: int = 5, ddof: int = 1) -> Expr:
|
|
97
106
|
d
|
98
107
|
ddof
|
99
108
|
自由度
|
109
|
+
min_samples
|
100
110
|
|
101
111
|
Notes
|
102
112
|
-----
|
103
113
|
x、y不区分先后
|
104
114
|
|
105
115
|
"""
|
106
|
-
|
116
|
+
minp = min_samples or polars_ta.MIN_SAMPLES
|
117
|
+
return rolling_corr(x, y, window_size=d, ddof=ddof, min_samples=minp)
|
107
118
|
|
108
119
|
|
109
|
-
def ts_count(x: Expr, d: int = 30) -> Expr:
|
120
|
+
def ts_count(x: Expr, d: int = 30, min_samples: Optional[int] = None) -> Expr:
|
110
121
|
"""时序滚动计数
|
111
122
|
|
112
123
|
Parameters
|
113
124
|
----------
|
114
125
|
x
|
115
126
|
d
|
127
|
+
min_samples
|
116
128
|
|
117
129
|
Examples
|
118
130
|
--------
|
@@ -141,16 +153,18 @@ def ts_count(x: Expr, d: int = 30) -> Expr:
|
|
141
153
|
```
|
142
154
|
|
143
155
|
"""
|
144
|
-
|
156
|
+
minp = min_samples or polars_ta.MIN_SAMPLES
|
157
|
+
return x.cast(Boolean).cast(UInt32).rolling_sum(d, min_samples=minp)
|
145
158
|
|
146
159
|
|
147
|
-
def ts_count_nans(x: Expr, d: int = 5) -> Expr:
|
160
|
+
def ts_count_nans(x: Expr, d: int = 5, min_samples: Optional[int] = None) -> Expr:
|
148
161
|
"""时序滚动统计nan出现次数
|
149
162
|
|
150
163
|
Parameters
|
151
164
|
----------
|
152
165
|
x
|
153
166
|
d
|
167
|
+
min_samples
|
154
168
|
|
155
169
|
Examples
|
156
170
|
--------
|
@@ -178,16 +192,18 @@ def ts_count_nans(x: Expr, d: int = 5) -> Expr:
|
|
178
192
|
```
|
179
193
|
|
180
194
|
"""
|
181
|
-
|
195
|
+
minp = min_samples or polars_ta.MIN_SAMPLES
|
196
|
+
return x.is_nan().cast(UInt32).rolling_sum(d, min_samples=minp)
|
182
197
|
|
183
198
|
|
184
|
-
def ts_count_nulls(x: Expr, d: int = 5) -> Expr:
|
199
|
+
def ts_count_nulls(x: Expr, d: int = 5, min_samples: Optional[int] = None) -> Expr:
|
185
200
|
"""时序滚动统计null出现次数
|
186
201
|
|
187
202
|
Parameters
|
188
203
|
----------
|
189
204
|
x
|
190
205
|
d
|
206
|
+
min_samples
|
191
207
|
|
192
208
|
Examples
|
193
209
|
--------
|
@@ -215,10 +231,11 @@ def ts_count_nulls(x: Expr, d: int = 5) -> Expr:
|
|
215
231
|
```
|
216
232
|
|
217
233
|
"""
|
218
|
-
|
234
|
+
minp = min_samples or polars_ta.MIN_SAMPLES
|
235
|
+
return x.is_null().cast(UInt32).rolling_sum(d, min_samples=minp)
|
219
236
|
|
220
237
|
|
221
|
-
def ts_covariance(x: Expr, y: Expr, d: int = 5, ddof: int = 1) -> Expr:
|
238
|
+
def ts_covariance(x: Expr, y: Expr, d: int = 5, ddof: int = 1, min_samples: Optional[int] = None) -> Expr:
|
222
239
|
"""rolling covariance between two columns
|
223
240
|
|
224
241
|
时序协方差
|
@@ -230,13 +247,15 @@ def ts_covariance(x: Expr, y: Expr, d: int = 5, ddof: int = 1) -> Expr:
|
|
230
247
|
d
|
231
248
|
ddof
|
232
249
|
自由度
|
250
|
+
min_samples
|
233
251
|
|
234
252
|
Notes
|
235
253
|
-----
|
236
254
|
x、y不区分先后
|
237
255
|
|
238
256
|
"""
|
239
|
-
|
257
|
+
minp = min_samples or polars_ta.MIN_SAMPLES
|
258
|
+
return rolling_cov(x, y, window_size=d, ddof=ddof, min_samples=minp)
|
240
259
|
|
241
260
|
|
242
261
|
def ts_cum_count(x: Expr) -> Expr:
|
@@ -379,12 +398,14 @@ def ts_cum_sum_reset(x: Expr) -> Expr:
|
|
379
398
|
return x.map_batches(lambda x1: batches_i1_o1(x1.to_numpy().astype(float), _cum_sum_reset))
|
380
399
|
|
381
400
|
|
382
|
-
def ts_decay_exp_window(x: Expr, d: int = 30, factor: float = 1.0) -> Expr:
|
401
|
+
def ts_decay_exp_window(x: Expr, d: int = 30, factor: float = 1.0, min_samples: Optional[int] = None) -> Expr:
|
383
402
|
"""指数衰减移动平均
|
384
403
|
|
385
404
|
Examples
|
386
405
|
--------
|
387
406
|
```python
|
407
|
+
from polars_ta.wq.time_series import ts_decay_linear, ts_decay_exp_window
|
408
|
+
|
388
409
|
df = pl.DataFrame({
|
389
410
|
'a': [None, 6, 5, 4, 5, 30],
|
390
411
|
}).with_columns(
|
@@ -412,6 +433,7 @@ def ts_decay_exp_window(x: Expr, d: int = 30, factor: float = 1.0) -> Expr:
|
|
412
433
|
d
|
413
434
|
factor
|
414
435
|
衰减系数
|
436
|
+
min_samples
|
415
437
|
|
416
438
|
References
|
417
439
|
----------
|
@@ -422,21 +444,26 @@ def ts_decay_exp_window(x: Expr, d: int = 30, factor: float = 1.0) -> Expr:
|
|
422
444
|
# weights = repeat(factor, d, eager=True).pow(y)
|
423
445
|
# print(weights)
|
424
446
|
# return x.rolling_mean(d, weights=weights)
|
425
|
-
|
447
|
+
minp = min_samples or polars_ta.MIN_SAMPLES or d
|
448
|
+
return x.map_batches(lambda x1: batches_i1_o1(x1.to_numpy().astype(float), roll_decay_exp_window, d, minp, factor))
|
426
449
|
|
427
450
|
|
428
|
-
def ts_decay_linear(x: Expr, d: int = 30) -> Expr:
|
451
|
+
def ts_decay_linear(x: Expr, d: int = 30, min_samples: Optional[int] = None) -> Expr:
|
429
452
|
"""线性衰减移动平均
|
430
453
|
|
431
454
|
Examples
|
432
455
|
--------
|
433
456
|
```python
|
457
|
+
from polars_ta.talib import WMA as ts_WMA
|
458
|
+
from polars_ta.wq.time_series import ts_decay_linear
|
459
|
+
|
434
460
|
df = pl.DataFrame({
|
435
461
|
'a': [None, 6, 5, 4, 5, 30],
|
436
462
|
}).with_columns(
|
437
463
|
out1=ts_decay_linear(pl.col('a'), 5),
|
438
464
|
out2=ts_WMA(pl.col('a'), 5),
|
439
465
|
)
|
466
|
+
|
440
467
|
shape: (6, 3)
|
441
468
|
┌──────┬──────┬──────┐
|
442
469
|
│ a ┆ out1 ┆ out2 │
|
@@ -461,7 +488,8 @@ def ts_decay_linear(x: Expr, d: int = 30) -> Expr:
|
|
461
488
|
# weights = arange(1, d + 1, eager=True)
|
462
489
|
# # print(weights)
|
463
490
|
# return x.rolling_mean(d, weights=weights)
|
464
|
-
|
491
|
+
minp = min_samples or polars_ta.MIN_SAMPLES or d
|
492
|
+
return x.map_batches(lambda x1: batches_i1_o1(x1.to_numpy().astype(float), roll_decay_linear, d, minp))
|
465
493
|
|
466
494
|
|
467
495
|
def ts_delay(x: Expr, d: int = 1, fill_value=None) -> Expr:
|
@@ -522,12 +550,12 @@ def ts_fill_null(x: Expr, limit: int = None) -> Expr:
|
|
522
550
|
return x.forward_fill(limit)
|
523
551
|
|
524
552
|
|
525
|
-
def ts_ir(x: Expr, d: int = 1) -> Expr:
|
553
|
+
def ts_ir(x: Expr, d: int = 1, min_samples: Optional[int] = None) -> Expr:
|
526
554
|
"""时序滚动信息系数rolling information ratio"""
|
527
|
-
return ts_mean(x, d) / ts_std_dev(x, d, 0)
|
555
|
+
return ts_mean(x, d, min_samples) / ts_std_dev(x, d, 0, min_samples)
|
528
556
|
|
529
557
|
|
530
|
-
def ts_kurtosis(x: Expr, d: int = 5) -> Expr:
|
558
|
+
def ts_kurtosis(x: Expr, d: int = 5, min_samples: Optional[int] = None) -> Expr:
|
531
559
|
"""kurtosis of x for the last d days
|
532
560
|
|
533
561
|
时序滚动峰度
|
@@ -537,14 +565,16 @@ def ts_kurtosis(x: Expr, d: int = 5) -> Expr:
|
|
537
565
|
等待polars官方出rolling_kurt
|
538
566
|
|
539
567
|
"""
|
540
|
-
|
568
|
+
minp = min_samples or polars_ta.MIN_SAMPLES or d
|
569
|
+
return x.map_batches(lambda a: roll_kurt(a, d, minp))
|
541
570
|
|
542
571
|
|
543
|
-
def ts_l2_norm(x: Expr, d: int = 5) -> Expr:
|
572
|
+
def ts_l2_norm(x: Expr, d: int = 5, min_samples: Optional[int] = None) -> Expr:
|
544
573
|
"""Euclidean norm
|
545
574
|
|
546
575
|
欧几里得范数"""
|
547
|
-
|
576
|
+
minp = min_samples or polars_ta.MIN_SAMPLES
|
577
|
+
return x.pow(2).rolling_sum(d, min_samples=minp).sqrt()
|
548
578
|
|
549
579
|
|
550
580
|
def ts_log_diff(x: Expr, d: int = 1) -> Expr:
|
@@ -554,47 +584,51 @@ def ts_log_diff(x: Expr, d: int = 1) -> Expr:
|
|
554
584
|
return x.log().diff(d)
|
555
585
|
|
556
586
|
|
557
|
-
def ts_max(x: Expr, d: int = 30) -> Expr:
|
587
|
+
def ts_max(x: Expr, d: int = 30, min_samples: Optional[int] = None) -> Expr:
|
558
588
|
"""时序滚动最大值"""
|
559
|
-
|
589
|
+
minp = min_samples or polars_ta.MIN_SAMPLES
|
590
|
+
return x.rolling_max(d, min_samples=minp)
|
560
591
|
|
561
592
|
|
562
|
-
def ts_max_diff(x: Expr, d: int = 30) -> Expr:
|
593
|
+
def ts_max_diff(x: Expr, d: int = 30, min_samples: Optional[int] = None) -> Expr:
|
563
594
|
"""Returns x - ts_max(x, d)"""
|
564
|
-
return x - ts_max(x, d)
|
595
|
+
return x - ts_max(x, d, min_samples)
|
565
596
|
|
566
597
|
|
567
|
-
def ts_mean(x: Expr, d: int = 5) -> Expr:
|
598
|
+
def ts_mean(x: Expr, d: int = 5, min_samples: Optional[int] = None) -> Expr:
|
568
599
|
"""简单移动平均"""
|
569
|
-
|
600
|
+
minp = min_samples or polars_ta.MIN_SAMPLES
|
601
|
+
return x.rolling_mean(d, min_samples=minp)
|
570
602
|
|
571
603
|
|
572
|
-
def ts_median(x: Expr, d: int = 5) -> Expr:
|
604
|
+
def ts_median(x: Expr, d: int = 5, min_samples: Optional[int] = None) -> Expr:
|
573
605
|
"""时序滚动中位数"""
|
574
|
-
|
606
|
+
minp = min_samples or polars_ta.MIN_SAMPLES
|
607
|
+
return x.rolling_median(d, min_samples=minp)
|
575
608
|
|
576
609
|
|
577
|
-
def ts_min(x: Expr, d: int = 30) -> Expr:
|
610
|
+
def ts_min(x: Expr, d: int = 30, min_samples: Optional[int] = None) -> Expr:
|
578
611
|
"""时序滚动最小值"""
|
579
|
-
|
612
|
+
minp = min_samples or polars_ta.MIN_SAMPLES
|
613
|
+
return x.rolling_min(d, min_samples=minp)
|
580
614
|
|
581
615
|
|
582
|
-
def ts_min_diff(x: Expr, d: int = 30) -> Expr:
|
616
|
+
def ts_min_diff(x: Expr, d: int = 30, min_samples: Optional[int] = None) -> Expr:
|
583
617
|
"""Returns x - ts_min(x, d)"""
|
584
|
-
return x - ts_min(x, d)
|
618
|
+
return x - ts_min(x, d, min_samples)
|
585
619
|
|
586
620
|
|
587
|
-
def ts_min_max_cps(x: Expr, d: int, f: float = 2.0) -> Expr:
|
621
|
+
def ts_min_max_cps(x: Expr, d: int, f: float = 2.0, min_samples: Optional[int] = None) -> Expr:
|
588
622
|
"""Returns (ts_min(x, d) + ts_max(x, d)) - f * x"""
|
589
|
-
return (ts_min(x, d) + ts_max(x, d)) - f * x
|
623
|
+
return (ts_min(x, d, min_samples) + ts_max(x, d, min_samples)) - f * x
|
590
624
|
|
591
625
|
|
592
|
-
def ts_min_max_diff(x: Expr, d: int, f: float = 0.5) -> Expr:
|
626
|
+
def ts_min_max_diff(x: Expr, d: int, f: float = 0.5, min_samples: Optional[int] = None) -> Expr:
|
593
627
|
"""Returns x - f * (ts_min(x, d) + ts_max(x, d))"""
|
594
|
-
return x - f * (ts_min(x, d) + ts_max(x, d))
|
628
|
+
return x - f * (ts_min(x, d, min_samples) + ts_max(x, d, min_samples))
|
595
629
|
|
596
630
|
|
597
|
-
def ts_moment(x: Expr, d: int, k: int = 0) -> Expr:
|
631
|
+
def ts_moment(x: Expr, d: int, k: int = 0, min_samples: Optional[int] = None) -> Expr:
|
598
632
|
"""Returns K-th central moment of x for the past d days.
|
599
633
|
|
600
634
|
滚动k阶中心距
|
@@ -604,20 +638,23 @@ def ts_moment(x: Expr, d: int, k: int = 0) -> Expr:
|
|
604
638
|
x
|
605
639
|
d
|
606
640
|
k
|
641
|
+
min_samples
|
607
642
|
|
608
643
|
"""
|
609
|
-
|
644
|
+
minp = min_samples or polars_ta.MIN_SAMPLES or d
|
645
|
+
return x.map_batches(lambda x1: batches_i1_o1(x1.to_numpy(), roll_moment, d, minp, k))
|
610
646
|
|
611
647
|
|
612
|
-
def ts_partial_corr(x: Expr, y: Expr, z: Expr, d: int) -> Expr:
|
648
|
+
def ts_partial_corr(x: Expr, y: Expr, z: Expr, d: int, min_samples: Optional[int] = None) -> Expr:
|
613
649
|
"""Returns partial correlation of x, y, z for the past d days.
|
614
650
|
|
615
651
|
滚动偏相关
|
616
652
|
"""
|
617
|
-
|
653
|
+
minp = min_samples or polars_ta.MIN_SAMPLES or d
|
654
|
+
return struct([x, y, z]).map_batches(lambda xx: batches_i2_o1(struct_to_numpy(xx, 3), roll_partial_corr, d, minp))
|
618
655
|
|
619
656
|
|
620
|
-
def ts_percentage(x: Expr, d: int, percentage: float = 0.5) -> Expr:
|
657
|
+
def ts_percentage(x: Expr, d: int, percentage: float = 0.5, min_samples: Optional[int] = None) -> Expr:
|
621
658
|
"""Returns percentile value of x for the past d days.
|
622
659
|
|
623
660
|
滚动百分位数
|
@@ -627,17 +664,20 @@ def ts_percentage(x: Expr, d: int, percentage: float = 0.5) -> Expr:
|
|
627
664
|
x
|
628
665
|
d
|
629
666
|
percentage
|
667
|
+
min_samples
|
630
668
|
|
631
669
|
"""
|
632
|
-
|
670
|
+
minp = min_samples or polars_ta.MIN_SAMPLES
|
671
|
+
return x.rolling_quantile(percentage, window_size=d, min_samples=minp)
|
633
672
|
|
634
673
|
|
635
|
-
def ts_product(x: Expr, d: int = 5) -> Expr:
|
674
|
+
def ts_product(x: Expr, d: int = 5, min_samples: Optional[int] = None) -> Expr:
|
636
675
|
"""时序滚动乘"""
|
637
|
-
|
676
|
+
minp = min_samples or polars_ta.MIN_SAMPLES or d
|
677
|
+
return x.map_batches(lambda x1: batches_i1_o1(x1.to_numpy(), roll_prod, d, minp))
|
638
678
|
|
639
679
|
|
640
|
-
def ts_rank(x: Expr, d: int = 5) -> Expr:
|
680
|
+
def ts_rank(x: Expr, d: int = 5, min_samples: Optional[int] = None) -> Expr:
|
641
681
|
"""时序滚动排名
|
642
682
|
|
643
683
|
Warnings
|
@@ -645,7 +685,8 @@ def ts_rank(x: Expr, d: int = 5) -> Expr:
|
|
645
685
|
等待polars官方出rolling_rank
|
646
686
|
|
647
687
|
"""
|
648
|
-
|
688
|
+
minp = min_samples or polars_ta.MIN_SAMPLES or d
|
689
|
+
return x.map_batches(lambda a: roll_rank(a, d, minp, True))
|
649
690
|
|
650
691
|
|
651
692
|
def ts_returns(x: Expr, d: int = 1) -> Expr:
|
@@ -653,13 +694,13 @@ def ts_returns(x: Expr, d: int = 1) -> Expr:
|
|
653
694
|
return x.pct_change(d)
|
654
695
|
|
655
696
|
|
656
|
-
def ts_scale(x: Expr, d: int = 5) -> Expr:
|
697
|
+
def ts_scale(x: Expr, d: int = 5, min_samples: Optional[int] = None) -> Expr:
|
657
698
|
"""Returns (x – ts_min(x, d)) / (ts_max(x, d) – ts_min(x, d)) + constant
|
658
699
|
|
659
700
|
时序滚动缩放
|
660
701
|
"""
|
661
|
-
a = ts_min(x, d)
|
662
|
-
b = ts_max(x, d)
|
702
|
+
a = ts_min(x, d, min_samples)
|
703
|
+
b = ts_max(x, d, min_samples)
|
663
704
|
# return (x - a) / (b - a + TA_EPSILON)
|
664
705
|
return when(a != b).then((x - a) / (b - a)).otherwise(0)
|
665
706
|
|
@@ -684,7 +725,7 @@ def ts_skewness(x: Expr, d: int = 5, bias: bool = False) -> Expr:
|
|
684
725
|
return x.rolling_skew(d, bias=bias)
|
685
726
|
|
686
727
|
|
687
|
-
def ts_std_dev(x: Expr, d: int = 5, ddof: int = 0) -> Expr:
|
728
|
+
def ts_std_dev(x: Expr, d: int = 5, ddof: int = 0, min_samples: Optional[int] = None) -> Expr:
|
688
729
|
"""时序滚动标准差
|
689
730
|
|
690
731
|
Parameters
|
@@ -693,14 +734,17 @@ def ts_std_dev(x: Expr, d: int = 5, ddof: int = 0) -> Expr:
|
|
693
734
|
d
|
694
735
|
ddof
|
695
736
|
自由度
|
737
|
+
min_samples
|
696
738
|
|
697
739
|
"""
|
698
|
-
|
740
|
+
minp = min_samples or polars_ta.MIN_SAMPLES
|
741
|
+
return x.rolling_std(d, ddof=ddof, min_samples=minp)
|
699
742
|
|
700
743
|
|
701
|
-
def ts_sum(x: Expr, d: int = 30) -> Expr:
|
744
|
+
def ts_sum(x: Expr, d: int = 30, min_samples: Optional[int] = None) -> Expr:
|
702
745
|
"""时序滚动求和"""
|
703
|
-
|
746
|
+
minp = min_samples or polars_ta.MIN_SAMPLES
|
747
|
+
return x.rolling_sum(d, min_samples=minp)
|
704
748
|
|
705
749
|
|
706
750
|
def ts_sum_split_by(x: Expr, by: Expr, d: int = 30, k: int = 10) -> Expr:
|
@@ -753,18 +797,19 @@ def ts_sum_split_by(x: Expr, by: Expr, d: int = 30, k: int = 10) -> Expr:
|
|
753
797
|
|
754
798
|
"""
|
755
799
|
dtype = Struct([Field(f"column_{i}", Float64) for i in range(2)])
|
756
|
-
return struct([x, by]).map_batches(lambda xx: batches_i2_o2(
|
800
|
+
return struct([x, by]).map_batches(lambda xx: batches_i2_o2(struct_to_numpy(xx, 2), _sum_split_by, d, k), return_dtype=dtype)
|
757
801
|
|
758
802
|
|
759
|
-
def ts_triple_corr(x: Expr, y: Expr, z: Expr, d: int) -> Expr:
|
803
|
+
def ts_triple_corr(x: Expr, y: Expr, z: Expr, d: int, min_samples: Optional[int] = None) -> Expr:
|
760
804
|
"""时序滚动三重相关系数 Returns triple correlation of x, y, z for the past d days.
|
761
805
|
|
762
806
|
|
763
807
|
"""
|
764
|
-
|
808
|
+
minp = min_samples or polars_ta.MIN_SAMPLES or d
|
809
|
+
return struct([x, y, z]).map_batches(lambda xx: batches_i2_o1(struct_to_numpy(xx, 3), roll_triple_corr, d, minp))
|
765
810
|
|
766
811
|
|
767
|
-
def ts_weighted_decay(x: Expr, k: float = 0.5) -> Expr:
|
812
|
+
def ts_weighted_decay(x: Expr, k: float = 0.5, min_samples: Optional[int] = None) -> Expr:
|
768
813
|
"""加权衰减 Instead of replacing today’s value with yesterday’s as in ts_delay(x, 1),
|
769
814
|
it assigns weighted average of today’s and yesterday’s values with weight on today’s value being k and yesterday’s being (1-k).
|
770
815
|
|
@@ -773,14 +818,16 @@ def ts_weighted_decay(x: Expr, k: float = 0.5) -> Expr:
|
|
773
818
|
x
|
774
819
|
k
|
775
820
|
衰减系数
|
821
|
+
min_samples
|
776
822
|
|
777
823
|
"""
|
778
|
-
|
824
|
+
minp = min_samples or polars_ta.MIN_SAMPLES
|
825
|
+
return x.rolling_sum(2, weights=[1 - k, k], min_samples=minp)
|
779
826
|
|
780
827
|
|
781
|
-
def ts_zscore(x: Expr, d: int = 5) -> Expr:
|
828
|
+
def ts_zscore(x: Expr, d: int = 5, min_samples: Optional[int] = None) -> Expr:
|
782
829
|
"""时序滚动zscore"""
|
783
|
-
return (x - ts_mean(x, d)) / ts_std_dev(x, d, 0)
|
830
|
+
return (x - ts_mean(x, d, min_samples)) / ts_std_dev(x, d, 0, min_samples)
|
784
831
|
|
785
832
|
|
786
833
|
def ts_cum_prod_by(r: Expr, v: Expr) -> Expr:
|
@@ -834,7 +881,7 @@ def ts_cum_prod_by(r: Expr, v: Expr) -> Expr:
|
|
834
881
|
|
835
882
|
|
836
883
|
"""
|
837
|
-
return struct([r, v]).map_batches(lambda xx: batches_i2_o1(
|
884
|
+
return struct([r, v]).map_batches(lambda xx: batches_i2_o1(struct_to_numpy(xx, 2), _cum_prod_by))
|
838
885
|
|
839
886
|
|
840
887
|
def ts_cum_sum_by(r: Expr, v: Expr) -> Expr:
|
@@ -883,32 +930,36 @@ def ts_cum_sum_by(r: Expr, v: Expr) -> Expr:
|
|
883
930
|
```
|
884
931
|
|
885
932
|
"""
|
886
|
-
return struct([r, v]).map_batches(lambda xx: batches_i2_o1(
|
933
|
+
return struct([r, v]).map_batches(lambda xx: batches_i2_o1(struct_to_numpy(xx, 2), _cum_sum_by))
|
887
934
|
|
888
935
|
|
889
|
-
def ts_regression_resid(y: Expr, x: Expr, d: int) -> Expr:
|
936
|
+
def ts_regression_resid(y: Expr, x: Expr, d: int, min_samples: Optional[int] = None) -> Expr:
|
890
937
|
"""时序滚动回归取残差"""
|
891
|
-
|
938
|
+
minp = min_samples or polars_ta.MIN_SAMPLES or d
|
939
|
+
return pls.compute_rolling_least_squares(y, x, mode='residuals', add_intercept=True, rolling_kwargs=RollingKwargs(window_size=d, min_periods=minp))
|
892
940
|
|
893
941
|
|
894
|
-
def ts_regression_pred(y: Expr, x: Expr, d: int) -> Expr:
|
942
|
+
def ts_regression_pred(y: Expr, x: Expr, d: int, min_samples: Optional[int] = None) -> Expr:
|
895
943
|
"""时序滚动回归取y的预测值
|
896
944
|
"""
|
897
|
-
|
945
|
+
minp = min_samples or polars_ta.MIN_SAMPLES or d
|
946
|
+
return pls.compute_rolling_least_squares(y, x, mode='predictions', add_intercept=True, rolling_kwargs=RollingKwargs(window_size=d, min_periods=minp))
|
898
947
|
|
899
948
|
|
900
|
-
def ts_regression_intercept(y: Expr, x: Expr, d: int) -> Expr:
|
949
|
+
def ts_regression_intercept(y: Expr, x: Expr, d: int, min_samples: Optional[int] = None) -> Expr:
|
901
950
|
"""时序滚动回归取截距
|
902
951
|
"""
|
903
|
-
|
952
|
+
minp = min_samples or polars_ta.MIN_SAMPLES or d
|
953
|
+
return pls.compute_rolling_least_squares(y, x, mode='coefficients', add_intercept=True, rolling_kwargs=RollingKwargs(window_size=d, min_periods=minp)).struct[1]
|
904
954
|
|
905
955
|
|
906
|
-
def ts_regression_slope(y: Expr, x: Expr, d: int) -> Expr:
|
956
|
+
def ts_regression_slope(y: Expr, x: Expr, d: int, min_samples: Optional[int] = None) -> Expr:
|
907
957
|
"""时序滚动回归取斜率"""
|
908
|
-
|
958
|
+
minp = min_samples or polars_ta.MIN_SAMPLES or d
|
959
|
+
return pls.compute_rolling_least_squares(y, x, mode='coefficients', add_intercept=True, rolling_kwargs=RollingKwargs(window_size=d, min_periods=minp)).struct[0]
|
909
960
|
|
910
961
|
|
911
|
-
def ts_resid(y: Expr, *more_x: Expr, d: int = 30) -> Expr:
|
962
|
+
def ts_resid(y: Expr, *more_x: Expr, d: int = 30, min_samples: Optional[int] = None) -> Expr:
|
912
963
|
"""多元时序滚动回归取残差
|
913
964
|
|
914
965
|
Parameters
|
@@ -917,12 +968,14 @@ def ts_resid(y: Expr, *more_x: Expr, d: int = 30) -> Expr:
|
|
917
968
|
*more_x
|
918
969
|
多个x
|
919
970
|
d
|
971
|
+
min_samples
|
920
972
|
|
921
973
|
"""
|
922
|
-
|
974
|
+
minp = min_samples or polars_ta.MIN_SAMPLES or d
|
975
|
+
return pls.compute_rolling_least_squares(y, *more_x, mode='residuals', rolling_kwargs=RollingKwargs(window_size=d, min_periods=minp))
|
923
976
|
|
924
977
|
|
925
|
-
def ts_pred(y: Expr, *more_x: Expr, d: int = 30) -> Expr:
|
978
|
+
def ts_pred(y: Expr, *more_x: Expr, d: int = 30, min_samples: Optional[int] = None) -> Expr:
|
926
979
|
"""多元时序滚动回归预测
|
927
980
|
|
928
981
|
Parameters
|
@@ -931,19 +984,23 @@ def ts_pred(y: Expr, *more_x: Expr, d: int = 30) -> Expr:
|
|
931
984
|
*more_x
|
932
985
|
多个x
|
933
986
|
d
|
987
|
+
min_samples
|
934
988
|
|
935
989
|
"""
|
936
|
-
|
990
|
+
minp = min_samples or polars_ta.MIN_SAMPLES or d
|
991
|
+
return pls.compute_rolling_least_squares(y, *more_x, mode='predictions', rolling_kwargs=RollingKwargs(window_size=d, min_periods=minp))
|
937
992
|
|
938
993
|
|
939
|
-
def ts_weighted_mean(x: Expr, w: Expr, d: int) -> Expr:
|
994
|
+
def ts_weighted_mean(x: Expr, w: Expr, d: int, min_samples: Optional[int] = None) -> Expr:
|
940
995
|
"""时序滚动加权平均"""
|
941
|
-
|
996
|
+
minp = min_samples or polars_ta.MIN_SAMPLES
|
997
|
+
return (x * w).rolling_sum(d, min_samples=minp) / w.rolling_sum(d, min_samples=minp)
|
942
998
|
|
943
999
|
|
944
|
-
def ts_weighted_sum(x: Expr, w: Expr, d: int) -> Expr:
|
1000
|
+
def ts_weighted_sum(x: Expr, w: Expr, d: int, min_samples: Optional[int] = None) -> Expr:
|
945
1001
|
"""时序滚动加权求和"""
|
946
|
-
|
1002
|
+
minp = min_samples or polars_ta.MIN_SAMPLES
|
1003
|
+
return (x * w).rolling_sum(d, min_samples=minp)
|
947
1004
|
|
948
1005
|
|
949
1006
|
def ts_signals_to_size(long_entry: Expr, long_exit: Expr,
|
@@ -969,5 +1026,4 @@ def ts_signals_to_size(long_entry: Expr, long_exit: Expr,
|
|
969
1026
|
|
970
1027
|
"""
|
971
1028
|
return struct([long_entry, long_exit, short_entry, short_exit]).map_batches(
|
972
|
-
lambda xx: batches_i2_o1(
|
973
|
-
_signals_to_size, accumulate, action))
|
1029
|
+
lambda xx: batches_i2_o1(struct_to_numpy(xx, 4, dtype=float), _signals_to_size, accumulate, action))
|