polars-ta 0.5.3__py3-none-any.whl → 0.5.4__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/_version.py +1 -1
- polars_ta/labels/__init__.py +1 -0
- polars_ta/labels/_nb.py +40 -0
- polars_ta/labels/future.py +165 -0
- polars_ta/performance/returns.py +1 -7
- polars_ta/prefix/labels.py +1 -0
- polars_ta/ta/README.md +12 -0
- polars_ta/talib/README.md +12 -0
- polars_ta/tdx/README.md +10 -0
- polars_ta/utils/numba_.py +2 -0
- polars_ta/wq/arithmetic.py +55 -26
- polars_ta/wq/cross_sectional.py +27 -15
- polars_ta/wq/logical.py +3 -3
- polars_ta/wq/preprocess.py +19 -42
- polars_ta/wq/time_series.py +62 -33
- polars_ta/wq/transformational.py +10 -5
- {polars_ta-0.5.3.dist-info → polars_ta-0.5.4.dist-info}/METADATA +13 -10
- {polars_ta-0.5.3.dist-info → polars_ta-0.5.4.dist-info}/RECORD +20 -14
- {polars_ta-0.5.3.dist-info → polars_ta-0.5.4.dist-info}/WHEEL +1 -2
- polars_ta-0.5.3.dist-info/top_level.txt +0 -1
- {polars_ta-0.5.3.dist-info → polars_ta-0.5.4.dist-info}/licenses/LICENSE +0 -0
polars_ta/_version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "0.5.
|
1
|
+
__version__ = "0.5.4"
|
@@ -0,0 +1 @@
|
|
1
|
+
from polars_ta.labels.future import * # noqa
|
polars_ta/labels/_nb.py
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
import numpy as np
|
2
|
+
from numba import jit
|
3
|
+
from numpy import full
|
4
|
+
|
5
|
+
|
6
|
+
@jit(nopython=True, nogil=True, cache=True)
|
7
|
+
def _triple_barrier(close: np.ndarray, high: np.ndarray, low: np.ndarray, window: int, take_profit: float, stop_loss: float) -> np.ndarray:
|
8
|
+
"""三重障碍打标法"""
|
9
|
+
out = full(close.shape[0], np.nan, dtype=np.float64)
|
10
|
+
for i in range(close.shape[0] - window + 1):
|
11
|
+
entry_price = close[i]
|
12
|
+
if np.isnan(entry_price):
|
13
|
+
# out[i] = 0
|
14
|
+
continue
|
15
|
+
upper_barrier = entry_price * (1 + take_profit)
|
16
|
+
lower_barrier = entry_price * (1 - stop_loss)
|
17
|
+
for j in range(i + 1, i + window):
|
18
|
+
hit_upper = high[j] >= upper_barrier
|
19
|
+
hit_lower = low[j] <= lower_barrier
|
20
|
+
if hit_upper and hit_lower:
|
21
|
+
# TODO 同一天无法知道是先触发止损还是先触发止盈
|
22
|
+
# 1. 假定离收盘价远的先触发
|
23
|
+
if high[j] - close[j] > close[j] - low[j]:
|
24
|
+
out[i] = 1 # 最高价更远,触发止盈
|
25
|
+
else:
|
26
|
+
out[i] = -1 # 最低价更远,触发止损
|
27
|
+
|
28
|
+
# out[i] = -1 # 2. 简化处理认为先触发止损
|
29
|
+
break
|
30
|
+
if hit_upper:
|
31
|
+
out[i] = 1 # 止盈
|
32
|
+
break
|
33
|
+
if hit_lower:
|
34
|
+
out[i] = -1 # 止损
|
35
|
+
break
|
36
|
+
else:
|
37
|
+
# out[i] = 0 # 1. 时间到了触发平仓
|
38
|
+
out[i] = np.sign(close[j] / entry_price - 1) # 2. 时间到了触发平仓
|
39
|
+
|
40
|
+
return out
|
@@ -0,0 +1,165 @@
|
|
1
|
+
"""
|
2
|
+
|
3
|
+
由于标签的定义比较灵活,所以以下代码主要用于参考
|
4
|
+
|
5
|
+
Notes
|
6
|
+
-----
|
7
|
+
标签都是未来数据,在机器学习中,只能用于`y`,不能用于`X`。
|
8
|
+
|
9
|
+
References
|
10
|
+
----------
|
11
|
+
https://mp.weixin.qq.com/s/XtgYezFsslOfW-QyIMr0VA
|
12
|
+
https://github.com/Rachnog/Advanced-Deep-Trading/blob/master/bars-labels-diff/Labeling.ipynb
|
13
|
+
|
14
|
+
"""
|
15
|
+
from polars import Expr, struct
|
16
|
+
|
17
|
+
from polars_ta.labels._nb import _triple_barrier
|
18
|
+
from polars_ta.utils.numba_ import batches_i2_o1, struct_to_numpy
|
19
|
+
from polars_ta.wq import cut, ts_delay, ts_log_diff, log
|
20
|
+
|
21
|
+
|
22
|
+
def ts_log_return(close: Expr, n: int = 5) -> Expr:
|
23
|
+
"""将未来数据当成卖出价后移到买入价位置,计算对数收益率
|
24
|
+
|
25
|
+
Examples
|
26
|
+
--------
|
27
|
+
```python
|
28
|
+
df = pl.DataFrame({
|
29
|
+
'a': [None, 10, 11, 12, 9, 12, 13],
|
30
|
+
}).with_columns(
|
31
|
+
out1=ts_log_return(pl.col('a'), 3),
|
32
|
+
out2=_ts_log_return(pl.col('a'), 3),
|
33
|
+
)
|
34
|
+
|
35
|
+
shape: (7, 3)
|
36
|
+
┌──────┬───────────┬───────────┐
|
37
|
+
│ a ┆ out1 ┆ out2 │
|
38
|
+
│ --- ┆ --- ┆ --- │
|
39
|
+
│ i64 ┆ f64 ┆ f64 │
|
40
|
+
╞══════╪═══════════╪═══════════╡
|
41
|
+
│ null ┆ null ┆ null │
|
42
|
+
│ 10 ┆ -0.105361 ┆ -0.105361 │
|
43
|
+
│ 11 ┆ 0.087011 ┆ 0.087011 │
|
44
|
+
│ 12 ┆ 0.080043 ┆ 0.080043 │
|
45
|
+
│ 9 ┆ null ┆ null │
|
46
|
+
│ 12 ┆ null ┆ null │
|
47
|
+
│ 13 ┆ null ┆ null │
|
48
|
+
└──────┴───────────┴───────────┘
|
49
|
+
```
|
50
|
+
|
51
|
+
"""
|
52
|
+
# return (close.shift(-n) / close).log()
|
53
|
+
return log(ts_delay(close, -n) / close)
|
54
|
+
|
55
|
+
|
56
|
+
def _ts_log_return(close: Expr, n: int = 5) -> Expr:
|
57
|
+
"""计算对数收益率,但将结果后移
|
58
|
+
|
59
|
+
如果打标签方式复杂,这种最终结果后移的方法更方便
|
60
|
+
"""
|
61
|
+
# return (close / close.shift(n)).log().shift(-n)
|
62
|
+
return ts_delay(ts_log_diff(close, n), -n)
|
63
|
+
|
64
|
+
|
65
|
+
def ts_simple_return(close: Expr, n: int = 5, threshold: float = 0.0, *more_threshold) -> Expr:
|
66
|
+
"""简单收益率标签。支持二分类、三分类等。对收益率使用`cut`进行分类
|
67
|
+
|
68
|
+
Parameters
|
69
|
+
----------
|
70
|
+
close
|
71
|
+
n:int
|
72
|
+
未来n天
|
73
|
+
threshold:float
|
74
|
+
收益率阈值,小于该值为0,大于等于该值为1
|
75
|
+
more_threshold:float
|
76
|
+
更多的阈值,用于三分类等。小于该值为1,大于等于该值为2,以此类推
|
77
|
+
|
78
|
+
Returns
|
79
|
+
-------
|
80
|
+
Expr
|
81
|
+
标签列, 类型为UInt32, 取值为0, 1, 2, ...
|
82
|
+
|
83
|
+
Examples
|
84
|
+
--------
|
85
|
+
```python
|
86
|
+
df = pl.DataFrame({
|
87
|
+
'a': [None, 10., 9.99, 9., 10., 11., 11.],
|
88
|
+
}).with_columns(
|
89
|
+
out1=label_simple_return(pl.col('a'), 1, 0),
|
90
|
+
out2=label_simple_return(pl.col('a'), 1, -0.001, 0.001),
|
91
|
+
)
|
92
|
+
|
93
|
+
shape: (7, 3)
|
94
|
+
┌──────┬──────┬──────┐
|
95
|
+
│ a ┆ out1 ┆ out2 │
|
96
|
+
│ --- ┆ --- ┆ --- │
|
97
|
+
│ f64 ┆ u32 ┆ u32 │
|
98
|
+
╞══════╪══════╪══════╡
|
99
|
+
│ null ┆ null ┆ null │
|
100
|
+
│ 10.0 ┆ 0 ┆ 0 │
|
101
|
+
│ 9.99 ┆ 0 ┆ 0 │
|
102
|
+
│ 9.0 ┆ 1 ┆ 2 │
|
103
|
+
│ 10.0 ┆ 1 ┆ 2 │
|
104
|
+
│ 11.0 ┆ 0 ┆ 1 │
|
105
|
+
│ 11.0 ┆ null ┆ null │
|
106
|
+
└──────┴──────┴──────┘
|
107
|
+
|
108
|
+
"""
|
109
|
+
return cut(close.pct_change(n).shift(-n), threshold, *more_threshold)
|
110
|
+
|
111
|
+
|
112
|
+
def ts_triple_barrier(close: Expr, high: Expr, low: Expr, d: int = 5, take_profit: float = 0.1, stop_loss: float = 0.05) -> Expr:
|
113
|
+
"""三重障碍打标法
|
114
|
+
|
115
|
+
Parameters
|
116
|
+
----------
|
117
|
+
close:Expr
|
118
|
+
收盘价
|
119
|
+
high:Expr
|
120
|
+
最高价
|
121
|
+
low:Expr
|
122
|
+
最低价
|
123
|
+
d:int
|
124
|
+
时间窗口
|
125
|
+
take_profit:float
|
126
|
+
止盈比例
|
127
|
+
stop_loss:float
|
128
|
+
止损比例
|
129
|
+
|
130
|
+
Returns
|
131
|
+
-------
|
132
|
+
Expr
|
133
|
+
标签列。取值为-1止损, 1止盈,0时间到期
|
134
|
+
|
135
|
+
Notes
|
136
|
+
-----
|
137
|
+
1. `high`, `low`在粗略情况下可用`close`代替
|
138
|
+
2. 时间到期时,根据盈亏返回不同的标签
|
139
|
+
|
140
|
+
Examples
|
141
|
+
--------
|
142
|
+
```python
|
143
|
+
df = pl.DataFrame({
|
144
|
+
"close": [np.nan, 1, 1, 1.0],
|
145
|
+
"high": [np.nan, 1, 1.1, 1],
|
146
|
+
"low": [np.nan, 1, 1, 0.95],
|
147
|
+
}).with_columns(
|
148
|
+
out=ts_triple_barrier(pl.col("close"), pl.col("high"), pl.col("low"), 2, 0.1, 0.05)
|
149
|
+
)
|
150
|
+
|
151
|
+
shape: (4, 4)
|
152
|
+
┌───────┬──────┬──────┬──────┐
|
153
|
+
│ close ┆ high ┆ low ┆ out │
|
154
|
+
│ --- ┆ --- ┆ --- ┆ --- │
|
155
|
+
│ f64 ┆ f64 ┆ f64 ┆ f64 │
|
156
|
+
╞═══════╪══════╪══════╪══════╡
|
157
|
+
│ NaN ┆ NaN ┆ NaN ┆ null │
|
158
|
+
│ 1.0 ┆ 1.0 ┆ 1.0 ┆ 1.0 │
|
159
|
+
│ 1.0 ┆ 1.1 ┆ 1.0 ┆ -1.0 │
|
160
|
+
│ 1.0 ┆ 1.0 ┆ 0.95 ┆ null │
|
161
|
+
└───────┴──────┴──────┴──────┘
|
162
|
+
```
|
163
|
+
|
164
|
+
"""
|
165
|
+
return struct([close, high, low]).map_batches(lambda xx: batches_i2_o1(struct_to_numpy(xx, 3), _triple_barrier, d, take_profit, stop_loss))
|
polars_ta/performance/returns.py
CHANGED
@@ -1,12 +1,6 @@
|
|
1
1
|
from polars import Expr
|
2
2
|
|
3
|
-
from polars_ta.wq.arithmetic import log1p, expm1
|
4
|
-
# log return
|
5
|
-
# 对数收益
|
6
|
-
from polars_ta.wq.time_series import ts_log_diff as ts_log_return # noqa
|
7
|
-
# simple percentage return
|
8
|
-
# 简单收益
|
9
|
-
from polars_ta.wq.time_series import ts_returns as ts_percent_return # noqa
|
3
|
+
from polars_ta.wq.arithmetic import log1p, expm1
|
10
4
|
|
11
5
|
|
12
6
|
def ts_cum_return(close: Expr) -> Expr:
|
@@ -0,0 +1 @@
|
|
1
|
+
from polars_ta.labels import * # noqa
|
polars_ta/ta/README.md
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# polars_ta.ta
|
2
|
+
|
3
|
+
1. Files in this folder mimic `talib`, and implement `polars` versions for the same functions
|
4
|
+
2. Since we reduce the functino calls between `Python` and `C` code, it should be faster than `talib`.
|
5
|
+
3. We first try to import from `ta`, then from `wq`, and only implement the function if it is not available.
|
6
|
+
4. When there is a circular dependency, we use `polars` instead.
|
7
|
+
|
8
|
+
|
9
|
+
1. 本文件夹中模仿`talib`,实现同名函数的`polars`版
|
10
|
+
2. 由于减少了python与c来回调用,理论上比直接调用`talib`快
|
11
|
+
3. 优先从`ta`中导入,然后从`wq`中导入,没有的才实现
|
12
|
+
4. 出现循环依赖时,使用`polars`
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# polars_ta.talib
|
2
|
+
|
3
|
+
Inside this package, files are generated by `tools.codegen_talib2`.
|
4
|
+
It is a wrapper of `talib` functions, with the following features:
|
5
|
+
|
6
|
+
1. Input and output are `Expr` instead of `Series`
|
7
|
+
2. ~~Add skipna feature (not efficient, will update when `polars` support backward fill)~~
|
8
|
+
|
9
|
+
本包由`tools.codegen_talib2`自动生成,是对`talib`代码的封装。实现了以下功能
|
10
|
+
1. 输入输出由`Series`改`Expr`
|
11
|
+
2. ~~添加跳过空值功能(效率不高,等`polars`支持反向填充,此部分将更新)~~
|
12
|
+
|
polars_ta/tdx/README.md
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
# polars_ta.tdx
|
2
|
+
|
3
|
+
1. Follows the `tdx` naming convention
|
4
|
+
2. Except for some element-wise functions, all functions are time-series functions. Pay special attention to `MAX` and similar functions.
|
5
|
+
3. First import from `tdx`, then from `wq`, and finally from `ta`. Only implement the function if it is not available.
|
6
|
+
|
7
|
+
|
8
|
+
1. 函数名称按照通达信来
|
9
|
+
2. 除了部分按元素计算的函数,其它都为时序函数,特别注意`MAX`等一类不要混淆
|
10
|
+
3. 优先从`tdx`中导入,然后从`wq`中导入,最后从`ta`,没有的才实现
|
polars_ta/utils/numba_.py
CHANGED
@@ -27,6 +27,7 @@ def isnan(x):
|
|
27
27
|
|
28
28
|
@jit(nopython=True, nogil=True, cache=True)
|
29
29
|
def full_with_window_size(arr, fill_value, dtype=None, window_size: int = 1):
|
30
|
+
"""创建一个更大的数组,填充后一截数据"""
|
30
31
|
out = full(arr.shape[0] + window_size - 1, fill_value, dtype=dtype)
|
31
32
|
out[window_size - 1:] = arr
|
32
33
|
return out
|
@@ -34,6 +35,7 @@ def full_with_window_size(arr, fill_value, dtype=None, window_size: int = 1):
|
|
34
35
|
|
35
36
|
@jit(nopython=True, nogil=True, cache=True)
|
36
37
|
def sliding_window_with_min_periods(arr, window_size: int, min_periods: int):
|
38
|
+
"""为rolling准备的数据,当数据长度不足时,用nan填充"""
|
37
39
|
windows = sliding_window_view(arr, window_size)
|
38
40
|
valid_counts = np.sum(~np.isnan(windows), axis=1)
|
39
41
|
# 修改这一行,使用布尔索引而不是np.where
|
polars_ta/wq/arithmetic.py
CHANGED
@@ -5,7 +5,7 @@ from polars import max_horizontal, sum_horizontal, min_horizontal, mean_horizont
|
|
5
5
|
|
6
6
|
|
7
7
|
def abs_(x: Expr) -> Expr:
|
8
|
-
"""
|
8
|
+
"""求绝对值
|
9
9
|
|
10
10
|
Examples
|
11
11
|
--------
|
@@ -39,7 +39,7 @@ def abs_(x: Expr) -> Expr:
|
|
39
39
|
|
40
40
|
|
41
41
|
def add(a: Expr, b: Expr, *args) -> Expr:
|
42
|
-
"""
|
42
|
+
"""水平多列相加
|
43
43
|
|
44
44
|
Examples
|
45
45
|
--------
|
@@ -133,12 +133,12 @@ def degrees(x: Expr) -> Expr:
|
|
133
133
|
return x.degrees()
|
134
134
|
|
135
135
|
|
136
|
-
def
|
136
|
+
def _densify(x: Expr) -> Expr:
|
137
137
|
raise
|
138
138
|
|
139
139
|
|
140
140
|
def div(x: Expr, y: Expr) -> Expr:
|
141
|
-
"""x
|
141
|
+
"""x除以y的整数部分
|
142
142
|
|
143
143
|
Examples
|
144
144
|
--------
|
@@ -170,7 +170,9 @@ def div(x: Expr, y: Expr) -> Expr:
|
|
170
170
|
|
171
171
|
|
172
172
|
def divide(x: Expr, y: Expr) -> Expr:
|
173
|
-
"""
|
173
|
+
"""除法
|
174
|
+
|
175
|
+
x/y
|
174
176
|
|
175
177
|
Examples
|
176
178
|
--------
|
@@ -231,7 +233,9 @@ def exp(x: Expr) -> Expr:
|
|
231
233
|
|
232
234
|
|
233
235
|
def expm1(x: Expr) -> Expr:
|
234
|
-
"""对数收益率 转 简单收益率
|
236
|
+
"""对数收益率 转 简单收益率
|
237
|
+
|
238
|
+
convert log return to simple return
|
235
239
|
|
236
240
|
Examples
|
237
241
|
--------
|
@@ -266,6 +270,7 @@ def floor(x: Expr) -> Expr:
|
|
266
270
|
|
267
271
|
def fraction(x: Expr) -> Expr:
|
268
272
|
"""小数部分
|
273
|
+
|
269
274
|
This operator removes the whole number part and returns the remaining fraction part with sign.
|
270
275
|
|
271
276
|
Examples
|
@@ -306,7 +311,9 @@ def fraction(x: Expr) -> Expr:
|
|
306
311
|
|
307
312
|
|
308
313
|
def inverse(x: Expr) -> Expr:
|
309
|
-
"""
|
314
|
+
"""倒数
|
315
|
+
|
316
|
+
1/x
|
310
317
|
|
311
318
|
Examples
|
312
319
|
--------
|
@@ -335,7 +342,7 @@ def inverse(x: Expr) -> Expr:
|
|
335
342
|
|
336
343
|
|
337
344
|
def log(x: Expr) -> Expr:
|
338
|
-
"""e为底的对数
|
345
|
+
"""以e为底的对数
|
339
346
|
|
340
347
|
Examples
|
341
348
|
--------
|
@@ -367,7 +374,7 @@ def log(x: Expr) -> Expr:
|
|
367
374
|
|
368
375
|
|
369
376
|
def log10(x: Expr) -> Expr:
|
370
|
-
"""10为底的对数
|
377
|
+
"""以10为底的对数
|
371
378
|
|
372
379
|
Examples
|
373
380
|
--------
|
@@ -396,7 +403,9 @@ def log10(x: Expr) -> Expr:
|
|
396
403
|
|
397
404
|
|
398
405
|
def log1p(x: Expr) -> Expr:
|
399
|
-
"""简单收益率 转 对数收益率
|
406
|
+
"""简单收益率 转 对数收益率
|
407
|
+
|
408
|
+
convert simple return to log return
|
400
409
|
|
401
410
|
log(x+1)
|
402
411
|
|
@@ -427,7 +436,7 @@ def log1p(x: Expr) -> Expr:
|
|
427
436
|
|
428
437
|
|
429
438
|
def log2(x: Expr) -> Expr:
|
430
|
-
"""2为底的对数
|
439
|
+
"""以2为底的对数
|
431
440
|
|
432
441
|
Examples
|
433
442
|
--------
|
@@ -456,12 +465,14 @@ def log2(x: Expr) -> Expr:
|
|
456
465
|
|
457
466
|
|
458
467
|
def max_(a: Expr, b: Expr, *args) -> Expr:
|
459
|
-
"""
|
468
|
+
"""水平多列求最大值
|
469
|
+
|
470
|
+
Maximum value of all inputs. At least 2 inputs are required."""
|
460
471
|
return max_horizontal(a, b, *args)
|
461
472
|
|
462
473
|
|
463
474
|
def mean(a: Expr, b: Expr, *args) -> Expr:
|
464
|
-
"""
|
475
|
+
"""水平多列求均值
|
465
476
|
|
466
477
|
Examples
|
467
478
|
--------
|
@@ -492,12 +503,16 @@ def mean(a: Expr, b: Expr, *args) -> Expr:
|
|
492
503
|
|
493
504
|
|
494
505
|
def min_(a: Expr, b: Expr, *args) -> Expr:
|
495
|
-
"""
|
506
|
+
"""水平多列求最小值
|
507
|
+
|
508
|
+
Maximum value of all inputs. At least 2 inputs are required."""
|
496
509
|
return min_horizontal(a, b, *args)
|
497
510
|
|
498
511
|
|
499
512
|
def mod(x: Expr, y: Expr) -> Expr:
|
500
|
-
"""
|
513
|
+
"""求余
|
514
|
+
|
515
|
+
x%y
|
501
516
|
|
502
517
|
Examples
|
503
518
|
--------
|
@@ -528,7 +543,9 @@ def mod(x: Expr, y: Expr) -> Expr:
|
|
528
543
|
|
529
544
|
|
530
545
|
def multiply(a: Expr, b: Expr, *args) -> Expr:
|
531
|
-
"""
|
546
|
+
"""水平多列相乘
|
547
|
+
|
548
|
+
Multiply all inputs. At least 2 inputs are required.
|
532
549
|
|
533
550
|
Examples
|
534
551
|
--------
|
@@ -569,7 +586,9 @@ def multiply(a: Expr, b: Expr, *args) -> Expr:
|
|
569
586
|
|
570
587
|
|
571
588
|
def power(x: Expr, y: Expr) -> Expr:
|
572
|
-
"""
|
589
|
+
"""乘幂
|
590
|
+
|
591
|
+
x ** y
|
573
592
|
|
574
593
|
Examples
|
575
594
|
--------
|
@@ -608,12 +627,14 @@ def radians(x: Expr) -> Expr:
|
|
608
627
|
|
609
628
|
|
610
629
|
def reverse(x: Expr) -> Expr:
|
611
|
-
"""
|
630
|
+
"""求相反数"""
|
612
631
|
return -x
|
613
632
|
|
614
633
|
|
615
634
|
def round_(x: Expr, decimals: int = 0) -> Expr:
|
616
|
-
"""四舍五入
|
635
|
+
"""四舍五入
|
636
|
+
|
637
|
+
Round input to closest integer.
|
617
638
|
|
618
639
|
Parameters
|
619
640
|
----------
|
@@ -653,7 +674,9 @@ def round_(x: Expr, decimals: int = 0) -> Expr:
|
|
653
674
|
|
654
675
|
|
655
676
|
def round_down(x: Expr, f: int = 1) -> Expr:
|
656
|
-
"""小于输入的f的最大倍数
|
677
|
+
"""小于输入的f的最大倍数
|
678
|
+
|
679
|
+
Round input to greatest multiple of f less than input
|
657
680
|
|
658
681
|
Parameters
|
659
682
|
----------
|
@@ -693,6 +716,8 @@ def round_down(x: Expr, f: int = 1) -> Expr:
|
|
693
716
|
def s_log_1p(x: Expr) -> Expr:
|
694
717
|
"""sign(x) * log10(1 + abs(x))
|
695
718
|
|
719
|
+
一种结合符号函数和对数变换的复合函数,常用于保留数据符号的同时压缩数值范围
|
720
|
+
|
696
721
|
Examples
|
697
722
|
--------
|
698
723
|
```python
|
@@ -729,7 +754,7 @@ def s_log_1p(x: Expr) -> Expr:
|
|
729
754
|
|
730
755
|
|
731
756
|
def sign(x: Expr) -> Expr:
|
732
|
-
"""
|
757
|
+
"""符号函数"""
|
733
758
|
if isinstance(x, (Expr, Series)):
|
734
759
|
return x.sign()
|
735
760
|
else:
|
@@ -737,7 +762,9 @@ def sign(x: Expr) -> Expr:
|
|
737
762
|
|
738
763
|
|
739
764
|
def signed_power(x: Expr, y: Expr) -> Expr:
|
740
|
-
"""x
|
765
|
+
"""x的y次幂,符号保留
|
766
|
+
|
767
|
+
x raised to the power of y such that final result preserves sign of x.
|
741
768
|
|
742
769
|
Examples
|
743
770
|
--------
|
@@ -793,7 +820,7 @@ def sinh(x: Expr) -> Expr:
|
|
793
820
|
|
794
821
|
|
795
822
|
def softsign(x: Expr) -> Expr:
|
796
|
-
"""softsign
|
823
|
+
"""softsign激活函数
|
797
824
|
|
798
825
|
Examples
|
799
826
|
--------
|
@@ -833,7 +860,9 @@ def square(x: Expr) -> Expr:
|
|
833
860
|
|
834
861
|
|
835
862
|
def subtract(x: Expr, y: Expr) -> Expr:
|
836
|
-
"""
|
863
|
+
"""减法
|
864
|
+
|
865
|
+
x-y"""
|
837
866
|
return x - y
|
838
867
|
|
839
868
|
|
@@ -898,7 +927,7 @@ def tanh(x: Expr) -> Expr:
|
|
898
927
|
|
899
928
|
|
900
929
|
def var(a: Expr, b: Expr, *args) -> Expr:
|
901
|
-
"""
|
930
|
+
"""水平多列求方差
|
902
931
|
|
903
932
|
Examples
|
904
933
|
--------
|
@@ -932,7 +961,7 @@ def var(a: Expr, b: Expr, *args) -> Expr:
|
|
932
961
|
|
933
962
|
|
934
963
|
def std(a: Expr, b: Expr, *args) -> Expr:
|
935
|
-
"""
|
964
|
+
"""水平多列求标准差
|
936
965
|
|
937
966
|
Examples
|
938
967
|
--------
|
polars_ta/wq/cross_sectional.py
CHANGED
@@ -17,7 +17,9 @@ _ols_kwargs = OLSKwargs(null_policy='drop', solve_method='svd')
|
|
17
17
|
|
18
18
|
|
19
19
|
def cs_one_side(x: Expr, is_long: bool = True) -> Expr:
|
20
|
-
"""
|
20
|
+
"""横截面上,将全部资产上调或下调,使得 Alpha 策略转为纯多头配置(当方向参数设为空头时则转为纯空头配置)
|
21
|
+
|
22
|
+
Shifts all instruments up or down so that the Alpha becomes long-only or short-only
|
21
23
|
(if side = short), respectively.
|
22
24
|
|
23
25
|
Examples
|
@@ -54,7 +56,9 @@ def cs_one_side(x: Expr, is_long: bool = True) -> Expr:
|
|
54
56
|
|
55
57
|
|
56
58
|
def cs_scale(x: Expr, scale_: float = 1, long_scale: float = 1, short_scale: float = 1) -> Expr:
|
57
|
-
"""
|
59
|
+
"""横截面上,将输入数据进行比例调整。此外,可通过向运算符添加额外参数,将多头头寸和空头头寸分别映射到独立的缩放比例上
|
60
|
+
|
61
|
+
Scales input to booksize. We can also scale the long positions and short positions to separate scales by mentioning additional parameters to the operator.
|
58
62
|
|
59
63
|
Examples
|
60
64
|
--------
|
@@ -95,7 +99,9 @@ def cs_scale(x: Expr, scale_: float = 1, long_scale: float = 1, short_scale: flo
|
|
95
99
|
|
96
100
|
|
97
101
|
def cs_scale_down(x: Expr, constant: int = 0) -> Expr:
|
98
|
-
"""
|
102
|
+
"""横截面上,将每日数据按比例缩放至 [0,1] 区间,使得最小值映射为 0,最大值映射为 1,并通过减去常数偏移量调整最终结果
|
103
|
+
|
104
|
+
Scales all values in each day proportionately between 0 and 1 such that minimum value maps to 0 and maximum value maps to 1.
|
99
105
|
constant is the offset by which final result is subtracted
|
100
106
|
|
101
107
|
Examples
|
@@ -130,7 +136,9 @@ def cs_scale_down(x: Expr, constant: int = 0) -> Expr:
|
|
130
136
|
|
131
137
|
|
132
138
|
def cs_truncate(x: Expr, max_percent: float = 0.01) -> Expr:
|
133
|
-
"""
|
139
|
+
"""横截面上,将所有 x 的取值截断至 maxPercent 指定的上限值,其中 maxPercent 需以十进制小数形式表示
|
140
|
+
|
141
|
+
Operator truncates all values of x to maxPercent. Here, maxPercent is in decimal notation
|
134
142
|
|
135
143
|
Examples
|
136
144
|
--------
|
@@ -161,8 +169,8 @@ def cs_truncate(x: Expr, max_percent: float = 0.01) -> Expr:
|
|
161
169
|
return x.clip(upper_bound=x.sum() * max_percent)
|
162
170
|
|
163
171
|
|
164
|
-
def cs_fill_except_all_null(x: Expr, value=0) -> Expr:
|
165
|
-
"""
|
172
|
+
def cs_fill_except_all_null(x: Expr, value: float = 0) -> Expr:
|
173
|
+
"""横截面上,全为`null`时,保持`null`,反之`null`填充为`value`
|
166
174
|
|
167
175
|
Examples
|
168
176
|
--------
|
@@ -199,27 +207,29 @@ def cs_fill_except_all_null(x: Expr, value=0) -> Expr:
|
|
199
207
|
|
200
208
|
|
201
209
|
def cs_fill_mean(x: Expr) -> Expr:
|
202
|
-
"""
|
210
|
+
"""横截面上,填充`null`为均值"""
|
203
211
|
return x.fill_null(strategy='mean')
|
204
212
|
|
205
213
|
|
206
|
-
def cs_fill_null(x: Expr, value=0) -> Expr:
|
207
|
-
"""
|
214
|
+
def cs_fill_null(x: Expr, value: float = 0) -> Expr:
|
215
|
+
"""横截面上,填充`null`为`value`"""
|
208
216
|
return x.fill_null(value)
|
209
217
|
|
210
218
|
|
211
219
|
def cs_regression_neut(y: Expr, x: Expr) -> Expr:
|
212
|
-
"""
|
220
|
+
"""横截面上,一元回归残差"""
|
213
221
|
return pls.compute_least_squares(y, x, add_intercept=True, mode='residuals', ols_kwargs=_ols_kwargs)
|
214
222
|
|
215
223
|
|
216
224
|
def cs_regression_proj(y: Expr, x: Expr) -> Expr:
|
217
|
-
"""
|
225
|
+
"""横截面上,一元回归预测"""
|
218
226
|
return pls.compute_least_squares(y, x, add_intercept=True, mode='predictions', ols_kwargs=_ols_kwargs)
|
219
227
|
|
220
228
|
|
221
229
|
def cs_rank(x: Expr, pct: bool = True) -> Expr:
|
222
|
-
"""
|
230
|
+
"""横截面排名。
|
231
|
+
|
232
|
+
Ranks the input among all the instruments and returns an equally distributed number between 0.0 and 1.0. For precise sort, use the rate as 0.
|
223
233
|
|
224
234
|
Parameters
|
225
235
|
----------
|
@@ -269,7 +279,7 @@ def cs_rank(x: Expr, pct: bool = True) -> Expr:
|
|
269
279
|
|
270
280
|
|
271
281
|
def _cs_qcut_rank(x: Expr, q: int = 10) -> Expr:
|
272
|
-
"""
|
282
|
+
"""横截面上等频分箱
|
273
283
|
|
274
284
|
Parameters
|
275
285
|
----------
|
@@ -314,7 +324,9 @@ def _cs_qcut_rank(x: Expr, q: int = 10) -> Expr:
|
|
314
324
|
|
315
325
|
|
316
326
|
def cs_qcut(x: Expr, q: int = 10) -> Expr:
|
317
|
-
"""
|
327
|
+
"""横截面上等频分箱
|
328
|
+
|
329
|
+
Convert float values into indexes for user-specified buckets. Bucket is useful for creating group values, which can be passed to group operators as input.
|
318
330
|
|
319
331
|
Parameters
|
320
332
|
----------
|
@@ -362,7 +374,7 @@ def cs_qcut(x: Expr, q: int = 10) -> Expr:
|
|
362
374
|
|
363
375
|
|
364
376
|
def cs_top_bottom(x: Expr, k: int = 10) -> Expr:
|
365
|
-
"""
|
377
|
+
"""横截面上,排名。前K标记成-1,后K标记成1
|
366
378
|
|
367
379
|
Examples
|
368
380
|
--------
|
polars_ta/wq/logical.py
CHANGED
@@ -12,9 +12,9 @@ def equal(input1: Expr, input2: Expr) -> Expr:
|
|
12
12
|
return input1 == input2
|
13
13
|
|
14
14
|
|
15
|
-
def if_else(
|
16
|
-
"""
|
17
|
-
return when(
|
15
|
+
def if_else(condition: Expr, true_value: Expr, false_value: Expr = None) -> Expr:
|
16
|
+
"""条件判断"""
|
17
|
+
return when(condition).then(true_value).otherwise(false_value)
|
18
18
|
|
19
19
|
|
20
20
|
def is_finite(input1: Expr) -> Expr:
|
polars_ta/wq/preprocess.py
CHANGED
@@ -8,10 +8,12 @@ from polars_ta.wq.cross_sectional import cs_rank
|
|
8
8
|
# ======================
|
9
9
|
# standardize
|
10
10
|
def cs_zscore(x: Expr, ddof: int = 0) -> Expr:
|
11
|
+
"""横截面zscore标准化"""
|
11
12
|
return (x - x.mean()) / x.std(ddof=ddof)
|
12
13
|
|
13
14
|
|
14
15
|
def cs_minmax(x: Expr) -> Expr:
|
16
|
+
"""横截面minmax标准化"""
|
15
17
|
a = x.min()
|
16
18
|
b = x.max()
|
17
19
|
# 这个版本在b-a为整数时,得到的结果不好看
|
@@ -22,12 +24,14 @@ def cs_minmax(x: Expr) -> Expr:
|
|
22
24
|
# ======================
|
23
25
|
# winsorize
|
24
26
|
def cs_quantile(x: Expr, low_limit: float = 0.025, up_limit: float = 0.995) -> Expr:
|
27
|
+
"""横截面分位数去极值"""
|
25
28
|
a = x.quantile(low_limit)
|
26
29
|
b = x.quantile(up_limit)
|
27
30
|
return x.clip(lower_bound=a, upper_bound=b)
|
28
31
|
|
29
32
|
|
30
33
|
def cs_3sigma(x: Expr, n: float = 3.) -> Expr:
|
34
|
+
"""横截面3倍sigma去极值"""
|
31
35
|
# fill_nan will seriously reduce speed. So it's more appropriate for users to handle it themselves
|
32
36
|
# fill_nan(None) 严重拖慢速度,所以还是由用户自己处理更合适
|
33
37
|
a = x.mean()
|
@@ -36,7 +40,13 @@ def cs_3sigma(x: Expr, n: float = 3.) -> Expr:
|
|
36
40
|
|
37
41
|
|
38
42
|
def cs_mad(x: Expr, n: float = 3., k: float = 1.4826) -> Expr:
|
39
|
-
|
43
|
+
"""横截面MAD去极值
|
44
|
+
|
45
|
+
References
|
46
|
+
----------
|
47
|
+
https://en.wikipedia.org/wiki/Median_absolute_deviation
|
48
|
+
|
49
|
+
"""
|
40
50
|
a = x.median()
|
41
51
|
b = (n * k) * (x - a).abs().median()
|
42
52
|
return x.clip(lower_bound=a - b, upper_bound=a + b)
|
@@ -45,7 +55,7 @@ def cs_mad(x: Expr, n: float = 3., k: float = 1.4826) -> Expr:
|
|
45
55
|
# ======================
|
46
56
|
# neutralize
|
47
57
|
def cs_demean(x: Expr) -> Expr:
|
48
|
-
"""
|
58
|
+
"""横截面去均值化
|
49
59
|
|
50
60
|
Notes
|
51
61
|
-----
|
@@ -66,75 +76,42 @@ def cs_demean(x: Expr) -> Expr:
|
|
66
76
|
_ols_kwargs = OLSKwargs(null_policy='drop', solve_method='svd')
|
67
77
|
|
68
78
|
|
69
|
-
# def _residual_multiple(cols: List[Series], add_constant: bool) -> Series:
|
70
|
-
# # 将pl.Struct转成list,这样可以实现传正则,其它也转list
|
71
|
-
# cols = [list(c.struct) if isinstance(c.dtype, Struct) else [c] for c in cols]
|
72
|
-
# # 二维列表转一维列表,再转np.ndarray
|
73
|
-
# cols = [i.to_numpy() for p in cols for i in p]
|
74
|
-
# if add_constant:
|
75
|
-
# cols += [np.ones_like(cols[0])]
|
76
|
-
# yx = np.vstack(cols).T
|
77
|
-
#
|
78
|
-
# # skip nan
|
79
|
-
# mask = np.any(np.isnan(yx), axis=1)
|
80
|
-
# yx_ = yx[~mask, :]
|
81
|
-
#
|
82
|
-
# y = yx_[:, 0]
|
83
|
-
# x = yx_[:, 1:]
|
84
|
-
# coef = np.linalg.lstsq(x, y, rcond=None)[0]
|
85
|
-
# y_hat = np.sum(x * coef, axis=1)
|
86
|
-
# residual = y - y_hat
|
87
|
-
#
|
88
|
-
# # refill
|
89
|
-
# out = np.empty_like(yx[:, 0])
|
90
|
-
# out[~mask] = residual
|
91
|
-
# out[mask] = np.nan
|
92
|
-
# return Series(out, nan_to_null=True)
|
93
|
-
#
|
94
|
-
#
|
95
|
-
# def cs_resid_(y: Expr, *more_x: Expr) -> Expr:
|
96
|
-
# """multivariate regression
|
97
|
-
# 多元回归
|
98
|
-
# """
|
99
|
-
# return map_batches([y, *more_x], lambda xx: _residual_multiple(xx, False))
|
100
|
-
|
101
|
-
|
102
79
|
def cs_resid(y: Expr, *more_x: Expr) -> Expr:
|
103
|
-
"""
|
80
|
+
"""横截面多元回归取残差"""
|
104
81
|
return pls.compute_least_squares(y, *more_x, mode='residuals', ols_kwargs=_ols_kwargs)
|
105
82
|
|
106
83
|
|
107
84
|
def cs_mad_zscore(y: Expr) -> Expr:
|
108
|
-
"""
|
85
|
+
"""横截面去极值、标准化"""
|
109
86
|
return cs_zscore(cs_mad(y))
|
110
87
|
|
111
88
|
|
112
89
|
def cs_mad_zscore_resid(y: Expr, *more_x: Expr) -> Expr:
|
113
|
-
"""
|
90
|
+
"""横截面去极值、标准化、中性化"""
|
114
91
|
return cs_resid(cs_zscore(cs_mad(y)), *more_x)
|
115
92
|
|
116
93
|
|
117
94
|
def cs_mad_rank(y: Expr) -> Expr:
|
118
|
-
"""
|
95
|
+
"""横截面去极值、排名"""
|
119
96
|
return cs_rank(cs_mad(y))
|
120
97
|
|
121
98
|
|
122
99
|
def cs_mad_rank2(y: Expr, m: float) -> Expr:
|
123
|
-
"""
|
100
|
+
"""横截面去极值,排名,移动峰或谷到零点,然后平方。非线性处理
|
124
101
|
|
125
102
|
适合于分层收益V型或倒V的情况"""
|
126
103
|
return (cs_rank(cs_mad(y)) - m) ** 2
|
127
104
|
|
128
105
|
|
129
106
|
def cs_mad_rank2_resid(y: Expr, m: float, *more_x: Expr) -> Expr:
|
130
|
-
"""
|
107
|
+
"""横截面去极值,排名,移动峰或谷到零点,然后平方。回归取残差。非线性处理
|
131
108
|
|
132
109
|
适合于分层收益V型或倒V的情况"""
|
133
110
|
return cs_resid((cs_rank(cs_mad(y)) - m) ** 2, *more_x)
|
134
111
|
|
135
112
|
|
136
113
|
def cs_rank2(y: Expr, m: float) -> Expr:
|
137
|
-
"""
|
114
|
+
"""横截面移动峰或谷到零点,然后平方。非线性处理
|
138
115
|
|
139
116
|
适合于分层收益V型或倒V的情况"""
|
140
117
|
return (cs_rank(y) - m) ** 2
|
polars_ta/wq/time_series.py
CHANGED
@@ -12,7 +12,9 @@ from polars_ta.wq._nb import roll_argmax, roll_argmin, roll_co_kurtosis, roll_co
|
|
12
12
|
|
13
13
|
|
14
14
|
def ts_arg_max(x: Expr, d: int = 5, reverse: bool = True, min_samples: Optional[int] = None) -> Expr:
|
15
|
-
"""
|
15
|
+
"""窗口内最大值出现的相对位置,最近的一天记为第 0 天,最远的一天为第 d-1 天
|
16
|
+
|
17
|
+
Returns the relative index of the max value in the time series for the past d days.
|
16
18
|
If the current day has the max value for the past d days, it returns 0.
|
17
19
|
If previous day has the max value for the past d days, it returns 1.
|
18
20
|
|
@@ -61,7 +63,7 @@ def ts_arg_max(x: Expr, d: int = 5, reverse: bool = True, min_samples: Optional[
|
|
61
63
|
|
62
64
|
|
63
65
|
def ts_arg_min(x: Expr, d: int = 5, reverse: bool = True, min_samples: Optional[int] = None) -> Expr:
|
64
|
-
"""
|
66
|
+
"""窗口内最小值出现的相对位置,最近的一天记为第 0 天,最远的一天为第 d-1 天
|
65
67
|
|
66
68
|
Parameters
|
67
69
|
----------
|
@@ -85,19 +87,21 @@ def ts_arg_min(x: Expr, d: int = 5, reverse: bool = True, min_samples: Optional[
|
|
85
87
|
|
86
88
|
|
87
89
|
def ts_co_kurtosis(x: Expr, y: Expr, d: int = 5, ddof: int = 0, min_samples: Optional[int] = None) -> Expr:
|
90
|
+
"""计算两个序列在滚动窗口内联合分布的协峰度"""
|
88
91
|
minp = min_samples or polars_ta.MIN_SAMPLES or d
|
89
92
|
return struct([x, y]).map_batches(lambda xx: batches_i2_o1(struct_to_numpy(xx, 2), roll_co_kurtosis, d, minp))
|
90
93
|
|
91
94
|
|
92
95
|
def ts_co_skewness(x: Expr, y: Expr, d: int = 5, ddof: int = 0, min_samples: Optional[int] = None) -> Expr:
|
96
|
+
"""计算两个序列在滚动窗口内联合分布的协偏度"""
|
93
97
|
minp = min_samples or polars_ta.MIN_SAMPLES or d
|
94
98
|
return struct([x, y]).map_batches(lambda xx: batches_i2_o1(struct_to_numpy(xx, 2), roll_co_skewness, d, minp))
|
95
99
|
|
96
100
|
|
97
101
|
def ts_corr(x: Expr, y: Expr, d: int = 5, ddof: int = 1, min_samples: Optional[int] = None) -> Expr:
|
98
|
-
"""
|
102
|
+
"""时序滚动相关系数
|
99
103
|
|
100
|
-
|
104
|
+
rolling correlation between two columns
|
101
105
|
|
102
106
|
Parameters
|
103
107
|
----------
|
@@ -236,9 +240,9 @@ def ts_count_nulls(x: Expr, d: int = 5, min_samples: Optional[int] = None) -> Ex
|
|
236
240
|
|
237
241
|
|
238
242
|
def ts_covariance(x: Expr, y: Expr, d: int = 5, ddof: int = 1, min_samples: Optional[int] = None) -> Expr:
|
239
|
-
"""
|
243
|
+
"""时序滚动协方差
|
240
244
|
|
241
|
-
|
245
|
+
rolling covariance between two columns
|
242
246
|
|
243
247
|
Parameters
|
244
248
|
----------
|
@@ -291,7 +295,7 @@ def ts_cum_count(x: Expr) -> Expr:
|
|
291
295
|
|
292
296
|
|
293
297
|
def ts_cum_max(x: Expr) -> Expr:
|
294
|
-
"""
|
298
|
+
"""时序累计最大值
|
295
299
|
|
296
300
|
Examples
|
297
301
|
--------
|
@@ -323,7 +327,7 @@ def ts_cum_max(x: Expr) -> Expr:
|
|
323
327
|
|
324
328
|
|
325
329
|
def ts_cum_min(x: Expr) -> Expr:
|
326
|
-
"""
|
330
|
+
"""时序累计最小值
|
327
331
|
|
328
332
|
Examples
|
329
333
|
--------
|
@@ -492,8 +496,10 @@ def ts_decay_linear(x: Expr, d: int = 30, min_samples: Optional[int] = None) ->
|
|
492
496
|
return x.map_batches(lambda x1: batches_i1_o1(x1.to_numpy().astype(float), roll_decay_linear, d, minp))
|
493
497
|
|
494
498
|
|
495
|
-
def ts_delay(x: Expr, d: int = 1, fill_value=None) -> Expr:
|
496
|
-
"""时序数据移动
|
499
|
+
def ts_delay(x: Expr, d: int = 1, fill_value: float = None) -> Expr:
|
500
|
+
"""时序数据移动
|
501
|
+
|
502
|
+
shift x
|
497
503
|
|
498
504
|
Parameters
|
499
505
|
----------
|
@@ -508,7 +514,7 @@ def ts_delay(x: Expr, d: int = 1, fill_value=None) -> Expr:
|
|
508
514
|
|
509
515
|
|
510
516
|
def ts_delta(x: Expr, d: int = 1) -> Expr:
|
511
|
-
"""
|
517
|
+
"""时序差分"""
|
512
518
|
return x.diff(d)
|
513
519
|
|
514
520
|
|
@@ -551,14 +557,16 @@ def ts_fill_null(x: Expr, limit: int = None) -> Expr:
|
|
551
557
|
|
552
558
|
|
553
559
|
def ts_ir(x: Expr, d: int = 1, min_samples: Optional[int] = None) -> Expr:
|
554
|
-
"""时序滚动信息系数
|
560
|
+
"""时序滚动信息系数
|
561
|
+
|
562
|
+
rolling information ratio"""
|
555
563
|
return ts_mean(x, d, min_samples) / ts_std_dev(x, d, 0, min_samples)
|
556
564
|
|
557
565
|
|
558
566
|
def ts_kurtosis(x: Expr, d: int = 5, bias: bool = False, min_samples: Optional[int] = None) -> Expr:
|
559
|
-
"""
|
567
|
+
"""时序滚动峰度
|
560
568
|
|
561
|
-
|
569
|
+
kurtosis of x for the last d days
|
562
570
|
|
563
571
|
Parameters
|
564
572
|
----------
|
@@ -603,16 +611,18 @@ def ts_kurtosis(x: Expr, d: int = 5, bias: bool = False, min_samples: Optional[i
|
|
603
611
|
|
604
612
|
|
605
613
|
def ts_l2_norm(x: Expr, d: int = 5, min_samples: Optional[int] = None) -> Expr:
|
606
|
-
"""
|
614
|
+
"""欧几里得范数
|
607
615
|
|
608
|
-
|
616
|
+
Euclidean norm
|
617
|
+
"""
|
609
618
|
minp = min_samples or polars_ta.MIN_SAMPLES
|
610
619
|
return x.pow(2).rolling_sum(d, min_samples=minp).sqrt()
|
611
620
|
|
612
621
|
|
613
622
|
def ts_log_diff(x: Expr, d: int = 1) -> Expr:
|
614
|
-
"""
|
623
|
+
"""求对数,然后时序滚动差分
|
615
624
|
|
625
|
+
log(current value of input or x[t] ) - log(previous value of input or x[t-1]).
|
616
626
|
"""
|
617
627
|
return x.log().diff(d)
|
618
628
|
|
@@ -624,7 +634,9 @@ def ts_max(x: Expr, d: int = 30, min_samples: Optional[int] = None) -> Expr:
|
|
624
634
|
|
625
635
|
|
626
636
|
def ts_max_diff(x: Expr, d: int = 30, min_samples: Optional[int] = None) -> Expr:
|
627
|
-
"""
|
637
|
+
"""窗口内最大值与当前值的差异
|
638
|
+
|
639
|
+
x - ts_max(x, d)"""
|
628
640
|
return x - ts_max(x, d, min_samples)
|
629
641
|
|
630
642
|
|
@@ -647,24 +659,30 @@ def ts_min(x: Expr, d: int = 30, min_samples: Optional[int] = None) -> Expr:
|
|
647
659
|
|
648
660
|
|
649
661
|
def ts_min_diff(x: Expr, d: int = 30, min_samples: Optional[int] = None) -> Expr:
|
650
|
-
"""
|
662
|
+
"""窗口内最小值与当前值的差异
|
663
|
+
|
664
|
+
x - ts_min(x, d)"""
|
651
665
|
return x - ts_min(x, d, min_samples)
|
652
666
|
|
653
667
|
|
654
668
|
def ts_min_max_cps(x: Expr, d: int, f: float = 2.0, min_samples: Optional[int] = None) -> Expr:
|
655
|
-
"""
|
669
|
+
"""计算时间窗口内最小值与最大值的总和减去当前值的加权结果
|
670
|
+
|
671
|
+
(ts_min(x, d) + ts_max(x, d)) - f * x"""
|
656
672
|
return (ts_min(x, d, min_samples) + ts_max(x, d, min_samples)) - f * x
|
657
673
|
|
658
674
|
|
659
675
|
def ts_min_max_diff(x: Expr, d: int, f: float = 0.5, min_samples: Optional[int] = None) -> Expr:
|
660
|
-
"""
|
676
|
+
"""计算当前值 x 与基于时间窗口内最小值、最大值的加权组合的差值
|
677
|
+
|
678
|
+
x - f * (ts_min(x, d) + ts_max(x, d))"""
|
661
679
|
return x - f * (ts_min(x, d, min_samples) + ts_max(x, d, min_samples))
|
662
680
|
|
663
681
|
|
664
682
|
def ts_moment(x: Expr, d: int, k: int = 0, min_samples: Optional[int] = None) -> Expr:
|
665
|
-
"""
|
683
|
+
"""滚动k阶中心距
|
666
684
|
|
667
|
-
|
685
|
+
Returns K-th central moment of x for the past d days.
|
668
686
|
|
669
687
|
Parameters
|
670
688
|
----------
|
@@ -679,18 +697,19 @@ def ts_moment(x: Expr, d: int, k: int = 0, min_samples: Optional[int] = None) ->
|
|
679
697
|
|
680
698
|
|
681
699
|
def ts_partial_corr(x: Expr, y: Expr, z: Expr, d: int, min_samples: Optional[int] = None) -> Expr:
|
682
|
-
"""
|
700
|
+
"""滚动偏相关
|
701
|
+
|
702
|
+
Returns partial correlation of x, y, z for the past d days.
|
683
703
|
|
684
|
-
滚动偏相关
|
685
704
|
"""
|
686
705
|
minp = min_samples or polars_ta.MIN_SAMPLES or d
|
687
706
|
return struct([x, y, z]).map_batches(lambda xx: batches_i2_o1(struct_to_numpy(xx, 3), roll_partial_corr, d, minp))
|
688
707
|
|
689
708
|
|
690
709
|
def ts_percentage(x: Expr, d: int, percentage: float = 0.5, min_samples: Optional[int] = None) -> Expr:
|
691
|
-
"""
|
710
|
+
"""滚动百分位数
|
692
711
|
|
693
|
-
|
712
|
+
Returns percentile value of x for the past d days.
|
694
713
|
|
695
714
|
Parameters
|
696
715
|
----------
|
@@ -722,15 +741,22 @@ def ts_rank(x: Expr, d: int = 5, min_samples: Optional[int] = None) -> Expr:
|
|
722
741
|
return x.map_batches(lambda a: roll_rank(a, d, minp, True))
|
723
742
|
|
724
743
|
|
744
|
+
def ts_realized_volatility(close: Expr, d: int = 5, min_samples: Optional[int] = None) -> Expr:
|
745
|
+
"""已实现波动率"""
|
746
|
+
minp = min_samples or polars_ta.MIN_SAMPLES or d
|
747
|
+
return ts_log_diff(close, 1).rolling_std(d, ddof=0, min_samples=minp)
|
748
|
+
|
749
|
+
|
725
750
|
def ts_returns(x: Expr, d: int = 1) -> Expr:
|
726
751
|
"""简单收益率"""
|
727
752
|
return x.pct_change(d)
|
728
753
|
|
729
754
|
|
730
755
|
def ts_scale(x: Expr, d: int = 5, min_samples: Optional[int] = None) -> Expr:
|
731
|
-
"""
|
756
|
+
"""时序滚动缩放
|
757
|
+
|
758
|
+
Returns (x – ts_min(x, d)) / (ts_max(x, d) – ts_min(x, d)) + constant
|
732
759
|
|
733
|
-
时序滚动缩放
|
734
760
|
"""
|
735
761
|
a = ts_min(x, d, min_samples)
|
736
762
|
b = ts_max(x, d, min_samples)
|
@@ -739,9 +765,9 @@ def ts_scale(x: Expr, d: int = 5, min_samples: Optional[int] = None) -> Expr:
|
|
739
765
|
|
740
766
|
|
741
767
|
def ts_skewness(x: Expr, d: int = 5, bias: bool = False, min_samples: Optional[int] = None) -> Expr:
|
742
|
-
"""
|
768
|
+
"""时序滚动偏度
|
743
769
|
|
744
|
-
|
770
|
+
Return skewness of x for the past d days
|
745
771
|
|
746
772
|
Parameters
|
747
773
|
----------
|
@@ -836,8 +862,9 @@ def ts_sum_split_by(x: Expr, by: Expr, d: int = 30, k: int = 10) -> Expr:
|
|
836
862
|
|
837
863
|
|
838
864
|
def ts_triple_corr(x: Expr, y: Expr, z: Expr, d: int, min_samples: Optional[int] = None) -> Expr:
|
839
|
-
"""时序滚动三重相关系数
|
865
|
+
"""时序滚动三重相关系数
|
840
866
|
|
867
|
+
Returns triple correlation of x, y, z for the past d days.
|
841
868
|
|
842
869
|
"""
|
843
870
|
minp = min_samples or polars_ta.MIN_SAMPLES or d
|
@@ -845,7 +872,9 @@ def ts_triple_corr(x: Expr, y: Expr, z: Expr, d: int, min_samples: Optional[int]
|
|
845
872
|
|
846
873
|
|
847
874
|
def ts_weighted_decay(x: Expr, k: float = 0.5, min_samples: Optional[int] = None) -> Expr:
|
848
|
-
"""
|
875
|
+
"""时序滚动加权衰减求和
|
876
|
+
|
877
|
+
Instead of replacing today’s value with yesterday’s as in ts_delay(x, 1),
|
849
878
|
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).
|
850
879
|
|
851
880
|
Parameters
|
polars_ta/wq/transformational.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
from polars import Expr, when, Boolean, Int32
|
1
|
+
from polars import Expr, when, Boolean, Int32, Float32
|
2
2
|
|
3
3
|
|
4
4
|
def cut(x: Expr, b: float, *more_bins) -> Expr:
|
@@ -86,7 +86,7 @@ def clamp(x: Expr, lower: float = 0, upper: float = 0, inverse: bool = False, ma
|
|
86
86
|
# raise
|
87
87
|
|
88
88
|
|
89
|
-
def
|
89
|
+
def _keep(x: Expr, f: float, period: int = 5) -> Expr:
|
90
90
|
"""This operator outputs value x when f changes and continues to do that for “period” days after f stopped changing. After “period” days since last change of f, NaN is output."""
|
91
91
|
raise
|
92
92
|
|
@@ -211,7 +211,7 @@ def right_tail(x: Expr, minimum: float = 0) -> Expr:
|
|
211
211
|
|
212
212
|
|
213
213
|
def sigmoid(x: Expr) -> Expr:
|
214
|
-
"""
|
214
|
+
"""sigmoid激活函数"""
|
215
215
|
return 1 / (1 + (-x).exp())
|
216
216
|
|
217
217
|
|
@@ -258,10 +258,15 @@ def tail(x: Expr, lower: float = 0, upper: float = 0, newval: float = 0) -> Expr
|
|
258
258
|
|
259
259
|
|
260
260
|
def int_(a: Expr) -> Expr:
|
261
|
-
"""
|
261
|
+
"""bool转int"""
|
262
262
|
return a.cast(Int32)
|
263
263
|
|
264
264
|
|
265
265
|
def bool_(a: Expr) -> Expr:
|
266
|
-
"""
|
266
|
+
"""int转成bool"""
|
267
267
|
return a.cast(Boolean)
|
268
|
+
|
269
|
+
|
270
|
+
def float_(a: Expr) -> Expr:
|
271
|
+
"""int转成float"""
|
272
|
+
return a.cast(Float32)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: polars_ta
|
3
|
-
Version: 0.5.
|
3
|
+
Version: 0.5.4
|
4
4
|
Summary: polars expressions
|
5
5
|
Author-email: wukan <wu-kan@163.com>
|
6
6
|
License: MIT License
|
@@ -24,21 +24,19 @@ License: MIT License
|
|
24
24
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
25
25
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
26
26
|
SOFTWARE.
|
27
|
-
|
28
|
-
Keywords: polars,
|
27
|
+
License-File: LICENSE
|
28
|
+
Keywords: expression,polars,talib
|
29
29
|
Classifier: Development Status :: 4 - Beta
|
30
30
|
Classifier: Programming Language :: Python
|
31
31
|
Requires-Python: >=3.8
|
32
|
-
Description-Content-Type: text/markdown
|
33
|
-
License-File: LICENSE
|
34
|
-
Requires-Dist: polars>=1.28.0
|
35
|
-
Requires-Dist: polars-ols>=0.3.0
|
36
|
-
Requires-Dist: numpy
|
37
32
|
Requires-Dist: numba
|
33
|
+
Requires-Dist: numpy
|
38
34
|
Requires-Dist: pandas
|
35
|
+
Requires-Dist: polars-ols>=0.3.0
|
36
|
+
Requires-Dist: polars>=1.28.0
|
39
37
|
Provides-Extra: talib
|
40
|
-
Requires-Dist:
|
41
|
-
|
38
|
+
Requires-Dist: ta-lib; extra == 'talib'
|
39
|
+
Description-Content-Type: text/markdown
|
42
40
|
|
43
41
|
# polars_ta
|
44
42
|
|
@@ -248,6 +246,11 @@ mkdocs build
|
|
248
246
|
也可以通过以下链接导入:
|
249
247
|
https://polars-ta.readthedocs.io/en/latest/llms-full.txt
|
250
248
|
|
249
|
+
## 提示词
|
250
|
+
由于`llms-full.txt`信息不适合做提示词,所以`tools/prompt.py`提供了生成更简洁算子清单的功能。
|
251
|
+
|
252
|
+
用户也可以直接使用`prompt.txt`(欢迎提示词工程专家帮忙改进,做的更准确)
|
253
|
+
|
251
254
|
## 参考
|
252
255
|
|
253
256
|
- https://github.com/pola-rs/polars
|
@@ -1,15 +1,19 @@
|
|
1
1
|
polars_ta/__init__.py,sha256=ig6f6c1AMSpntwKjqaX3msBzVIwkI7J776IujEmiuvA,123
|
2
|
-
polars_ta/_version.py,sha256=
|
2
|
+
polars_ta/_version.py,sha256=DITpct-LrdIsTgwx2NgH5Ghx5y8Xgz1YMimy1ZV5RTY,22
|
3
3
|
polars_ta/noise.py,sha256=LJHubBqnWlU3Bz84z07N1JB-b-hAMW2rgBF1BT4m0FE,1471
|
4
4
|
polars_ta/candles/__init__.py,sha256=AW68IuFC0gD4_OyjwLP3p22WSzSIYqlSrsS9fW_15xw,141
|
5
5
|
polars_ta/candles/cdl1.py,sha256=RnRu1QzpqEt5y0-1hlfZRUvza1no-Gj4x_dx2QWxr5A,3130
|
6
6
|
polars_ta/candles/cdl1_limit.py,sha256=1escagSXOS1N0kxrItwfrmrvZ5aQf8jqEXQRRu90Pf0,3914
|
7
7
|
polars_ta/candles/cdl2.py,sha256=jQJTKmyEmv5Pqxe2QIVUyu_fD681rirhgHwksdoaFs0,1122
|
8
|
+
polars_ta/labels/__init__.py,sha256=NKANbfheMNIs97jVXgqtZwkfx8RQxH9fY7D_fh1V_Ls,46
|
9
|
+
polars_ta/labels/_nb.py,sha256=rNGQOTEeO0tZfYPL7IZkGSjs4DmMIlzX_Y0j1LSqagg,1577
|
10
|
+
polars_ta/labels/future.py,sha256=OdERljrbzzLwnjmQaOFNantzv-CEeUpbMasMUfIzGpY,5304
|
8
11
|
polars_ta/performance/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
12
|
polars_ta/performance/drawdown.py,sha256=9blEXGXT-ficbwbaIqwnY0cIeY9oAL0LrwviZW4wVWU,240
|
10
|
-
polars_ta/performance/returns.py,sha256
|
13
|
+
polars_ta/performance/returns.py,sha256=-2G-RcMEJkL2ESqgwpBixT2Gjlxq2zBi3RJ5btGER-8,440
|
11
14
|
polars_ta/prefix/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
12
15
|
polars_ta/prefix/cdl.py,sha256=DS5GACM3biJmzunlUCkiQrZy-ltzQP0vFmCKkfGxS5E,40
|
16
|
+
polars_ta/prefix/labels.py,sha256=v15cxwiZ3K3PnSqpYG4821bVZXfZminZU5hSQQiXKKw,39
|
13
17
|
polars_ta/prefix/reports.py,sha256=B2QgdfX6RbZu9ytgaINv3Aq-ZAh_m3cr2pgbpFyL35A,40
|
14
18
|
polars_ta/prefix/ta.py,sha256=qIb3oRmexNZ6LTQ35V194QTLqj8UgzjaYl5ASwqN5pc,4167
|
15
19
|
polars_ta/prefix/talib.py,sha256=6JsrkgDIUsR2bIA7jVywxgWwxiiFuzsCPvbDeAt4qBA,9392
|
@@ -17,6 +21,7 @@ polars_ta/prefix/tdx.py,sha256=EttaExzqoA3Y3lD-YKA32-5GfJ6jgKjt-nRuoeuK0wQ,11429
|
|
17
21
|
polars_ta/prefix/wq.py,sha256=PpSLQQ3vD0Mf3Tiz_AFSi--q8p7CkLg9CHh_ayMfoYo,35
|
18
22
|
polars_ta/reports/__init__.py,sha256=KEATtWxhdaO6XScHYN2XE4WkYbYpQvDOEyXgyc2z22g,45
|
19
23
|
polars_ta/reports/cicc.py,sha256=ZpNzHo5h855Xo9IeKeOzlUjjwE5tR8opb11UoJVxGkg,707
|
24
|
+
polars_ta/ta/README.md,sha256=XuDf1sMxNrq9QDEiwBaP8cp-skTK3Jr5VClxhsNiYJ4,647
|
20
25
|
polars_ta/ta/__init__.py,sha256=GRI1suzvmLxfyfXAik4zsxqLaijq5MRCO-fUx3qaCl0,351
|
21
26
|
polars_ta/ta/momentum.py,sha256=-W-wZ1oQE9QiUiVgEx7fvnCEkWJnW6j9CxA7Mc-WMGg,5623
|
22
27
|
polars_ta/ta/operators.py,sha256=H_ORq1SeFKLj58vrOTAIa-X135evZNyo4ZE7gaH_7VM,3711
|
@@ -26,7 +31,9 @@ polars_ta/ta/statistic.py,sha256=dS5dPBszbdlroJ9u5aXBniJmKgPQnuh9zE7miYKzICs,968
|
|
26
31
|
polars_ta/ta/transform.py,sha256=c4s5l6khVqIer50g6oScdZ1EEPWYANeKm64AkBkPrtY,1789
|
27
32
|
polars_ta/ta/volatility.py,sha256=yQDKLxos521y3RzywOcE0hTj3qIG_2mfqpARpdxQ1KU,836
|
28
33
|
polars_ta/ta/volume.py,sha256=fPd9Po30kFu-cSmYoRQP4_Ypi9oSWROj650-mjwlfwM,739
|
34
|
+
polars_ta/talib/README.md,sha256=IC-pwcGYXALKzMlK0C9GeswoUlCDK86mxmrAagzPy8s,537
|
29
35
|
polars_ta/talib/__init__.py,sha256=UZIkJ6tDYTcxBuKqjeKW93Ya_VyzTtNjXefoTqMd5P8,69701
|
36
|
+
polars_ta/tdx/README.md,sha256=rI7VUKm6H8_HBpm9MUePuuf1uE8JTfDX1AvPsfMZPPQ,545
|
30
37
|
polars_ta/tdx/__init__.py,sha256=HBVPri6GwiEsFx4op0ZxDa3Yk4MbnPZgth5xJhtnxiA,662
|
31
38
|
polars_ta/tdx/_chip.py,sha256=2eCe-y_0DcBivVjQHXlFwAiY410-hH-KKPrsUcRJcyk,3832
|
32
39
|
polars_ta/tdx/_nb.py,sha256=IV3XrgSYPoR4jnOOT8p7jJWGtnoRrHLw5-fnIOfmMvA,2192
|
@@ -47,22 +54,21 @@ polars_ta/tdx/trend_feature.py,sha256=uNc4Z46Kyd7Prl0Ftl2ljSAXztTzQtbO28p7gy8iMv
|
|
47
54
|
polars_ta/tdx/volume.py,sha256=juYM4Qlx2BX5okRCSwuf-6kRUETqDF7MVWUbYIzc4ww,901
|
48
55
|
polars_ta/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
49
56
|
polars_ta/utils/helper.py,sha256=rqxBhmA-RhpHd1-qxdYi7OEZloQpPxR30Kz8fJ_hLic,6254
|
50
|
-
polars_ta/utils/numba_.py,sha256=
|
57
|
+
polars_ta/utils/numba_.py,sha256=P0z-81mabX_9zyJOX0Ib1CFmvPl9-SSatzki3dOciVA,5972
|
51
58
|
polars_ta/utils/pandas_.py,sha256=codb51l45TUMngY55twQaUPUxnffjvj8UEOm35zFpNE,1989
|
52
59
|
polars_ta/utils/pit.py,sha256=YNgUE6mbwhrtA-7wyOL0PCUDdwfTQouXwage-cK6efY,4312
|
53
60
|
polars_ta/utils/wrapper.py,sha256=jbR-ZQdzBf5iWvtnJ1HsN9HdepmDbU7fUj4w8Bt2BkU,3422
|
54
61
|
polars_ta/wq/__init__.py,sha256=C3YYJc997XCUI7H_afGT_mj2m4UdHMcql4sboCVvrXU,327
|
55
62
|
polars_ta/wq/_nb.py,sha256=9N7afRiABqdjO1QPnRlP1RIKJ98cQLpv6nF3dsqUA6k,11281
|
56
63
|
polars_ta/wq/_slow.py,sha256=MfWg9FYX8NGNLWN4ezI_awf3pPTqhSq_zo0LOS4nCzw,937
|
57
|
-
polars_ta/wq/arithmetic.py,sha256=
|
58
|
-
polars_ta/wq/cross_sectional.py,sha256=
|
59
|
-
polars_ta/wq/logical.py,sha256=
|
60
|
-
polars_ta/wq/preprocess.py,sha256=
|
61
|
-
polars_ta/wq/time_series.py,sha256=
|
62
|
-
polars_ta/wq/transformational.py,sha256=
|
64
|
+
polars_ta/wq/arithmetic.py,sha256=NwyX-K8j9ul7XHHSNuGimBq6f3NvcOGQ4le5PQuaRPc,26346
|
65
|
+
polars_ta/wq/cross_sectional.py,sha256=1unrHaPPDQIZACg0CepWn3CXvd_zmQWjNwbXzqZXke8,14518
|
66
|
+
polars_ta/wq/logical.py,sha256=PfcPrY3iYoYFDTJ-B1IlCfpab1uTWV7GN1TdRtjauEk,2241
|
67
|
+
polars_ta/wq/preprocess.py,sha256=Zpjv7zpU690Ugr5PNnq6CNlUn5qD9sH0SQr5q5AFtys,3444
|
68
|
+
polars_ta/wq/time_series.py,sha256=KGVgFSQWiDAOpN7nW0rPE8UE81Q3Co9WwZiY1DWs3KQ,33164
|
69
|
+
polars_ta/wq/transformational.py,sha256=HBnxQiS2Pw0fHnRW-aLqbznQVl1SSbZ9OqZG62igiJk,7266
|
63
70
|
polars_ta/wq/vector.py,sha256=Qs-mHC2YsiWXoyMuXZZPzd5W5w_HL1ZgDCj9wRAnqmQ,1902
|
64
|
-
polars_ta-0.5.
|
65
|
-
polars_ta-0.5.
|
66
|
-
polars_ta-0.5.
|
67
|
-
polars_ta-0.5.
|
68
|
-
polars_ta-0.5.3.dist-info/RECORD,,
|
71
|
+
polars_ta-0.5.4.dist-info/METADATA,sha256=YuA2qBXp9R4_9PbOLyk-ZhjiUdTnNLxXKQmZPvpIjc8,8839
|
72
|
+
polars_ta-0.5.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
73
|
+
polars_ta-0.5.4.dist-info/licenses/LICENSE,sha256=nREFtfwxWCCYD-ZA1jMzhhxMyTz-wGWFlnkpgg0DCtQ,1062
|
74
|
+
polars_ta-0.5.4.dist-info/RECORD,,
|
@@ -1 +0,0 @@
|
|
1
|
-
polars_ta
|
File without changes
|