betaquant 0.5.3__tar.gz → 0.5.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {betaquant-0.5.3 → betaquant-0.5.4}/.gitea/workflows/publish.yml +1 -1
- {betaquant-0.5.3 → betaquant-0.5.4}/Cargo.lock +2 -2
- {betaquant-0.5.3 → betaquant-0.5.4}/Cargo.toml +3 -3
- {betaquant-0.5.3 → betaquant-0.5.4}/PKG-INFO +18 -18
- {betaquant-0.5.3 → betaquant-0.5.4}/README.md +16 -16
- {betaquant-0.5.3 → betaquant-0.5.4}/build.rs +2 -2
- {betaquant-0.5.3 → betaquant-0.5.4}/examples/gtja191/al/__init__.py +7 -7
- betaquant-0.5.4/examples/gtja191/al/alpha191_context.py +1 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/examples/gtja191/main.py +3 -3
- {betaquant-0.5.3 → betaquant-0.5.4}/examples/quickstart/full_demo.py +15 -15
- {betaquant-0.5.3 → betaquant-0.5.4}/examples/quickstart/rank.py +3 -3
- {betaquant-0.5.3 → betaquant-0.5.4}/examples/quickstart/usage.py +1 -1
- {betaquant-0.5.3 → betaquant-0.5.4}/examples/quickstart/verify_sumif.py +2 -2
- {betaquant-0.5.3 → betaquant-0.5.4}/examples/wq101/al/__init__.py +7 -7
- {betaquant-0.5.3 → betaquant-0.5.4}/examples/wq101/al/alpha101_context.py +1 -1
- {betaquant-0.5.3 → betaquant-0.5.4}/examples/wq101/main.py +3 -3
- {betaquant-0.5.3 → betaquant-0.5.4}/pyproject.toml +2 -3
- {betaquant-0.5.3/python/betalib → betaquant-0.5.4/python/betaquant}/context.py +5 -5
- {betaquant-0.5.3/python/betalib → betaquant-0.5.4/python/betaquant}/lang/__main__.py +1 -1
- {betaquant-0.5.3/python/betalib → betaquant-0.5.4/python/betaquant}/perf.py +4 -4
- {betaquant-0.5.3 → betaquant-0.5.4}/python/tests/test_grammar.py +1 -1
- {betaquant-0.5.3 → betaquant-0.5.4}/python/tests/test_rank.py +6 -6
- {betaquant-0.5.3 → betaquant-0.5.4}/python/tests/test_to_python.py +1 -1
- {betaquant-0.5.3 → betaquant-0.5.4}/src//345/277/205/350/257/273.md +14 -14
- betaquant-0.5.3/examples/gtja191/al/alpha191_context.py +0 -1
- {betaquant-0.5.3 → betaquant-0.5.4}/.gitea/builder/Dockerfile +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/.gitea/builder/README.md +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/.gitignore +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/CHANGELOG.md +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/LICENSE +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/examples/gtja191/al/alpha191.py +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/examples/gtja191/alpha191.txt +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/examples/wq101/al/alpha101.py +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/examples/wq101/alpha101.txt +0 -0
- {betaquant-0.5.3/python/betalib → betaquant-0.5.4/python/betaquant}/__init__.py +0 -0
- {betaquant-0.5.3/python/betalib → betaquant-0.5.4/python/betaquant}/algo/__init__.py +0 -0
- {betaquant-0.5.3/python/betalib → betaquant-0.5.4/python/betaquant}/algo/algo_gen.py +0 -0
- {betaquant-0.5.3/python/betalib → betaquant-0.5.4/python/betaquant}/algo/manual.py +0 -0
- {betaquant-0.5.3/python/betalib → betaquant-0.5.4/python/betaquant}/algo.md +0 -0
- {betaquant-0.5.3/python/betalib → betaquant-0.5.4/python/betaquant}/lang/__init__.py +0 -0
- {betaquant-0.5.3/python/betalib → betaquant-0.5.4/python/betaquant}/lang/alpha.lark +0 -0
- {betaquant-0.5.3/python/betalib → betaquant-0.5.4/python/betaquant}/lang/parser.py +0 -0
- {betaquant-0.5.3/python/betalib → betaquant-0.5.4/python/betaquant}/lang/to_python.py +0 -0
- {betaquant-0.5.3/python/betalib → betaquant-0.5.4/python/betaquant}/transforms.py +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/rustfmt.toml +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/src/algo/alpha.rs +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/src/algo/backfill.rs +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/src/algo/context.rs +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/src/algo/cross.rs +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/src/algo/drawdown.rs +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/src/algo/ema.rs +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/src/algo/entropy.rs +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/src/algo/error.rs +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/src/algo/extremum.rs +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/src/algo/group.rs +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/src/algo/internal.rs +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/src/algo/ma.rs +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/src/algo/misc.rs +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/src/algo/mod.rs +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/src/algo/moments.rs +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/src/algo/neutralize.rs +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/src/algo/quantile.rs +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/src/algo/rank.rs +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/src/algo/returns.rs +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/src/algo/rolling.rs +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/src/algo/scan.rs +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/src/algo/series.rs +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/src/algo/sharpe.rs +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/src/algo/slope.rs +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/src/algo/spec.rs +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/src/algo/stats.rs +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/src/algo/stddev.rs +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/src/algo/sum.rs +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/src/algo/zscore.rs +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/src/lib.rs +0 -0
- {betaquant-0.5.3 → betaquant-0.5.4}/tag_release.py +0 -0
|
@@ -24,8 +24,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
24
24
|
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
|
25
25
|
|
|
26
26
|
[[package]]
|
|
27
|
-
name = "
|
|
28
|
-
version = "0.5.
|
|
27
|
+
name = "betaquant"
|
|
28
|
+
version = "0.5.4"
|
|
29
29
|
dependencies = [
|
|
30
30
|
"anyhow",
|
|
31
31
|
"log",
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
[package]
|
|
2
|
-
name = "
|
|
3
|
-
version = "0.5.
|
|
2
|
+
name = "betaquant"
|
|
3
|
+
version = "0.5.4"
|
|
4
4
|
edition = "2024"
|
|
5
5
|
authors = ["ZhaoJun"]
|
|
6
6
|
readme = "README.md"
|
|
7
7
|
|
|
8
8
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
9
9
|
[lib]
|
|
10
|
-
name = "
|
|
10
|
+
name = "betaquant"
|
|
11
11
|
crate-type = ["cdylib", "rlib"]
|
|
12
12
|
doctest = false
|
|
13
13
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: betaquant
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.4
|
|
4
4
|
Classifier: Programming Language :: Rust
|
|
5
5
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
6
6
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
@@ -12,9 +12,9 @@ Author: ZhaoJun
|
|
|
12
12
|
License-Expression: BSD-2-Clause
|
|
13
13
|
Requires-Python: >=3.11
|
|
14
14
|
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
15
|
-
Project-URL: repository, https://
|
|
15
|
+
Project-URL: repository, https://home.zhaojun.com
|
|
16
16
|
|
|
17
|
-
#
|
|
17
|
+
# betaquant
|
|
18
18
|
|
|
19
19
|
高性能量化金融算子库。Rust 实现 + Python 绑定 ([PyO3](https://pyo3.rs/))。
|
|
20
20
|
|
|
@@ -25,14 +25,14 @@ Project-URL: repository, https://github.com/tic-top/py-alpha-lib
|
|
|
25
25
|
## 安装
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
|
-
pip install
|
|
28
|
+
pip install betaquant
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
## 使用
|
|
32
32
|
|
|
33
33
|
### 上下文设置
|
|
34
34
|
|
|
35
|
-
通过 `
|
|
35
|
+
通过 `betaquant.set_ctx()` 控制计算行为:
|
|
36
36
|
|
|
37
37
|
- **`groups`** — 数据数组中的标的数量。每个 group 独立并行处理。`cc_rank` 等截面算子要求 `groups >= 2`。
|
|
38
38
|
- **`flags`** — 位标志:
|
|
@@ -40,9 +40,9 @@ pip install betalib
|
|
|
40
40
|
- `FLAG_STRICTLY_CYCLE` (2):窗口未填满前返回 NaN(与 pandas `rolling()` 默认行为一致)。
|
|
41
41
|
- 用 `|` 组合:`flags=FLAG_SKIP_NAN | FLAG_STRICTLY_CYCLE`
|
|
42
42
|
|
|
43
|
-
`set_ctx` 只更新传入的字段,其它字段保持当前值。要恢复默认 (`groups=0, flags=0`) 调用 `
|
|
43
|
+
`set_ctx` 只更新传入的字段,其它字段保持当前值。要恢复默认 (`groups=0, flags=0`) 调用 `betaquant.reset_ctx()`。
|
|
44
44
|
|
|
45
|
-
如需只算某一段,请在调用前自行切片输入数组(如 `
|
|
45
|
+
如需只算某一段,请在调用前自行切片输入数组(如 `betaquant.ts_ma(data[start:end], 3)`)。
|
|
46
46
|
|
|
47
47
|
### NaN 处理合约(所有滑窗算子)
|
|
48
48
|
|
|
@@ -72,24 +72,24 @@ pip install betalib
|
|
|
72
72
|
`NaN`、`±inf`、`ts_sma(n=0, ...)` 都会报 `InvalidParameter`,而不是产生 NaN 输出。
|
|
73
73
|
|
|
74
74
|
```python
|
|
75
|
-
import
|
|
75
|
+
import betaquant
|
|
76
76
|
import numpy as np
|
|
77
77
|
|
|
78
78
|
data = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], dtype=np.float64)
|
|
79
79
|
|
|
80
80
|
# 3 周期均线(预热阶段返回部分窗口结果)
|
|
81
|
-
result =
|
|
81
|
+
result = betaquant.ts_ma(data, 3)
|
|
82
82
|
# [1. 1.5 2. 3. 4. 5. 6. 7. 8. 9.]
|
|
83
83
|
|
|
84
84
|
# 严格模式:窗口填满前返回 NaN
|
|
85
|
-
|
|
86
|
-
result =
|
|
85
|
+
betaquant.set_ctx(flags=betaquant.FLAG_STRICTLY_CYCLE)
|
|
86
|
+
result = betaquant.ts_ma(data, 3)
|
|
87
87
|
# [nan nan 2. 3. 4. 5. 6. 7. 8. 9.]
|
|
88
88
|
|
|
89
89
|
# 跳过 NaN(fixed-time-slot:窗口里跳过 NaN,剩余有效值算均值)
|
|
90
|
-
|
|
90
|
+
betaquant.set_ctx(flags=betaquant.FLAG_SKIP_NAN)
|
|
91
91
|
data_nan = np.array([1, 2, np.nan, 4, 5, 6, 7, 8, 9, 10], dtype=np.float64)
|
|
92
|
-
result =
|
|
92
|
+
result = betaquant.ts_ma(data_nan, 3)
|
|
93
93
|
# [1. 1.5 nan 3. 4.5 5. 6. 7. 8. 9. ]
|
|
94
94
|
# i=2 当前是 NaN ⇒ NaN;i=3 窗口 [2,NaN,4] valid [2,4] mean=3.0;
|
|
95
95
|
# i=4 窗口 [NaN,4,5] valid [4,5] mean=4.5;之后窗口无 NaN,恢复正常。
|
|
@@ -118,12 +118,12 @@ python -m alpha.lang examples/wq101/alpha101.txt > factors.py
|
|
|
118
118
|
跑生成的因子:
|
|
119
119
|
|
|
120
120
|
```python
|
|
121
|
-
import
|
|
121
|
+
import betaquant
|
|
122
122
|
from factors import alpha_001
|
|
123
123
|
|
|
124
124
|
# 用合成面板做最小可运行例子;自己的数据用 polars.DataFrame 传入也行
|
|
125
|
-
data =
|
|
126
|
-
ctx =
|
|
125
|
+
data = betaquant.make_synthetic_panel(securities=50, trades=252)
|
|
126
|
+
ctx = betaquant.ExecContext(data) # 自动推断 groups
|
|
127
127
|
result = alpha_001(ctx)
|
|
128
128
|
```
|
|
129
129
|
|
|
@@ -142,7 +142,7 @@ result = alpha_001(ctx)
|
|
|
142
142
|
python examples/gtja191/main.py
|
|
143
143
|
```
|
|
144
144
|
|
|
145
|
-
默认用 `
|
|
145
|
+
默认用 `betaquant.make_synthetic_panel()` 生成 50 股 × 252 天的合成面板,跑全部因子并打印
|
|
146
146
|
绩效统计。要换成自己的数据,直接调用 `examples.gtja191.al.run(data=<polars.DataFrame>,
|
|
147
147
|
alphas=[1, 2, 3])`。
|
|
148
148
|
|
|
@@ -164,7 +164,7 @@ python examples/wq101/main.py
|
|
|
164
164
|
|
|
165
165
|
### 已支持的算子
|
|
166
166
|
|
|
167
|
-
完整函数签名与说明:[python/
|
|
167
|
+
完整函数签名与说明:[python/betaquant/algo.md](python/betaquant/algo.md)
|
|
168
168
|
|
|
169
169
|
### 入门示例
|
|
170
170
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# betaquant
|
|
2
2
|
|
|
3
3
|
高性能量化金融算子库。Rust 实现 + Python 绑定 ([PyO3](https://pyo3.rs/))。
|
|
4
4
|
|
|
@@ -9,14 +9,14 @@
|
|
|
9
9
|
## 安装
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
pip install
|
|
12
|
+
pip install betaquant
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
## 使用
|
|
16
16
|
|
|
17
17
|
### 上下文设置
|
|
18
18
|
|
|
19
|
-
通过 `
|
|
19
|
+
通过 `betaquant.set_ctx()` 控制计算行为:
|
|
20
20
|
|
|
21
21
|
- **`groups`** — 数据数组中的标的数量。每个 group 独立并行处理。`cc_rank` 等截面算子要求 `groups >= 2`。
|
|
22
22
|
- **`flags`** — 位标志:
|
|
@@ -24,9 +24,9 @@ pip install betalib
|
|
|
24
24
|
- `FLAG_STRICTLY_CYCLE` (2):窗口未填满前返回 NaN(与 pandas `rolling()` 默认行为一致)。
|
|
25
25
|
- 用 `|` 组合:`flags=FLAG_SKIP_NAN | FLAG_STRICTLY_CYCLE`
|
|
26
26
|
|
|
27
|
-
`set_ctx` 只更新传入的字段,其它字段保持当前值。要恢复默认 (`groups=0, flags=0`) 调用 `
|
|
27
|
+
`set_ctx` 只更新传入的字段,其它字段保持当前值。要恢复默认 (`groups=0, flags=0`) 调用 `betaquant.reset_ctx()`。
|
|
28
28
|
|
|
29
|
-
如需只算某一段,请在调用前自行切片输入数组(如 `
|
|
29
|
+
如需只算某一段,请在调用前自行切片输入数组(如 `betaquant.ts_ma(data[start:end], 3)`)。
|
|
30
30
|
|
|
31
31
|
### NaN 处理合约(所有滑窗算子)
|
|
32
32
|
|
|
@@ -56,24 +56,24 @@ pip install betalib
|
|
|
56
56
|
`NaN`、`±inf`、`ts_sma(n=0, ...)` 都会报 `InvalidParameter`,而不是产生 NaN 输出。
|
|
57
57
|
|
|
58
58
|
```python
|
|
59
|
-
import
|
|
59
|
+
import betaquant
|
|
60
60
|
import numpy as np
|
|
61
61
|
|
|
62
62
|
data = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], dtype=np.float64)
|
|
63
63
|
|
|
64
64
|
# 3 周期均线(预热阶段返回部分窗口结果)
|
|
65
|
-
result =
|
|
65
|
+
result = betaquant.ts_ma(data, 3)
|
|
66
66
|
# [1. 1.5 2. 3. 4. 5. 6. 7. 8. 9.]
|
|
67
67
|
|
|
68
68
|
# 严格模式:窗口填满前返回 NaN
|
|
69
|
-
|
|
70
|
-
result =
|
|
69
|
+
betaquant.set_ctx(flags=betaquant.FLAG_STRICTLY_CYCLE)
|
|
70
|
+
result = betaquant.ts_ma(data, 3)
|
|
71
71
|
# [nan nan 2. 3. 4. 5. 6. 7. 8. 9.]
|
|
72
72
|
|
|
73
73
|
# 跳过 NaN(fixed-time-slot:窗口里跳过 NaN,剩余有效值算均值)
|
|
74
|
-
|
|
74
|
+
betaquant.set_ctx(flags=betaquant.FLAG_SKIP_NAN)
|
|
75
75
|
data_nan = np.array([1, 2, np.nan, 4, 5, 6, 7, 8, 9, 10], dtype=np.float64)
|
|
76
|
-
result =
|
|
76
|
+
result = betaquant.ts_ma(data_nan, 3)
|
|
77
77
|
# [1. 1.5 nan 3. 4.5 5. 6. 7. 8. 9. ]
|
|
78
78
|
# i=2 当前是 NaN ⇒ NaN;i=3 窗口 [2,NaN,4] valid [2,4] mean=3.0;
|
|
79
79
|
# i=4 窗口 [NaN,4,5] valid [4,5] mean=4.5;之后窗口无 NaN,恢复正常。
|
|
@@ -102,12 +102,12 @@ python -m alpha.lang examples/wq101/alpha101.txt > factors.py
|
|
|
102
102
|
跑生成的因子:
|
|
103
103
|
|
|
104
104
|
```python
|
|
105
|
-
import
|
|
105
|
+
import betaquant
|
|
106
106
|
from factors import alpha_001
|
|
107
107
|
|
|
108
108
|
# 用合成面板做最小可运行例子;自己的数据用 polars.DataFrame 传入也行
|
|
109
|
-
data =
|
|
110
|
-
ctx =
|
|
109
|
+
data = betaquant.make_synthetic_panel(securities=50, trades=252)
|
|
110
|
+
ctx = betaquant.ExecContext(data) # 自动推断 groups
|
|
111
111
|
result = alpha_001(ctx)
|
|
112
112
|
```
|
|
113
113
|
|
|
@@ -126,7 +126,7 @@ result = alpha_001(ctx)
|
|
|
126
126
|
python examples/gtja191/main.py
|
|
127
127
|
```
|
|
128
128
|
|
|
129
|
-
默认用 `
|
|
129
|
+
默认用 `betaquant.make_synthetic_panel()` 生成 50 股 × 252 天的合成面板,跑全部因子并打印
|
|
130
130
|
绩效统计。要换成自己的数据,直接调用 `examples.gtja191.al.run(data=<polars.DataFrame>,
|
|
131
131
|
alphas=[1, 2, 3])`。
|
|
132
132
|
|
|
@@ -148,7 +148,7 @@ python examples/wq101/main.py
|
|
|
148
148
|
|
|
149
149
|
### 已支持的算子
|
|
150
150
|
|
|
151
|
-
完整函数签名与说明:[python/
|
|
151
|
+
完整函数签名与说明:[python/betaquant/algo.md](python/betaquant/algo.md)
|
|
152
152
|
|
|
153
153
|
### 入门示例
|
|
154
154
|
|
|
@@ -372,7 +372,7 @@ fn py_convert(ty: &TaType, expr: &str) -> String {
|
|
|
372
372
|
}
|
|
373
373
|
|
|
374
374
|
fn build_algo_py(functions: &[TaFunc]) -> Result<()> {
|
|
375
|
-
let out_file = "python/
|
|
375
|
+
let out_file = "python/betaquant/algo/algo_gen.py";
|
|
376
376
|
let mut file = fs::File::create(out_file)?;
|
|
377
377
|
|
|
378
378
|
writeln!(file, "# Copyright 2026 MSD-RS Project LiJia")?;
|
|
@@ -513,7 +513,7 @@ fn build_algo_py(functions: &[TaFunc]) -> Result<()> {
|
|
|
513
513
|
|
|
514
514
|
|
|
515
515
|
fn build_algo_md(functions: &Vec<TaFunc>) -> Result<()> {
|
|
516
|
-
let mut file = fs::File::create("python/
|
|
516
|
+
let mut file = fs::File::create("python/betaquant/algo.md")?;
|
|
517
517
|
writeln!(file, "# 算子清单")?;
|
|
518
518
|
writeln!(file, "")?;
|
|
519
519
|
writeln!(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""GTJA191 因子计算 + 绩效统计(纯函数 API,不依赖命令行)。
|
|
2
2
|
|
|
3
|
-
绩效统计的公共逻辑在 ``
|
|
3
|
+
绩效统计的公共逻辑在 ``betaquant.perf``,本模块只负责数据加载、循环、收集结果。
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
6
|
from __future__ import annotations
|
|
@@ -8,7 +8,7 @@ from __future__ import annotations
|
|
|
8
8
|
import logging
|
|
9
9
|
import time
|
|
10
10
|
|
|
11
|
-
import
|
|
11
|
+
import betaquant
|
|
12
12
|
import numpy as np
|
|
13
13
|
import pandas as pd
|
|
14
14
|
import polars as pl
|
|
@@ -57,7 +57,7 @@ def run(
|
|
|
57
57
|
Args:
|
|
58
58
|
data_path: 输入 csv 路径(包含 securityid / tradetime / OHLCV 列)。
|
|
59
59
|
data: 直接传入的 polars DataFrame(与 ``data_path`` 二选一,优先使用)。
|
|
60
|
-
``data_path`` 和 ``data`` 都为 None 时会用 ``
|
|
60
|
+
``data_path`` 和 ``data`` 都为 None 时会用 ``betaquant.make_synthetic_panel()``
|
|
61
61
|
生成一份 GBM 合成面板,方便快速验证。
|
|
62
62
|
alphas: 要计算的因子编号列表;为 None 时按 [start, end) 区间取并去掉 NOFUNC。
|
|
63
63
|
start / end: alphas 为 None 时的范围。
|
|
@@ -69,10 +69,10 @@ def run(
|
|
|
69
69
|
IC / IR / 累计收益 / 年化收益 / 夏普 / 最大回撤。
|
|
70
70
|
"""
|
|
71
71
|
if data is None and data_path is None:
|
|
72
|
-
logger.info("no data given, using
|
|
73
|
-
data =
|
|
72
|
+
logger.info("no data given, using betaquant.make_synthetic_panel() (GBM)")
|
|
73
|
+
data = betaquant.make_synthetic_panel()
|
|
74
74
|
ctx, trades, securities, load_time = setup_context(data_path=data_path, data=data)
|
|
75
|
-
fwd_ret =
|
|
75
|
+
fwd_ret = betaquant.compute_forward_return(ctx)
|
|
76
76
|
|
|
77
77
|
if alphas is None:
|
|
78
78
|
alphas = [n for n in range(start, end) if n not in NOFUNC]
|
|
@@ -94,7 +94,7 @@ def run(
|
|
|
94
94
|
if verbose:
|
|
95
95
|
print(v[0:trades])
|
|
96
96
|
|
|
97
|
-
stats =
|
|
97
|
+
stats = betaquant.compute_factor_stats(v, fwd_ret, securities, trades, top_pct=top_pct)
|
|
98
98
|
# 只把标量指标塞进 DataFrame 行,曲线(ndarray)字段不进表
|
|
99
99
|
stats_scalar = {k: x for k, x in stats.items() if not isinstance(x, np.ndarray)}
|
|
100
100
|
rows.append(
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from betaquant.context import ExecContext # noqa: F401
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""GTJA191 因子全量计算 + 绩效统计入口(合成数据,纯函数,无命令行)。
|
|
2
2
|
|
|
3
|
-
数据由 ``
|
|
3
|
+
数据由 ``betaquant.make_synthetic_panel()`` 生成(GBM 价格 + OHLCV 扰动),
|
|
4
4
|
默认 50 只股票 × 252 交易日。无需任何外部下载。
|
|
5
5
|
|
|
6
6
|
用法:
|
|
@@ -14,7 +14,7 @@ from __future__ import annotations
|
|
|
14
14
|
import logging
|
|
15
15
|
|
|
16
16
|
import al
|
|
17
|
-
import
|
|
17
|
+
import betaquant
|
|
18
18
|
|
|
19
19
|
FORMAT = "%(levelname)s %(name)s %(asctime)-15s %(message)s"
|
|
20
20
|
logging.basicConfig(level=logging.INFO, format=FORMAT)
|
|
@@ -22,7 +22,7 @@ logger = logging.getLogger("gtja191")
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
def main() -> None:
|
|
25
|
-
data =
|
|
25
|
+
data = betaquant.make_synthetic_panel(securities=50, trades=252)
|
|
26
26
|
df = al.run(data=data)
|
|
27
27
|
print(df.to_string())
|
|
28
28
|
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
流程:
|
|
8
8
|
1. 用合成 OHLCV 数据造一个 long-format DataFrame(含一只股票数据缺失的情形)。
|
|
9
|
-
2. 用 ``
|
|
10
|
-
3. 用 ``
|
|
9
|
+
2. 用 ``betaquant.matrix_transform`` 把它对齐成 (date, code) MultiIndex 的稠密 long-format。
|
|
10
|
+
3. 用 ``betaquant.ExecContext`` 包起来;构造时它会自动 ``set_ctx(groups=...)`` 并按
|
|
11
11
|
``securityid * trades + tradetime`` 的顺序展开 OHLCV 字段成 ``groups × trades`` 的扁平数组。
|
|
12
12
|
4. 用 ctx 方法表达若干常见因子(rank / zscore / mean reversion / momentum)。
|
|
13
13
|
5. 取一个简单因子,与 pandas 手工实现对照,确认数值一致。
|
|
@@ -20,7 +20,7 @@ from __future__ import annotations
|
|
|
20
20
|
import numpy as np
|
|
21
21
|
import pandas as pd
|
|
22
22
|
|
|
23
|
-
import
|
|
23
|
+
import betaquant
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
# ---------------------------------------------------------------------------
|
|
@@ -71,7 +71,7 @@ print()
|
|
|
71
71
|
# 2. matrix_transform:对齐到 (trade_date, ts_code) MultiIndex 长表
|
|
72
72
|
# ---------------------------------------------------------------------------
|
|
73
73
|
|
|
74
|
-
aligned =
|
|
74
|
+
aligned = betaquant.matrix_transform(
|
|
75
75
|
df,
|
|
76
76
|
code_field="ts_code",
|
|
77
77
|
date_field="trade_date",
|
|
@@ -102,7 +102,7 @@ print(f"panel 形状:{panel.shape}(数据按 [securityid, tradetime] 排序
|
|
|
102
102
|
print(panel.head(8))
|
|
103
103
|
print()
|
|
104
104
|
|
|
105
|
-
ctx =
|
|
105
|
+
ctx = betaquant.ExecContext(panel)
|
|
106
106
|
print(
|
|
107
107
|
f"ExecContext 初始化:groups(股票数)={panel['securityid'].nunique()},"
|
|
108
108
|
f"trades(天数)={panel['tradetime'].nunique()}"
|
|
@@ -181,27 +181,27 @@ if not ok:
|
|
|
181
181
|
|
|
182
182
|
|
|
183
183
|
# ---------------------------------------------------------------------------
|
|
184
|
-
# 6. 因子绩效评估:复用
|
|
184
|
+
# 6. 因子绩效评估:复用 betaquant.compute_forward_return / betaquant.compute_factor_stats
|
|
185
185
|
#
|
|
186
186
|
# 公共逻辑(IC、IR、累计收益、年化收益、夏普、最大回撤)已经放到 alpha/perf.py,
|
|
187
187
|
# 两个 examples(gtja191 / wq101)都共用同一份实现。
|
|
188
188
|
#
|
|
189
|
-
# - 持仓回报用 ``
|
|
190
|
-
# - 单因子整体绩效用 ``
|
|
189
|
+
# - 持仓回报用 ``betaquant.compute_forward_return(ctx)``(位置 t = t+1 日 open→close)。
|
|
190
|
+
# - 单因子整体绩效用 ``betaquant.compute_factor_stats(factor, fwd, securities, trades, top_pct)``:
|
|
191
191
|
# - 按 ``top_pct`` 分位选股做多空(默认 10%);
|
|
192
192
|
# - 4 只股票时 top_pct=0.25 ⇒ top/bottom 各 1 只;
|
|
193
193
|
# - 返回 ic/ir 以及多头(long)/空头(short)/多空(ls)三腿的 cum_ret/ann_ret/sharpe/mdd。
|
|
194
194
|
# ---------------------------------------------------------------------------
|
|
195
195
|
|
|
196
196
|
print("\n" + "=" * 60)
|
|
197
|
-
print("因子绩效(公共 API:
|
|
197
|
+
print("因子绩效(公共 API:betaquant.compute_factor_stats)")
|
|
198
198
|
print("=" * 60)
|
|
199
199
|
|
|
200
|
-
fwd_ret_flat =
|
|
200
|
+
fwd_ret_flat = betaquant.compute_forward_return(ctx)
|
|
201
201
|
|
|
202
202
|
|
|
203
203
|
def report_stats(name: str, factor: np.ndarray, top_pct: float = 0.25) -> None:
|
|
204
|
-
stats =
|
|
204
|
+
stats = betaquant.compute_factor_stats(factor, fwd_ret_flat, n_codes, n_dates, top_pct=top_pct)
|
|
205
205
|
# IC/IR 是因子级指标;收益指标分多头 / 空头 / 多空三腿展示
|
|
206
206
|
table = pd.DataFrame(
|
|
207
207
|
[
|
|
@@ -251,9 +251,9 @@ if plt is not None:
|
|
|
251
251
|
|
|
252
252
|
# 上面 4 股 × 20 日的 demo 太小,10 日窗口因子的有效收益日只有 1~2 天,
|
|
253
253
|
# 画图看不出曲线。这里换一份稍大的合成面板(30 股 × 100 日)专门演示绘图。
|
|
254
|
-
big_panel =
|
|
255
|
-
big_ctx =
|
|
256
|
-
big_fwd =
|
|
254
|
+
big_panel = betaquant.make_synthetic_panel(securities=30, trades=100)
|
|
255
|
+
big_ctx = betaquant.ExecContext(big_panel)
|
|
256
|
+
big_fwd = betaquant.compute_forward_return(big_ctx)
|
|
257
257
|
big_codes = 30
|
|
258
258
|
big_dates = 100
|
|
259
259
|
|
|
@@ -273,7 +273,7 @@ if plt is not None:
|
|
|
273
273
|
axes = [axes]
|
|
274
274
|
|
|
275
275
|
for ax, (name, factor) in zip(axes, big_factors):
|
|
276
|
-
stats =
|
|
276
|
+
stats = betaquant.compute_factor_stats(factor, big_fwd, big_codes, big_dates, top_pct=0.2)
|
|
277
277
|
for leg, label in (("long", "多头"), ("short", "空头"), ("ls", "多空")):
|
|
278
278
|
eq = stats[f"{leg}_equity"]
|
|
279
279
|
if eq.size == 0:
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import numpy as np
|
|
4
4
|
import pandas as pd
|
|
5
5
|
|
|
6
|
-
import
|
|
6
|
+
import betaquant
|
|
7
7
|
|
|
8
8
|
df = pd.DataFrame(
|
|
9
9
|
data={
|
|
@@ -13,6 +13,6 @@ df = pd.DataFrame(
|
|
|
13
13
|
)
|
|
14
14
|
|
|
15
15
|
# 把 5 个样本视为 5 个 group,做截面 rank
|
|
16
|
-
|
|
17
|
-
print("
|
|
16
|
+
betaquant.set_ctx(groups=5)
|
|
17
|
+
print("betaquant.cc_rank :", betaquant.cc_rank(df["Number_legs"].to_numpy().astype(np.float64)))
|
|
18
18
|
print("pandas rank :", df["Number_legs"].rank(pct=True).to_numpy().astype(np.float64))
|
|
@@ -10,7 +10,7 @@ import sys
|
|
|
10
10
|
import numpy as np
|
|
11
11
|
|
|
12
12
|
try:
|
|
13
|
-
import
|
|
13
|
+
import betaquant
|
|
14
14
|
except ImportError:
|
|
15
15
|
print("无法导入 alpha;请先执行 `maturin develop --release` 安装到当前环境。")
|
|
16
16
|
sys.exit(1)
|
|
@@ -27,7 +27,7 @@ def test_sumif():
|
|
|
27
27
|
# 4: [2,3,4] -> 3(T), 4(F), 5(T) -> 3+5 = 8
|
|
28
28
|
expected = np.array([1.0, 1.0, 4.0, 3.0, 8.0])
|
|
29
29
|
|
|
30
|
-
res =
|
|
30
|
+
res = betaquant.ts_sumif(a, c, 3)
|
|
31
31
|
print("Input A:", a)
|
|
32
32
|
print("Input C:", c)
|
|
33
33
|
print("Result :", res)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""WQ101 因子计算 + 绩效统计(纯函数 API,不依赖命令行)。
|
|
2
2
|
|
|
3
|
-
绩效统计的公共逻辑在 ``
|
|
3
|
+
绩效统计的公共逻辑在 ``betaquant.perf``,本模块只负责数据加载、循环、收集结果。
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
6
|
from __future__ import annotations
|
|
@@ -8,7 +8,7 @@ from __future__ import annotations
|
|
|
8
8
|
import logging
|
|
9
9
|
import time
|
|
10
10
|
|
|
11
|
-
import
|
|
11
|
+
import betaquant
|
|
12
12
|
import numpy as np
|
|
13
13
|
import pandas as pd
|
|
14
14
|
import polars as pl
|
|
@@ -52,14 +52,14 @@ def run(
|
|
|
52
52
|
) -> pd.DataFrame:
|
|
53
53
|
"""计算指定编号的 WQ101 因子并附带绩效统计。
|
|
54
54
|
|
|
55
|
-
``data_path`` 与 ``data`` 都为 None 时,会用 ``
|
|
55
|
+
``data_path`` 与 ``data`` 都为 None 时,会用 ``betaquant.make_synthetic_panel()`` 生成
|
|
56
56
|
GBM 合成面板,方便快速验证。
|
|
57
57
|
"""
|
|
58
58
|
if data is None and data_path is None:
|
|
59
|
-
logger.info("no data given, using
|
|
60
|
-
data =
|
|
59
|
+
logger.info("no data given, using betaquant.make_synthetic_panel() (GBM)")
|
|
60
|
+
data = betaquant.make_synthetic_panel()
|
|
61
61
|
ctx, trades, securities, load_time = setup_context(data_path=data_path, data=data)
|
|
62
|
-
fwd_ret =
|
|
62
|
+
fwd_ret = betaquant.compute_forward_return(ctx)
|
|
63
63
|
|
|
64
64
|
if alphas is None:
|
|
65
65
|
alphas = [n for n in range(start, end) if n not in NOFUNC]
|
|
@@ -78,7 +78,7 @@ def run(
|
|
|
78
78
|
logger.info("Alpha %s computed in %.3fs", fn_name, t2 - t1)
|
|
79
79
|
if verbose:
|
|
80
80
|
print(v[0:trades])
|
|
81
|
-
stats =
|
|
81
|
+
stats = betaquant.compute_factor_stats(v, fwd_ret, securities, trades, top_pct=top_pct)
|
|
82
82
|
# 只把标量指标塞进 DataFrame 行,曲线(ndarray)字段不进表
|
|
83
83
|
stats_scalar = {k: x for k, x in stats.items() if not isinstance(x, np.ndarray)}
|
|
84
84
|
rows.append(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""WQ101 因子全量计算 + 绩效统计入口(合成数据,纯函数,无命令行)。
|
|
2
2
|
|
|
3
|
-
数据由 ``
|
|
3
|
+
数据由 ``betaquant.make_synthetic_panel()`` 生成(GBM 价格 + OHLCV 扰动),
|
|
4
4
|
默认 50 只股票 × 252 交易日。无需任何外部下载。
|
|
5
5
|
|
|
6
6
|
用法:
|
|
@@ -14,7 +14,7 @@ from __future__ import annotations
|
|
|
14
14
|
import logging
|
|
15
15
|
|
|
16
16
|
import al
|
|
17
|
-
import
|
|
17
|
+
import betaquant
|
|
18
18
|
|
|
19
19
|
FORMAT = "%(levelname)s %(name)s %(asctime)-15s %(message)s"
|
|
20
20
|
logging.basicConfig(level=logging.INFO, format=FORMAT)
|
|
@@ -22,7 +22,7 @@ logger = logging.getLogger("wq101")
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
def main() -> None:
|
|
25
|
-
data =
|
|
25
|
+
data = betaquant.make_synthetic_panel(securities=50, trades=252)
|
|
26
26
|
df = al.run(data=data)
|
|
27
27
|
print(df.to_string())
|
|
28
28
|
|
|
@@ -20,8 +20,7 @@ license-files = ["LICENSE"]
|
|
|
20
20
|
authors = [{ name = "ZhaoJun" }]
|
|
21
21
|
|
|
22
22
|
[project.urls]
|
|
23
|
-
|
|
24
|
-
repository = "https://github.com/tic-top/py-alpha-lib"
|
|
23
|
+
repository = "https://home.zhaojun.com"
|
|
25
24
|
|
|
26
25
|
[build-system]
|
|
27
26
|
requires = ["maturin>=1.10,<2.0"]
|
|
@@ -36,5 +35,5 @@ dev = [
|
|
|
36
35
|
|
|
37
36
|
[tool.maturin]
|
|
38
37
|
python-source = "python"
|
|
39
|
-
module-name = "
|
|
38
|
+
module-name = "betaquant.algo._algo"
|
|
40
39
|
features = ["pyo3/extension-module"]
|
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
"""
|
|
5
5
|
Generic ExecContext for alpha factor computation.
|
|
6
6
|
|
|
7
|
-
命名约定:与底层 ``
|
|
7
|
+
命名约定:与底层 ``betaquant.*`` 函数名一一对应的 lower_snake_case:
|
|
8
8
|
|
|
9
9
|
- ts_xxx(x, d) — time-series / rolling window operators
|
|
10
10
|
- cc_xxx(x) — cross-sectional operators (across groups)
|
|
11
11
|
- 元素级 — max / min / abs / sign / log / signedpower / ...
|
|
12
12
|
|
|
13
13
|
每个算子只有一个名字(无别名)。DSL 表达式(alpha101.txt / alpha191.txt)也使用同一套
|
|
14
|
-
名字;转译器 `python -m
|
|
14
|
+
名字;转译器 `python -m betaquant.lang ...` 直接生成 `ctx.<name>(...)`,没有任何重映射。
|
|
15
15
|
|
|
16
16
|
特别提醒:
|
|
17
17
|
- ``ts_corr2(a, b, d)`` —— 两序列的滚动皮尔逊相关。
|
|
@@ -19,13 +19,13 @@ Generic ExecContext for alpha factor computation.
|
|
|
19
19
|
两者底层是不同函数,名字也不一样,不要混。
|
|
20
20
|
|
|
21
21
|
Usage:
|
|
22
|
-
import
|
|
23
|
-
from
|
|
22
|
+
import betaquant
|
|
23
|
+
from betaquant.context import ExecContext
|
|
24
24
|
|
|
25
25
|
data = pl.read_csv("data.csv").sort(["securityid", "tradetime"])
|
|
26
26
|
ctx = ExecContext(data)
|
|
27
27
|
# securities/trades auto-inferred from securityid/tradetime columns
|
|
28
|
-
#
|
|
28
|
+
# betaquant.set_ctx(groups=...) called automatically
|
|
29
29
|
"""
|
|
30
30
|
|
|
31
31
|
import logging
|
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
API:
|
|
7
7
|
- ``compute_forward_return(ctx, delay=1, periods=5)``
|
|
8
8
|
返回 ``(securities*trades,)`` 扁平数组,位置 t 处为 t+delay 日 open 进、
|
|
9
|
-
t+delay+periods-1 日 close 出的持仓回报。底层走 ``
|
|
9
|
+
t+delay+periods-1 日 close 出的持仓回报。底层走 ``betaquant.ts_fret``。
|
|
10
10
|
默认 periods=5(5 日 IC / 5 日持仓是国内卖方研究最常见的口径)。
|
|
11
11
|
- ``compute_factor_stats(factor, fwd_ret, securities, trades, top_pct=0.1, holding_periods=5)``
|
|
12
12
|
返回 dict:``ic / ir`` 加多头/空头/多空三腿的
|
|
13
13
|
``{long,short,ls}_{cum_ret,ann_ret,sharpe,mdd}``。
|
|
14
|
-
多/空腿用 top_pct 分位等权;夏普走 ``
|
|
14
|
+
多/空腿用 top_pct 分位等权;夏普走 ``betaquant.ts_sharpe``,回撤走 ``betaquant.ts_max_drawdown``。
|
|
15
15
|
|
|
16
16
|
数据布局约定(与 ExecContext 一致):
|
|
17
17
|
扁平数组按 ``[s1_t1..tT, s2_t1..tT, ...]`` 排列,``reshape(securities, trades).T``
|
|
@@ -107,8 +107,8 @@ def compute_factor_stats(
|
|
|
107
107
|
- 收益指标用**算术口径**(alphalens 标准),对极端日收益鲁棒:
|
|
108
108
|
``cum_ret = sum(r)``
|
|
109
109
|
``ann_ret = mean(r) * periods_per_year``
|
|
110
|
-
``mdd`` = 在 ``1 + cumsum(r)`` 上调 ``
|
|
111
|
-
- 夏普走 ``
|
|
110
|
+
``mdd`` = 在 ``1 + cumsum(r)`` 上调 ``betaquant.ts_max_drawdown`` 的末值
|
|
111
|
+
- 夏普走 ``betaquant.ts_sharpe``(总体标准差),再乘 ``sqrt(periods_per_year)`` 年化。
|
|
112
112
|
"""
|
|
113
113
|
f_panel = pd.DataFrame(factor.reshape(securities, trades).T)
|
|
114
114
|
r_panel = pd.DataFrame(fwd_ret.reshape(securities, trades).T)
|
|
@@ -7,7 +7,7 @@ from lark import Lark
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
_ROOT = Path(__file__).resolve().parents[2]
|
|
10
|
-
_GRAMMAR = _ROOT / "python" / "
|
|
10
|
+
_GRAMMAR = _ROOT / "python" / "betaquant" / "lang" / "alpha.lark"
|
|
11
11
|
_ALPHA101 = _ROOT / "examples" / "wq101" / "alpha101.txt"
|
|
12
12
|
|
|
13
13
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# Copyright 2026 MSD-RS Project LiJia
|
|
2
2
|
# SPDX-License-Identifier: BSD-2-Clause
|
|
3
3
|
|
|
4
|
-
"""``
|
|
4
|
+
"""``betaquant.cc_rank`` 与 pandas ``Series.rank(pct=True)`` 的一致性回归。"""
|
|
5
5
|
|
|
6
6
|
import numpy as np
|
|
7
7
|
|
|
8
|
-
import
|
|
8
|
+
import betaquant
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def test_cc_rank_matches_pandas_pct_rank():
|
|
@@ -15,8 +15,8 @@ def test_cc_rank_matches_pandas_pct_rank():
|
|
|
15
15
|
total = groups * rows_per_group
|
|
16
16
|
data = rng.random(total).astype(np.float64)
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
got =
|
|
18
|
+
betaquant.set_ctx(groups=groups)
|
|
19
|
+
got = betaquant.cc_rank(data)
|
|
20
20
|
|
|
21
21
|
# 等价计算:把数据 reshape 成 (groups, rows_per_group),
|
|
22
22
|
# 沿 axis=0 在每个时间步上做 pct rank(average 平均),
|
|
@@ -47,9 +47,9 @@ def test_cc_rank_matches_pandas_pct_rank():
|
|
|
47
47
|
|
|
48
48
|
|
|
49
49
|
def test_cc_rank_with_nan():
|
|
50
|
-
|
|
50
|
+
betaquant.set_ctx(groups=4)
|
|
51
51
|
data = np.array([1.0, 2.0, np.nan, 4.0], dtype=np.float64)
|
|
52
|
-
got =
|
|
52
|
+
got = betaquant.cc_rank(data)
|
|
53
53
|
# NaN -> NaN;其余按比例排名(3 个有效值)
|
|
54
54
|
assert np.isnan(got[2])
|
|
55
55
|
np.testing.assert_allclose(got[[0, 1, 3]], np.array([1, 2, 3]) / 3.0)
|
|
@@ -9,25 +9,25 @@ description: 在 alpha-lib 中添加新算子的标准流程。
|
|
|
9
9
|
|
|
10
10
|
- **底层 Rust 算子**:手写,函数名带 `ta_ts_*` / `ta_cc_*` 前缀。
|
|
11
11
|
- **顶层 Python 包装**:`build.rs` 在 `cargo build` 阶段自动生成(写入
|
|
12
|
-
`python/
|
|
12
|
+
`python/betaquant/algo/algo_gen.py` 与 `python/betaquant/algo.md`),名字为
|
|
13
13
|
`ts_*` / `cc_*`,无需手写。
|
|
14
14
|
|
|
15
15
|
只要写好 Rust 函数 + 文档注释 + 单元测试,跑一次 `cargo build` 就能在
|
|
16
|
-
Python 端用上 `
|
|
16
|
+
Python 端用上 `betaquant.ts_xxx(...)`。
|
|
17
17
|
|
|
18
18
|
## 命名规范
|
|
19
19
|
|
|
20
20
|
- **时序算子**(rolling-window,输入与输出长度一致):
|
|
21
|
-
Rust 函数名 `ta_ts_<name>`,Python 端为 `
|
|
21
|
+
Rust 函数名 `ta_ts_<name>`,Python 端为 `betaquant.ts_<name>` 与
|
|
22
22
|
`ctx.ts_<name>`。
|
|
23
23
|
- **截面算子**(cross-sectional,跨 group 维度):
|
|
24
|
-
Rust 函数名 `ta_cc_<name>`,Python 端为 `
|
|
24
|
+
Rust 函数名 `ta_cc_<name>`,Python 端为 `betaquant.cc_<name>` 与
|
|
25
25
|
`ctx.cc_<name>`。
|
|
26
26
|
- **元素级算子**(如 `max` / `min` / `abs` / `log` / `sign`):
|
|
27
|
-
无前缀,通常已经在 `python/
|
|
27
|
+
无前缀,通常已经在 `python/betaquant/context.py` 内用 numpy 实现。
|
|
28
28
|
|
|
29
29
|
`<name>` 用 `lower_snake_case`,例:`ta_ts_decay_linear` 对应
|
|
30
|
-
`
|
|
30
|
+
`betaquant.ts_decay_linear` 与 `ctx.ts_decay_linear`。
|
|
31
31
|
|
|
32
32
|
## 上下文 (Context) 与 flags
|
|
33
33
|
|
|
@@ -168,7 +168,7 @@ fn requires_full_window(&self) -> bool { true }
|
|
|
168
168
|
## 文档注释(用于自动生成 algo.md)
|
|
169
169
|
|
|
170
170
|
`build.rs::build_algo_md` 会把 `pub fn ta_*` **正上方** 的连续 `///`
|
|
171
|
-
文档注释抓出来生成 `python/
|
|
171
|
+
文档注释抓出来生成 `python/betaquant/algo.md`。
|
|
172
172
|
|
|
173
173
|
写注释的硬性要求:
|
|
174
174
|
|
|
@@ -213,7 +213,7 @@ pub fn ta_ts_stddev<NumT: Float + Send + Sync>(
|
|
|
213
213
|
1. **算子名与 DSL 关键字一致**:DSL 名直接 lower-case 后能匹配 `ts_<name>` /
|
|
214
214
|
`cc_<name>`,不用动 `to_python.py`。
|
|
215
215
|
2. **算子在 DSL 里有别名**(例如 `RANK` → `cc_rank`、`CORR` → `ts_correlation`、
|
|
216
|
-
`DECAYLINEAR` → `ts_decay_linear`):在 `python/
|
|
216
|
+
`DECAYLINEAR` → `ts_decay_linear`):在 `python/betaquant/lang/to_python.py`
|
|
217
217
|
的 `_OP_ALIASES` 字典里加一行 `"<dsl_name_lower>": "<exec_method_name>"`。
|
|
218
218
|
|
|
219
219
|
DSL 字段(变量)名仍是 `OPEN`、`CLOSE`、`HIGH`、`LOW`、`VOLUME`、`VWAP`、
|
|
@@ -221,11 +221,11 @@ DSL 字段(变量)名仍是 `OPEN`、`CLOSE`、`HIGH`、`LOW`、`VOLUME`、`
|
|
|
221
221
|
|
|
222
222
|
## ExecContext 入口(按需添加)
|
|
223
223
|
|
|
224
|
-
`python/
|
|
224
|
+
`python/betaquant/context.py` 里给每个新增算子加一个薄包装即可:
|
|
225
225
|
|
|
226
226
|
```python
|
|
227
227
|
def ts_<name>(self, a: np.ndarray, w: int) -> np.ndarray:
|
|
228
|
-
return
|
|
228
|
+
return betaquant.ts_<name>(a, int(w))
|
|
229
229
|
```
|
|
230
230
|
|
|
231
231
|
## 流程清单
|
|
@@ -235,11 +235,11 @@ def ts_<name>(self, a: np.ndarray, w: int) -> np.ndarray:
|
|
|
235
235
|
2. 在同文件末尾的 `mod tests` 加单测覆盖默认 / strict / skip-nan / 边界值。
|
|
236
236
|
3. 滑窗算子在 `src/algo/spec.rs` 加 `spec_ts_<name>` 测试。
|
|
237
237
|
4. `cargo test --lib` 全过。
|
|
238
|
-
5. `cargo build --lib` —— 自动重新生成 `python/
|
|
239
|
-
`python/
|
|
240
|
-
6. 如果 DSL 转译要支持新名字,在 `python/
|
|
238
|
+
5. `cargo build --lib` —— 自动重新生成 `python/betaquant/algo/algo_gen.py` 与
|
|
239
|
+
`python/betaquant/algo.md`,确认新算子出现在两个文件中。
|
|
240
|
+
6. 如果 DSL 转译要支持新名字,在 `python/betaquant/lang/to_python.py::_OP_ALIASES`
|
|
241
241
|
加映射。
|
|
242
|
-
7. 在 `python/
|
|
242
|
+
7. 在 `python/betaquant/context.py` 加 `ctx.ts_<name>` / `ctx.cc_<name>`
|
|
243
243
|
包装方法。
|
|
244
244
|
8. (可选)在 `examples/` 里加用例或重新生成 `alpha101.py` / `alpha191.py`:
|
|
245
245
|
```bash
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
from betalib.context import ExecContext # noqa: F401
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|