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/utils/numba_.py
CHANGED
@@ -6,6 +6,7 @@ from typing import List
|
|
6
6
|
|
7
7
|
import numpy as np
|
8
8
|
from numba import jit
|
9
|
+
from numpy import full
|
9
10
|
from numpy.lib.stride_tricks import sliding_window_view
|
10
11
|
from polars import Series, Expr, struct, DataFrame
|
11
12
|
|
@@ -15,6 +16,90 @@ batches_i1_o1这一类的函数输入不支持Series,只支持numpy。设计
|
|
15
16
|
"""
|
16
17
|
|
17
18
|
|
19
|
+
@jit(nopython=True, nogil=True, fastmath=True, cache=True)
|
20
|
+
def isnan(x):
|
21
|
+
# https://github.com/numba/numba/issues/2919#issuecomment-747377615
|
22
|
+
if int(x) == -9223372036854775808:
|
23
|
+
return True
|
24
|
+
else:
|
25
|
+
return False
|
26
|
+
|
27
|
+
|
28
|
+
@jit(nopython=True, nogil=True, cache=True)
|
29
|
+
def full_with_window_size(arr, fill_value, dtype=None, window_size: int = 1):
|
30
|
+
out = full(arr.shape[0] + window_size - 1, fill_value, dtype=dtype)
|
31
|
+
out[window_size - 1:] = arr
|
32
|
+
return out
|
33
|
+
|
34
|
+
|
35
|
+
@jit(nopython=True, nogil=True, cache=True)
|
36
|
+
def sliding_window_with_min_periods(arr, window_size: int, min_periods: int):
|
37
|
+
windows = sliding_window_view(arr, window_size)
|
38
|
+
valid_counts = np.sum(~np.isnan(windows), axis=1)
|
39
|
+
# 修改这一行,使用布尔索引而不是np.where
|
40
|
+
result = windows.copy()
|
41
|
+
result[valid_counts < min_periods] = np.nan
|
42
|
+
return result
|
43
|
+
|
44
|
+
|
45
|
+
@jit(nopython=True, nogil=True, cache=True)
|
46
|
+
def _roll_1(x1: np.ndarray, window: int, min_periods: int, func):
|
47
|
+
"""TODO 只是模板演示,无法编译通过"""
|
48
|
+
out1 = full_with_window_size(x1, np.nan, dtype=np.float64, window_size=window)
|
49
|
+
a1 = sliding_window_with_min_periods(out1, window, min_periods)
|
50
|
+
out1[:] = np.nan
|
51
|
+
for i, v1 in enumerate(a1):
|
52
|
+
if np.isnan(v1).all():
|
53
|
+
continue
|
54
|
+
out1[i] = func(v1)
|
55
|
+
return out1[:x1.shape[0]]
|
56
|
+
|
57
|
+
|
58
|
+
@jit(nopython=True, nogil=True, cache=True)
|
59
|
+
def _roll_2(x1, x2, window, min_periods, func):
|
60
|
+
"""TODO 只是模板演示,无法编译通过"""
|
61
|
+
out1 = full_with_window_size(x1, np.nan, dtype=np.float64, window_size=window)
|
62
|
+
out2 = full_with_window_size(x2, np.nan, dtype=np.float64, window_size=window)
|
63
|
+
a1 = sliding_window_with_min_periods(out1, window, min_periods)
|
64
|
+
a2 = sliding_window_with_min_periods(out2, window, min_periods)
|
65
|
+
out1[:] = np.nan
|
66
|
+
for i, (v1, v2) in enumerate(zip(a1, a2)):
|
67
|
+
if np.isnan(v1).all():
|
68
|
+
continue
|
69
|
+
if np.isnan(v2).all():
|
70
|
+
continue
|
71
|
+
out1[i] = func(v1, v2)
|
72
|
+
return out1[:x1.shape[0]]
|
73
|
+
|
74
|
+
|
75
|
+
@jit(nopython=True, nogil=True, cache=True)
|
76
|
+
def _roll_3(x1, x2, x3, window, min_periods, func):
|
77
|
+
"""TODO 只是模板演示,无法编译通过"""
|
78
|
+
out1 = full_with_window_size(x1, np.nan, dtype=np.float64, window_size=window)
|
79
|
+
out2 = full_with_window_size(x2, np.nan, dtype=np.float64, window_size=window)
|
80
|
+
out3 = full_with_window_size(x3, np.nan, dtype=np.float64, window_size=window)
|
81
|
+
a1 = sliding_window_with_min_periods(out1, window, min_periods)
|
82
|
+
a2 = sliding_window_with_min_periods(out2, window, min_periods)
|
83
|
+
a3 = sliding_window_with_min_periods(out3, window, min_periods)
|
84
|
+
out1[:] = np.nan
|
85
|
+
for i, (v1, v2, v3) in enumerate(zip(a1, a2, a3)):
|
86
|
+
if np.isnan(v1).all():
|
87
|
+
continue
|
88
|
+
if np.isnan(v2).all():
|
89
|
+
continue
|
90
|
+
if np.isnan(v3).all():
|
91
|
+
continue
|
92
|
+
out1[i] = func(v1, v2, v3)
|
93
|
+
return out1[:x1.shape[0]]
|
94
|
+
|
95
|
+
|
96
|
+
def struct_to_numpy(xx, n: int, dtype=None):
|
97
|
+
if dtype is None:
|
98
|
+
return [xx.struct[i].to_numpy() for i in range(n)]
|
99
|
+
else:
|
100
|
+
return [xx.struct[i].to_numpy().astype(dtype) for i in range(n)]
|
101
|
+
|
102
|
+
|
18
103
|
def batches_i1_o1(x1: np.ndarray, func, *args, dtype=None) -> Series:
|
19
104
|
return Series(func(x1, *args), nan_to_null=True, dtype=dtype)
|
20
105
|
|
@@ -24,15 +109,11 @@ def batches_i2_o1(xx: List[np.ndarray], func, *args, dtype=None) -> Series:
|
|
24
109
|
|
25
110
|
|
26
111
|
def batches_i1_o2(x1: np.ndarray, func, *args, dtype=None) -> Series:
|
27
|
-
|
28
|
-
ss = [Series(x, nan_to_null=True, dtype=dtype) for x in out]
|
29
|
-
return DataFrame(ss).to_struct()
|
112
|
+
return DataFrame(func(x1, *args), nan_to_null=True).to_struct()
|
30
113
|
|
31
114
|
|
32
115
|
def batches_i2_o2(xx: List[np.ndarray], func, *args, dtype=None) -> Series:
|
33
|
-
|
34
|
-
ss = [Series(x, nan_to_null=True, dtype=dtype) for x in out]
|
35
|
-
return DataFrame(ss).to_struct()
|
116
|
+
return DataFrame(func(*xx, *args), nan_to_null=True).to_struct()
|
36
117
|
|
37
118
|
|
38
119
|
def batches_i2_o2_v2(xx: List[np.ndarray], func, *args, dtype=None) -> Series:
|
@@ -76,4 +157,4 @@ def roll_sum(x: Expr, n: int) -> Expr:
|
|
76
157
|
|
77
158
|
|
78
159
|
def roll_cov(a: Expr, b: Expr, n: int) -> Expr:
|
79
|
-
return struct([a, b]).map_batches(lambda xx: batches_i2_o1(
|
160
|
+
return struct([a, b]).map_batches(lambda xx: batches_i2_o1(struct_to_numpy(xx, 2), nb_roll_cov, n))
|
polars_ta/utils/pandas_.py
CHANGED
@@ -35,7 +35,7 @@ def get_window_bounds(
|
|
35
35
|
return start, end
|
36
36
|
|
37
37
|
|
38
|
-
def roll_rank(x: Series, d: int, pct: bool = True, method: str = 'average', ascending: bool = True):
|
38
|
+
def roll_rank(x: Series, d: int, minp: int, pct: bool = True, method: str = 'average', ascending: bool = True):
|
39
39
|
start, end = get_window_bounds(len(x), d)
|
40
40
|
"""
|
41
41
|
https://github.com/pandas-dev/pandas/blob/main/pandas/_libs/window/aggregations.pyx#L1281
|
@@ -46,11 +46,11 @@ def roll_rank(x: Series, d: int, pct: bool = True, method: str = 'average', asce
|
|
46
46
|
|
47
47
|
O(N log(window)) implementation using skip list
|
48
48
|
"""
|
49
|
-
ret = _roll_rank(x.to_numpy().astype(float), start, end,
|
49
|
+
ret = _roll_rank(x.to_numpy().astype(float), start, end, minp, pct, method, ascending)
|
50
50
|
return Series(ret, nan_to_null=True)
|
51
51
|
|
52
52
|
|
53
|
-
def roll_kurt(x, d):
|
53
|
+
def roll_kurt(x, d: int, minp: int):
|
54
54
|
start, end = get_window_bounds(len(x), d)
|
55
55
|
"""
|
56
56
|
https://github.com/pandas-dev/pandas/blob/main/pandas/_libs/window/aggregations.pyx#L803
|
@@ -58,5 +58,5 @@ def roll_kurt(x, d):
|
|
58
58
|
def roll_kurt(ndarray[float64_t] values, ndarray[int64_t] start,
|
59
59
|
ndarray[int64_t] end, int64_t minp) -> np.ndarray:
|
60
60
|
"""
|
61
|
-
ret = _roll_kurt(x.to_numpy().astype(float), start, end,
|
61
|
+
ret = _roll_kurt(x.to_numpy().astype(float), start, end, minp)
|
62
62
|
return Series(ret, nan_to_null=True)
|
polars_ta/wq/_nb.py
CHANGED
@@ -1,107 +1,121 @@
|
|
1
1
|
import numpy as np
|
2
|
-
from numba import jit, float64,
|
3
|
-
from numpy import argmax, argmin,
|
2
|
+
from numba import jit, float64, boolean
|
3
|
+
from numpy import argmax, argmin, full, vstack, corrcoef, nanprod, nanmean, nanstd
|
4
4
|
from numpy.lib.stride_tricks import sliding_window_view
|
5
5
|
|
6
|
+
from polars_ta.utils.numba_ import isnan, full_with_window_size, sliding_window_with_min_periods
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
8
|
+
|
9
|
+
@jit(nopython=True, nogil=True, cache=True)
|
10
|
+
def roll_argmax(x1, window, min_periods, reverse):
|
11
|
+
out1 = full_with_window_size(x1, np.nan, dtype=np.float64, window_size=window)
|
12
|
+
a1 = sliding_window_with_min_periods(out1, window, min_periods)
|
13
|
+
out1[:] = np.nan
|
13
14
|
if reverse:
|
14
15
|
a1 = a1[:, ::-1]
|
15
16
|
for i, v1 in enumerate(a1):
|
16
|
-
|
17
|
-
|
17
|
+
if np.isnan(v1).all():
|
18
|
+
continue
|
19
|
+
out1[i] = argmax(v1)
|
20
|
+
return out1[:x1.shape[0]]
|
18
21
|
|
19
22
|
|
20
|
-
@jit(nopython=True, nogil=True,
|
21
|
-
def roll_argmin(x1, window, reverse):
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
a1 = sliding_window_view(x1, window)
|
23
|
+
@jit(nopython=True, nogil=True, cache=True)
|
24
|
+
def roll_argmin(x1, window, min_periods, reverse):
|
25
|
+
out1 = full_with_window_size(x1, np.nan, dtype=np.float64, window_size=window)
|
26
|
+
a1 = sliding_window_with_min_periods(out1, window, min_periods)
|
27
|
+
out1[:] = np.nan
|
26
28
|
if reverse:
|
27
29
|
a1 = a1[:, ::-1]
|
28
30
|
for i, v1 in enumerate(a1):
|
29
|
-
|
30
|
-
|
31
|
+
if np.isnan(v1).all():
|
32
|
+
continue
|
33
|
+
out1[i] = argmin(v1)
|
34
|
+
return out1[:x1.shape[0]]
|
31
35
|
|
32
36
|
|
33
|
-
@jit(nopython=True, nogil=True,
|
34
|
-
def roll_prod(x1, window):
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
a1 = sliding_window_view(x1, window)
|
37
|
+
@jit(nopython=True, nogil=True, cache=True)
|
38
|
+
def roll_prod(x1, window, min_periods):
|
39
|
+
out1 = full_with_window_size(x1, np.nan, dtype=np.float64, window_size=window)
|
40
|
+
a1 = sliding_window_with_min_periods(out1, window, min_periods)
|
41
|
+
out1[:] = np.nan
|
39
42
|
for i, v1 in enumerate(a1):
|
40
|
-
|
41
|
-
|
43
|
+
if np.isnan(v1).all():
|
44
|
+
continue
|
45
|
+
out1[i] = nanprod(v1)
|
46
|
+
return out1[:x1.shape[0]]
|
42
47
|
|
43
48
|
|
44
|
-
@jit(nopython=True, nogil=True,
|
49
|
+
@jit(nopython=True, nogil=True, cache=True)
|
45
50
|
def _co_kurtosis(a1, a2):
|
46
|
-
t1 = a1 -
|
47
|
-
t2 = a2 -
|
48
|
-
t3 =
|
49
|
-
t4 =
|
50
|
-
return
|
51
|
+
t1 = a1 - nanmean(a1)
|
52
|
+
t2 = a2 - nanmean(a2)
|
53
|
+
t3 = nanstd(a1)
|
54
|
+
t4 = nanstd(a2)
|
55
|
+
return nanmean(t1 * (t2 ** 3)) / (t3 * (t4 ** 3))
|
51
56
|
|
52
57
|
|
53
|
-
@jit(nopython=True, nogil=True,
|
54
|
-
def roll_co_kurtosis(x1, x2, window):
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
58
|
+
@jit(nopython=True, nogil=True, cache=True)
|
59
|
+
def roll_co_kurtosis(x1, x2, window, min_periods):
|
60
|
+
out1 = full_with_window_size(x1, np.nan, dtype=np.float64, window_size=window)
|
61
|
+
out2 = full_with_window_size(x2, np.nan, dtype=np.float64, window_size=window)
|
62
|
+
a1 = sliding_window_with_min_periods(out1, window, min_periods)
|
63
|
+
a2 = sliding_window_with_min_periods(out2, window, min_periods)
|
64
|
+
out1[:] = np.nan
|
60
65
|
for i, (v1, v2) in enumerate(zip(a1, a2)):
|
61
|
-
|
62
|
-
|
66
|
+
if np.isnan(v1).all():
|
67
|
+
continue
|
68
|
+
if np.isnan(v2).all():
|
69
|
+
continue
|
70
|
+
out1[i] = _co_kurtosis(v1, v2)
|
71
|
+
return out1[:x1.shape[0]]
|
63
72
|
|
64
73
|
|
65
|
-
@jit(nopython=True, nogil=True,
|
74
|
+
@jit(nopython=True, nogil=True, cache=True)
|
66
75
|
def _co_skewness(a1, a2):
|
67
|
-
t1 = a1 -
|
68
|
-
t2 = a2 -
|
69
|
-
t3 =
|
70
|
-
t4 =
|
71
|
-
return
|
76
|
+
t1 = a1 - nanmean(a1)
|
77
|
+
t2 = a2 - nanmean(a2)
|
78
|
+
t3 = nanstd(a1)
|
79
|
+
t4 = nanstd(a2)
|
80
|
+
return nanmean(t1 * (t2 ** 2)) / (t3 * (t4 ** 2))
|
72
81
|
|
73
82
|
|
74
|
-
@jit(nopython=True, nogil=True,
|
75
|
-
def roll_co_skewness(x1, x2, window):
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
83
|
+
@jit(nopython=True, nogil=True, cache=True)
|
84
|
+
def roll_co_skewness(x1, x2, window, min_periods):
|
85
|
+
out1 = full_with_window_size(x1, np.nan, dtype=np.float64, window_size=window)
|
86
|
+
out2 = full_with_window_size(x2, np.nan, dtype=np.float64, window_size=window)
|
87
|
+
a1 = sliding_window_with_min_periods(out1, window, min_periods)
|
88
|
+
a2 = sliding_window_with_min_periods(out2, window, min_periods)
|
89
|
+
out1[:] = np.nan
|
81
90
|
for i, (v1, v2) in enumerate(zip(a1, a2)):
|
82
|
-
|
83
|
-
|
91
|
+
if np.isnan(v1).all():
|
92
|
+
continue
|
93
|
+
if np.isnan(v2).all():
|
94
|
+
continue
|
95
|
+
out1[i] = _co_skewness(v1, v2)
|
96
|
+
return out1[:x1.shape[0]]
|
84
97
|
|
85
98
|
|
86
|
-
@jit(nopython=True, nogil=True,
|
99
|
+
@jit(nopython=True, nogil=True, cache=True)
|
87
100
|
def _moment(a1, k):
|
88
101
|
"""centeral moment
|
89
102
|
中心矩阵"""
|
90
|
-
return
|
103
|
+
return nanmean((a1 - nanmean(a1)) ** k)
|
91
104
|
|
92
105
|
|
93
|
-
@jit(nopython=True, nogil=True,
|
94
|
-
def roll_moment(x1, window, k):
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
a1 = sliding_window_view(x1, window)
|
106
|
+
@jit(nopython=True, nogil=True, cache=True)
|
107
|
+
def roll_moment(x1, window, min_periods, k):
|
108
|
+
out1 = full_with_window_size(x1, np.nan, dtype=np.float64, window_size=window)
|
109
|
+
a1 = sliding_window_with_min_periods(out1, window, min_periods)
|
110
|
+
out1[:] = np.nan
|
99
111
|
for i, v1 in enumerate(a1):
|
100
|
-
|
101
|
-
|
112
|
+
if np.isnan(v1).all():
|
113
|
+
continue
|
114
|
+
out1[i] = _moment(v1, k)
|
115
|
+
return out1[:x1.shape[0]]
|
102
116
|
|
103
117
|
|
104
|
-
@jit(nopython=True, nogil=True,
|
118
|
+
@jit(nopython=True, nogil=True, cache=True)
|
105
119
|
def _partial_corr(a1, a2, a3):
|
106
120
|
"""TODO 不知是否正确,需要检查"""
|
107
121
|
c = corrcoef(vstack((a1, a2, a3)))
|
@@ -114,50 +128,55 @@ def _partial_corr(a1, a2, a3):
|
|
114
128
|
return t1 / (t2 * t3)
|
115
129
|
|
116
130
|
|
117
|
-
@jit(nopython=True, nogil=True,
|
118
|
-
def roll_partial_corr(x1, x2, x3, window):
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
a1 =
|
123
|
-
a2 =
|
124
|
-
a3 =
|
131
|
+
@jit(nopython=True, nogil=True, cache=True)
|
132
|
+
def roll_partial_corr(x1, x2, x3, window, min_periods):
|
133
|
+
out1 = full_with_window_size(x1, np.nan, dtype=np.float64, window_size=window)
|
134
|
+
out2 = full_with_window_size(x2, np.nan, dtype=np.float64, window_size=window)
|
135
|
+
out3 = full_with_window_size(x3, np.nan, dtype=np.float64, window_size=window)
|
136
|
+
a1 = sliding_window_with_min_periods(out1, window, min_periods)
|
137
|
+
a2 = sliding_window_with_min_periods(out2, window, min_periods)
|
138
|
+
a3 = sliding_window_with_min_periods(out3, window, min_periods)
|
139
|
+
out1[:] = np.nan
|
125
140
|
for i, (v1, v2, v3) in enumerate(zip(a1, a2, a3)):
|
126
|
-
|
127
|
-
|
141
|
+
if np.isnan(v1).all():
|
142
|
+
continue
|
143
|
+
if np.isnan(v2).all():
|
144
|
+
continue
|
145
|
+
if np.isnan(v3).all():
|
146
|
+
continue
|
147
|
+
out1[i] = _partial_corr(v1, v2, v3)
|
148
|
+
return out1[:x1.shape[0]]
|
128
149
|
|
129
150
|
|
130
|
-
@jit(nopython=True, nogil=True,
|
151
|
+
@jit(nopython=True, nogil=True, cache=True)
|
131
152
|
def _triple_corr(a1, a2, a3):
|
132
|
-
t1 = a1 -
|
133
|
-
t2 = a2 -
|
134
|
-
t3 = a3 -
|
135
|
-
t4 =
|
136
|
-
t5 =
|
137
|
-
t6 =
|
138
|
-
return
|
153
|
+
t1 = a1 - nanmean(a1)
|
154
|
+
t2 = a2 - nanmean(a2)
|
155
|
+
t3 = a3 - nanmean(a3)
|
156
|
+
t4 = nanstd(a1)
|
157
|
+
t5 = nanstd(a2)
|
158
|
+
t6 = nanstd(a3)
|
159
|
+
return nanmean(t1 * t2 * t3) / (t4 * t5 * t6)
|
139
160
|
|
140
161
|
|
141
|
-
@jit(nopython=True, nogil=True,
|
142
|
-
def roll_triple_corr(x1, x2, x3, window):
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
a1 =
|
147
|
-
a2 =
|
148
|
-
a3 =
|
162
|
+
@jit(nopython=True, nogil=True, cache=True)
|
163
|
+
def roll_triple_corr(x1, x2, x3, window, min_periods):
|
164
|
+
out1 = full_with_window_size(x1, np.nan, dtype=np.float64, window_size=window)
|
165
|
+
out2 = full_with_window_size(x2, np.nan, dtype=np.float64, window_size=window)
|
166
|
+
out3 = full_with_window_size(x3, np.nan, dtype=np.float64, window_size=window)
|
167
|
+
a1 = sliding_window_with_min_periods(out1, window, min_periods)
|
168
|
+
a2 = sliding_window_with_min_periods(out2, window, min_periods)
|
169
|
+
a3 = sliding_window_with_min_periods(out3, window, min_periods)
|
170
|
+
out1[:] = np.nan
|
149
171
|
for i, (v1, v2, v3) in enumerate(zip(a1, a2, a3)):
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
return True
|
159
|
-
else:
|
160
|
-
return False
|
172
|
+
if np.isnan(v1).all():
|
173
|
+
continue
|
174
|
+
if np.isnan(v2).all():
|
175
|
+
continue
|
176
|
+
if np.isnan(v3).all():
|
177
|
+
continue
|
178
|
+
out1[i] = _triple_corr(v1, v2, v3)
|
179
|
+
return out1[:x1.shape[0]]
|
161
180
|
|
162
181
|
|
163
182
|
@jit(nopython=True, nogil=True, fastmath=True, cache=True)
|
@@ -217,7 +236,8 @@ def _sum_split_by(x1, x2, window=10, n=2):
|
|
217
236
|
return out1, out2
|
218
237
|
|
219
238
|
|
220
|
-
@jit(float64[:](
|
239
|
+
@jit(float64[:](boolean[:], boolean[:], boolean[:], boolean[:], boolean, boolean),
|
240
|
+
nopython=True, nogil=True, cache=True)
|
221
241
|
def _signals_to_size(is_long_entry: np.ndarray, is_long_exit: np.ndarray,
|
222
242
|
is_short_entry: np.ndarray, is_short_exit: np.ndarray,
|
223
243
|
accumulate: bool = False,
|
@@ -289,27 +309,31 @@ def _signals_to_size(is_long_entry: np.ndarray, is_long_exit: np.ndarray,
|
|
289
309
|
return out
|
290
310
|
|
291
311
|
|
292
|
-
@jit(nopython=True, nogil=True,
|
293
|
-
def roll_decay_linear(x1, window):
|
294
|
-
out = full(x1.shape, np.nan, dtype=np.float64)
|
295
|
-
if len(x1) < window:
|
296
|
-
return out
|
312
|
+
@jit(nopython=True, nogil=True, cache=True)
|
313
|
+
def roll_decay_linear(x1, window, min_periods):
|
297
314
|
weights = np.arange(1., window + 1)
|
298
|
-
|
299
|
-
|
315
|
+
|
316
|
+
out1 = full_with_window_size(x1, np.nan, dtype=np.float64, window_size=window)
|
317
|
+
a1 = sliding_window_with_min_periods(out1, window, min_periods)
|
318
|
+
out1[:] = np.nan
|
300
319
|
for i, v1 in enumerate(a1):
|
301
|
-
|
302
|
-
|
320
|
+
if np.isnan(v1).all():
|
321
|
+
continue
|
322
|
+
mask = ~np.isnan(v1)
|
323
|
+
out1[i] = np.average(v1[mask], weights=weights[mask])
|
324
|
+
return out1[:x1.shape[0]]
|
303
325
|
|
304
326
|
|
305
|
-
@jit(nopython=True, nogil=True,
|
306
|
-
def roll_decay_exp_window(x1, window, factor):
|
307
|
-
out = full(x1.shape, np.nan, dtype=np.float64)
|
308
|
-
if len(x1) < window:
|
309
|
-
return out
|
327
|
+
@jit(nopython=True, nogil=True, cache=True)
|
328
|
+
def roll_decay_exp_window(x1, window, min_periods, factor):
|
310
329
|
weights = factor ** np.arange(window - 1, -1, -1)
|
311
|
-
|
312
|
-
|
330
|
+
|
331
|
+
out1 = full_with_window_size(x1, np.nan, dtype=np.float64, window_size=window)
|
332
|
+
a1 = sliding_window_with_min_periods(out1, window, min_periods)
|
333
|
+
out1[:] = np.nan
|
313
334
|
for i, v1 in enumerate(a1):
|
314
|
-
|
315
|
-
|
335
|
+
if np.isnan(v1).all():
|
336
|
+
continue
|
337
|
+
mask = ~np.isnan(v1)
|
338
|
+
out1[i] = np.average(v1[mask], weights=weights[mask])
|
339
|
+
return out1[:x1.shape[0]]
|