expr-codegen 0.6.4__tar.gz → 0.7.0__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.
Files changed (28) hide show
  1. {expr_codegen-0.6.4 → expr_codegen-0.7.0}/PKG-INFO +66 -44
  2. {expr_codegen-0.6.4 → expr_codegen-0.7.0}/README.md +65 -43
  3. expr_codegen-0.7.0/expr_codegen/_version.py +1 -0
  4. {expr_codegen-0.6.4 → expr_codegen-0.7.0}/expr_codegen/codes.py +12 -1
  5. {expr_codegen-0.6.4 → expr_codegen-0.7.0}/expr_codegen/expr.py +9 -0
  6. {expr_codegen-0.6.4 → expr_codegen-0.7.0}/expr_codegen/model.py +7 -5
  7. {expr_codegen-0.6.4 → expr_codegen-0.7.0}/expr_codegen/tool.py +23 -9
  8. {expr_codegen-0.6.4 → expr_codegen-0.7.0}/expr_codegen.egg-info/PKG-INFO +66 -44
  9. expr_codegen-0.6.4/expr_codegen/_version.py +0 -1
  10. {expr_codegen-0.6.4 → expr_codegen-0.7.0}/LICENSE +0 -0
  11. {expr_codegen-0.6.4 → expr_codegen-0.7.0}/expr_codegen/__init__.py +0 -0
  12. {expr_codegen-0.6.4 → expr_codegen-0.7.0}/expr_codegen/dag.py +0 -0
  13. {expr_codegen-0.6.4 → expr_codegen-0.7.0}/expr_codegen/latex/__init__.py +0 -0
  14. {expr_codegen-0.6.4 → expr_codegen-0.7.0}/expr_codegen/latex/printer.py +0 -0
  15. {expr_codegen-0.6.4 → expr_codegen-0.7.0}/expr_codegen/pandas/__init__.py +0 -0
  16. {expr_codegen-0.6.4 → expr_codegen-0.7.0}/expr_codegen/pandas/code.py +0 -0
  17. {expr_codegen-0.6.4 → expr_codegen-0.7.0}/expr_codegen/pandas/printer.py +0 -0
  18. {expr_codegen-0.6.4 → expr_codegen-0.7.0}/expr_codegen/pandas/template.py.j2 +0 -0
  19. {expr_codegen-0.6.4 → expr_codegen-0.7.0}/expr_codegen/polars/__init__.py +0 -0
  20. {expr_codegen-0.6.4 → expr_codegen-0.7.0}/expr_codegen/polars/code.py +0 -0
  21. {expr_codegen-0.6.4 → expr_codegen-0.7.0}/expr_codegen/polars/printer.py +0 -0
  22. {expr_codegen-0.6.4 → expr_codegen-0.7.0}/expr_codegen/polars/template.py.j2 +0 -0
  23. {expr_codegen-0.6.4 → expr_codegen-0.7.0}/expr_codegen.egg-info/SOURCES.txt +0 -0
  24. {expr_codegen-0.6.4 → expr_codegen-0.7.0}/expr_codegen.egg-info/dependency_links.txt +0 -0
  25. {expr_codegen-0.6.4 → expr_codegen-0.7.0}/expr_codegen.egg-info/requires.txt +0 -0
  26. {expr_codegen-0.6.4 → expr_codegen-0.7.0}/expr_codegen.egg-info/top_level.txt +0 -0
  27. {expr_codegen-0.6.4 → expr_codegen-0.7.0}/pyproject.toml +0 -0
  28. {expr_codegen-0.6.4 → expr_codegen-0.7.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: expr_codegen
3
- Version: 0.6.4
3
+ Version: 0.7.0
4
4
  Summary: symbol expression to polars expression tool
5
5
  Author-email: wukan <wu-kan@163.com>
6
6
  License: BSD 3-Clause License
@@ -75,9 +75,48 @@ https://exprcodegen.streamlit.app
75
75
 
76
76
  更完整示例访问[alpha_examples](https://github.com/wukan1986/alpha_examples)
77
77
 
78
- ## 使用方法
78
+ ## 使用示例
79
79
 
80
- 运行`demo_cn.py`生成`output.py`,将此文件复制到其它项目中直接`import`使用即可。一般生成的文件不需要再修改。
80
+ ```python
81
+ import sys
82
+
83
+ # from polars_ta.prefix.talib import * # noqa
84
+ from polars_ta.prefix.cdl import * # noqa
85
+ from polars_ta.prefix.ta import * # noqa
86
+ from polars_ta.prefix.tdx import * # noqa
87
+ from polars_ta.prefix.wq import * # noqa
88
+
89
+ from expr_codegen.tool import codegen_exec
90
+
91
+
92
+ def _code_block_():
93
+ # 因子编辑区,可利用IDE的智能提示在此区域编辑因子
94
+
95
+ # 模板中已经默认导入了from polars_ta.prefix下大量的算子,但
96
+ # talib在模板中没有默认导入。这种写法可实现在生成的代码中导入
97
+ from polars_ta.prefix.talib import ts_LINEARREG_SLOPE # noqa
98
+
99
+ # 1. 下划线开头的变量是中间变量,会被自动更名,最终输出时会被剔除
100
+ # 2. 下划线开头的变量可重复使用。多个复杂因子多行书写时有重复中间变时不再冲突
101
+ _avg = ts_mean(corr, 20)
102
+ _std = ts_std_dev(corr, 20)
103
+ _beta = ts_LINEARREG_SLOPE(corr, 20)
104
+
105
+ # 3. 下划线开头的变量支持有环循环赋值。在调试时可快速用注释进行切换
106
+ _avg = cs_mad_zscore_resid(_avg, LOG_MC_ZS, ONE)
107
+ _std = cs_mad_zscore_resid(_std, LOG_MC_ZS, ONE)
108
+ # _beta = cs_mad_zscore_resid(_beta, LOG_MC_ZS, ONE)
109
+
110
+ _corr = cs_zscore(_avg) + cs_zscore(_std)
111
+ CPV = cs_zscore(_corr) + cs_zscore(_beta)
112
+
113
+
114
+ df = None # 替换成真实的polars数据
115
+ df = codegen_exec(_code_block_, df, output_file=sys.stdout) # 打印代码
116
+ df = codegen_exec(_code_block_, df, output_file="output.py") # 保存到文件
117
+ df = codegen_exec(_code_block_, df) # 只执行,不保存代码
118
+
119
+ ```
81
120
 
82
121
  ## 目录结构
83
122
 
@@ -86,8 +125,7 @@ https://exprcodegen.streamlit.app
86
125
  ├─data
87
126
  │ prepare_date.py # 准备数据
88
127
  ├─examples
89
- alpha101.txt # WorldQuant Alpha101示例,可复制到`streamlit`应用
90
- │ demo_cn.py # 中文注释示例。演示如何将表达式转换成代码
128
+ demo_express.py # 速成示例。演示如何将表达式转换成代码
91
129
  │ demo_exec_pl.py # 演示调用转换后代码并绘图
92
130
  │ demo_transformer.py # 演示将第三方表达式转成内部表达式
93
131
  │ output.py # 结果输出。可不修改代码,直接被其它项目导入
@@ -144,7 +182,7 @@ https://exprcodegen.streamlit.app
144
182
 
145
183
  ## 二次开发
146
184
 
147
- 1. 备份后编辑`demo_cn.py`, `import`需要引入的函数
185
+ 1. 备份后编辑`demo_express.py`, `import`需要引入的函数
148
186
  2. 然后`printer.py`有可能需要添加对应函数的打印代码
149
187
  - 注意:需要留意是否要加括号`()`,不加时可能优先级混乱,可以每次都加括号,也可用提供的`parenthesize`简化处理
150
188
 
@@ -166,58 +204,42 @@ https://exprcodegen.streamlit.app
166
204
 
167
205
  以上三种问题本项目都使用`ast`进行了处理,可以简化使用
168
206
 
169
- ## 示例片段
207
+ ## 转译结果示例
170
208
 
171
- 需要转译的部分公式,详细代码请参考 [Demo](examples/demo_cn.py)
172
-
173
- ```python
174
- exprs_src = {
175
- "expr_1": -ts_corr(cs_rank(ts_mean(OPEN, 10)), cs_rank(ts_mean(CLOSE, 10)), 10),
176
- "expr_2": cs_rank(ts_mean(OPEN, 10)) - abs_(log(ts_mean(CLOSE, 10))) + gp_rank(sw_l1, CLOSE),
177
- "expr_3": ts_mean(cs_rank(ts_mean(OPEN, 10)), 10),
178
- "expr_4": cs_rank(ts_mean(cs_rank(OPEN), 10)),
179
- "expr_5": -ts_corr(OPEN, CLOSE, 10),
180
- }
181
- ```
182
-
183
- 转译后的代码片段,详细代码请参考[Polars版](codes)
209
+ 转译后的代码片段,详细代码请参考[Polars版](examples/output_polars.py)
184
210
 
185
211
  ```python
186
212
  def func_0_ts__asset(df: pl.DataFrame) -> pl.DataFrame:
187
- df = df.sort(by=[_DATE_])
188
- # ========================================
189
- df = df.with_columns(
190
- _x_0=1 / ts_delay(OPEN, -1),
191
- LABEL_CC_1=(-CLOSE + ts_delay(CLOSE, -1)) / CLOSE,
192
- )
193
- # ========================================
194
- df = df.with_columns(
195
- LABEL_OO_1=_x_0 * ts_delay(OPEN, -2) - 1,
196
- LABEL_OO_2=_x_0 * ts_delay(OPEN, -3) - 1,
197
- )
198
- return df
213
+ df = df.sort(by=[_DATE_])
214
+ # ========================================
215
+ df = df.with_columns(
216
+ _x_0=1 / ts_delay(OPEN, -1),
217
+ LABEL_CC_1=(-CLOSE + ts_delay(CLOSE, -1)) / CLOSE,
218
+ )
219
+ # ========================================
220
+ df = df.with_columns(
221
+ LABEL_OO_1=_x_0 * ts_delay(OPEN, -2) - 1,
222
+ LABEL_OO_2=_x_0 * ts_delay(OPEN, -3) - 1,
223
+ )
224
+ return df
199
225
  ```
200
226
 
201
227
  转译后的代码片段,详细代码请参考[Pandas版](examples/output_pandas.py)
202
228
 
203
229
  ```python
204
230
  def func_2_cs__date(df: pd.DataFrame) -> pd.DataFrame:
205
- # expr_4 = cs_rank(x_7)
206
- df["expr_4"] = (df["x_7"]).rank(pct=True)
207
- return df
231
+ # expr_4 = cs_rank(x_7)
232
+ df["expr_4"] = (df["x_7"]).rank(pct=True)
233
+ return df
208
234
 
209
235
 
210
236
  def func_3_ts__asset__date(df: pd.DataFrame) -> pd.DataFrame:
211
- # expr_5 = -ts_corr(OPEN, CLOSE, 10)
212
- df["expr_5"] = -(df["OPEN"]).rolling(10).corr(df["CLOSE"])
213
- # expr_6 = ts_delta(OPEN, 10)
214
- df["expr_6"] = df["OPEN"].diff(10)
215
- return df
216
-
237
+ # expr_5 = -ts_corr(OPEN, CLOSE, 10)
238
+ df["expr_5"] = -(df["OPEN"]).rolling(10).corr(df["CLOSE"])
239
+ # expr_6 = ts_delta(OPEN, 10)
240
+ df["expr_6"] = df["OPEN"].diff(10)
241
+ return df
217
242
 
218
- df = df.sort_values(by=["asset", "date"]).groupby(by=["asset"], group_keys=False).apply(func_0_ts__asset__date)
219
- df = df.groupby(by=["date"], group_keys=False).apply(func_0_cs__date)
220
- df = func_0_cl(df)
221
243
  ```
222
244
 
223
245
  ## 本地部署交互网页
@@ -25,9 +25,48 @@ https://exprcodegen.streamlit.app
25
25
 
26
26
  更完整示例访问[alpha_examples](https://github.com/wukan1986/alpha_examples)
27
27
 
28
- ## 使用方法
28
+ ## 使用示例
29
29
 
30
- 运行`demo_cn.py`生成`output.py`,将此文件复制到其它项目中直接`import`使用即可。一般生成的文件不需要再修改。
30
+ ```python
31
+ import sys
32
+
33
+ # from polars_ta.prefix.talib import * # noqa
34
+ from polars_ta.prefix.cdl import * # noqa
35
+ from polars_ta.prefix.ta import * # noqa
36
+ from polars_ta.prefix.tdx import * # noqa
37
+ from polars_ta.prefix.wq import * # noqa
38
+
39
+ from expr_codegen.tool import codegen_exec
40
+
41
+
42
+ def _code_block_():
43
+ # 因子编辑区,可利用IDE的智能提示在此区域编辑因子
44
+
45
+ # 模板中已经默认导入了from polars_ta.prefix下大量的算子,但
46
+ # talib在模板中没有默认导入。这种写法可实现在生成的代码中导入
47
+ from polars_ta.prefix.talib import ts_LINEARREG_SLOPE # noqa
48
+
49
+ # 1. 下划线开头的变量是中间变量,会被自动更名,最终输出时会被剔除
50
+ # 2. 下划线开头的变量可重复使用。多个复杂因子多行书写时有重复中间变时不再冲突
51
+ _avg = ts_mean(corr, 20)
52
+ _std = ts_std_dev(corr, 20)
53
+ _beta = ts_LINEARREG_SLOPE(corr, 20)
54
+
55
+ # 3. 下划线开头的变量支持有环循环赋值。在调试时可快速用注释进行切换
56
+ _avg = cs_mad_zscore_resid(_avg, LOG_MC_ZS, ONE)
57
+ _std = cs_mad_zscore_resid(_std, LOG_MC_ZS, ONE)
58
+ # _beta = cs_mad_zscore_resid(_beta, LOG_MC_ZS, ONE)
59
+
60
+ _corr = cs_zscore(_avg) + cs_zscore(_std)
61
+ CPV = cs_zscore(_corr) + cs_zscore(_beta)
62
+
63
+
64
+ df = None # 替换成真实的polars数据
65
+ df = codegen_exec(_code_block_, df, output_file=sys.stdout) # 打印代码
66
+ df = codegen_exec(_code_block_, df, output_file="output.py") # 保存到文件
67
+ df = codegen_exec(_code_block_, df) # 只执行,不保存代码
68
+
69
+ ```
31
70
 
32
71
  ## 目录结构
33
72
 
@@ -36,8 +75,7 @@ https://exprcodegen.streamlit.app
36
75
  ├─data
37
76
  │ prepare_date.py # 准备数据
38
77
  ├─examples
39
- alpha101.txt # WorldQuant Alpha101示例,可复制到`streamlit`应用
40
- │ demo_cn.py # 中文注释示例。演示如何将表达式转换成代码
78
+ demo_express.py # 速成示例。演示如何将表达式转换成代码
41
79
  │ demo_exec_pl.py # 演示调用转换后代码并绘图
42
80
  │ demo_transformer.py # 演示将第三方表达式转成内部表达式
43
81
  │ output.py # 结果输出。可不修改代码,直接被其它项目导入
@@ -94,7 +132,7 @@ https://exprcodegen.streamlit.app
94
132
 
95
133
  ## 二次开发
96
134
 
97
- 1. 备份后编辑`demo_cn.py`, `import`需要引入的函数
135
+ 1. 备份后编辑`demo_express.py`, `import`需要引入的函数
98
136
  2. 然后`printer.py`有可能需要添加对应函数的打印代码
99
137
  - 注意:需要留意是否要加括号`()`,不加时可能优先级混乱,可以每次都加括号,也可用提供的`parenthesize`简化处理
100
138
 
@@ -116,58 +154,42 @@ https://exprcodegen.streamlit.app
116
154
 
117
155
  以上三种问题本项目都使用`ast`进行了处理,可以简化使用
118
156
 
119
- ## 示例片段
157
+ ## 转译结果示例
120
158
 
121
- 需要转译的部分公式,详细代码请参考 [Demo](examples/demo_cn.py)
122
-
123
- ```python
124
- exprs_src = {
125
- "expr_1": -ts_corr(cs_rank(ts_mean(OPEN, 10)), cs_rank(ts_mean(CLOSE, 10)), 10),
126
- "expr_2": cs_rank(ts_mean(OPEN, 10)) - abs_(log(ts_mean(CLOSE, 10))) + gp_rank(sw_l1, CLOSE),
127
- "expr_3": ts_mean(cs_rank(ts_mean(OPEN, 10)), 10),
128
- "expr_4": cs_rank(ts_mean(cs_rank(OPEN), 10)),
129
- "expr_5": -ts_corr(OPEN, CLOSE, 10),
130
- }
131
- ```
132
-
133
- 转译后的代码片段,详细代码请参考[Polars版](codes)
159
+ 转译后的代码片段,详细代码请参考[Polars版](examples/output_polars.py)
134
160
 
135
161
  ```python
136
162
  def func_0_ts__asset(df: pl.DataFrame) -> pl.DataFrame:
137
- df = df.sort(by=[_DATE_])
138
- # ========================================
139
- df = df.with_columns(
140
- _x_0=1 / ts_delay(OPEN, -1),
141
- LABEL_CC_1=(-CLOSE + ts_delay(CLOSE, -1)) / CLOSE,
142
- )
143
- # ========================================
144
- df = df.with_columns(
145
- LABEL_OO_1=_x_0 * ts_delay(OPEN, -2) - 1,
146
- LABEL_OO_2=_x_0 * ts_delay(OPEN, -3) - 1,
147
- )
148
- return df
163
+ df = df.sort(by=[_DATE_])
164
+ # ========================================
165
+ df = df.with_columns(
166
+ _x_0=1 / ts_delay(OPEN, -1),
167
+ LABEL_CC_1=(-CLOSE + ts_delay(CLOSE, -1)) / CLOSE,
168
+ )
169
+ # ========================================
170
+ df = df.with_columns(
171
+ LABEL_OO_1=_x_0 * ts_delay(OPEN, -2) - 1,
172
+ LABEL_OO_2=_x_0 * ts_delay(OPEN, -3) - 1,
173
+ )
174
+ return df
149
175
  ```
150
176
 
151
177
  转译后的代码片段,详细代码请参考[Pandas版](examples/output_pandas.py)
152
178
 
153
179
  ```python
154
180
  def func_2_cs__date(df: pd.DataFrame) -> pd.DataFrame:
155
- # expr_4 = cs_rank(x_7)
156
- df["expr_4"] = (df["x_7"]).rank(pct=True)
157
- return df
181
+ # expr_4 = cs_rank(x_7)
182
+ df["expr_4"] = (df["x_7"]).rank(pct=True)
183
+ return df
158
184
 
159
185
 
160
186
  def func_3_ts__asset__date(df: pd.DataFrame) -> pd.DataFrame:
161
- # expr_5 = -ts_corr(OPEN, CLOSE, 10)
162
- df["expr_5"] = -(df["OPEN"]).rolling(10).corr(df["CLOSE"])
163
- # expr_6 = ts_delta(OPEN, 10)
164
- df["expr_6"] = df["OPEN"].diff(10)
165
- return df
166
-
187
+ # expr_5 = -ts_corr(OPEN, CLOSE, 10)
188
+ df["expr_5"] = -(df["OPEN"]).rolling(10).corr(df["CLOSE"])
189
+ # expr_6 = ts_delta(OPEN, 10)
190
+ df["expr_6"] = df["OPEN"].diff(10)
191
+ return df
167
192
 
168
- df = df.sort_values(by=["asset", "date"]).groupby(by=["asset"], group_keys=False).apply(func_0_ts__asset__date)
169
- df = df.groupby(by=["date"], group_keys=False).apply(func_0_cs__date)
170
- df = func_0_cl(df)
171
193
  ```
172
194
 
173
195
  ## 本地部署交互网页
@@ -0,0 +1 @@
1
+ __version__ = "0.7.0"
@@ -51,7 +51,8 @@ class SympyTransformer(ast.NodeTransformer):
51
51
 
52
52
  # 赋值给下划线开头代码时,对其进行重命名,方便重复书写表达式时不冲突
53
53
  if old_target_id.startswith('_'):
54
- new_target_id = f'{old_target_id}_{len(self.targets_new):03d}'
54
+ # 减少与cse中_x_冲突
55
+ new_target_id = f'{old_target_id}_{len(self.targets_new)}_'
55
56
 
56
57
  if old_target_id != new_target_id:
57
58
  self.targets_new.add(new_target_id)
@@ -149,6 +150,16 @@ class SympyTransformer(ast.NodeTransformer):
149
150
  self.generic_visit(node)
150
151
  return node
151
152
 
153
+ def visit_UnaryOp(self, node):
154
+ # -x
155
+ if isinstance(node.operand, ast.Name):
156
+ self.args_old.add(node.operand.id)
157
+ node.operand.id = self.args_map.get(node.operand.id, node.operand.id)
158
+ self.args_new.add(node.operand.id)
159
+
160
+ self.generic_visit(node)
161
+ return node
162
+
152
163
 
153
164
  def sources_to_asts(*sources):
154
165
  """输入多份源代码"""
@@ -132,6 +132,15 @@ def is_NegativeX(expr):
132
132
  return False
133
133
 
134
134
 
135
+ def is_simple_expr(expr):
136
+ if isinstance(expr, Mul):
137
+ if expr.args[0] == -1 and len(expr.args) == 2 and expr.args[1].is_Atom:
138
+ return True
139
+ if isinstance(expr, Symbol):
140
+ return True
141
+ return False
142
+
143
+
135
144
  def get_current_by_prefix(expr, **kwargs):
136
145
  """表达式根节点信息。按名称前缀。例如
137
146
 
@@ -5,7 +5,7 @@ import networkx as nx
5
5
  from sympy import symbols
6
6
 
7
7
  from expr_codegen.dag import zero_indegree, hierarchy_pos, remove_paths_by_zero_outdegree
8
- from expr_codegen.expr import CL, get_symbols, get_children, get_key, is_NegativeX
8
+ from expr_codegen.expr import CL, get_symbols, get_children, get_key, is_NegativeX, is_simple_expr
9
9
 
10
10
 
11
11
  class ListDictList:
@@ -214,7 +214,7 @@ def merge_nodes_1(G: nx.DiGraph, keep_nodes, *args):
214
214
  expr = dic['expr']
215
215
  symbols = dic['symbols']
216
216
  if key[0] == CL:
217
- if is_NegativeX(expr):
217
+ if is_simple_expr(expr):
218
218
  # 检查表达式是否很简单, 是就替换,可能会替换多个
219
219
  skip_expr_node(G, node, keep_nodes)
220
220
  else:
@@ -253,7 +253,7 @@ def merge_nodes_2(G: nx.DiGraph, keep_nodes, *args):
253
253
  for node in this_pred:
254
254
  dic = G.nodes[node]
255
255
  expr = dic['expr']
256
- if not is_NegativeX(expr):
256
+ if not is_simple_expr(expr):
257
257
  continue
258
258
  pred = G.pred[node]
259
259
  for p in pred.copy():
@@ -337,8 +337,10 @@ def dag_start(exprs_dict, func, func_kwargs):
337
337
  def dag_middle(G, exprs_names, func, func_kwargs):
338
338
  """删除几个没有必要的节点"""
339
339
  G = remove_paths_by_zero_outdegree(G, exprs_names)
340
- G = merge_nodes_1(G, exprs_names, *exprs_names)
341
- G = merge_nodes_2(G, exprs_names, *exprs_names)
340
+ # 以下划线开头的节点,不保留
341
+ keep_nodes = [k for k in exprs_names if not k.startswith('_')]
342
+ G = merge_nodes_1(G, keep_nodes, *keep_nodes)
343
+ G = merge_nodes_2(G, keep_nodes, *keep_nodes)
342
344
 
343
345
  # 由于表达式修改,需再次更新表达式
344
346
  G = init_dag_exprs(G, func, func_kwargs)
@@ -1,5 +1,6 @@
1
1
  import inspect
2
2
  from functools import lru_cache
3
+ from io import TextIOWrapper
3
4
  from typing import Sequence, Dict, Optional
4
5
 
5
6
  from black import Mode, format_str
@@ -223,21 +224,24 @@ class ExprTool:
223
224
  return globals_['df_output']
224
225
 
225
226
  @lru_cache(maxsize=64)
226
- def _get_codes(self, source: str, extra_codes: str, output_file: str) -> str:
227
+ def _get_codes(self, source: str, extra_codes: str, output_file: str,
228
+ style='polars', template_file='template.py.j2',
229
+ date='date', asset='asset') -> str:
227
230
  """通过字符串生成代码, 加了缓存,多次调用不重复生成"""
228
231
  raw, exprs_dict = sources_to_exprs(self.globals_, source, safe=False)
229
232
 
230
233
  # 生成代码
231
- codes, G = _TOOL_.all(exprs_dict, style='polars', template_file='template.py.j2',
234
+ codes, G = _TOOL_.all(exprs_dict, style=style, template_file=template_file,
232
235
  replace=True, regroup=True, format=True,
233
- date='date', asset='asset',
236
+ date=date, asset=asset,
234
237
  # 复制了需要使用的函数,还复制了最原始的表达式
235
238
  extra_codes=(raw,
236
239
  # 传入多个列的方法
237
240
  extra_codes,
238
241
  ))
239
-
240
- if output_file is not None:
242
+ if isinstance(output_file, TextIOWrapper):
243
+ output_file.write(codes)
244
+ elif output_file is not None:
241
245
  with open(output_file, 'w', encoding='utf-8') as f:
242
246
  f.write(codes)
243
247
 
@@ -247,9 +251,13 @@ class ExprTool:
247
251
  _TOOL_ = ExprTool()
248
252
 
249
253
 
250
- def codegen_exec(code_block, df_input,
254
+ def codegen_exec(code_block,
255
+ df_input,
251
256
  extra_codes: str = r'CS_SW_L1 = pl.col(r"^sw_l1_\d+$")',
252
- output_file: Optional[str] = None):
257
+ output_file: Optional[str] = None,
258
+ style: str = 'polars', template_file: str = 'template.py.j2',
259
+ date: str = 'date', asset: str = 'asset'
260
+ ):
253
261
  """快速转换源代码并执行"""
254
262
  # 此代码来自于sympy.var
255
263
  frame = inspect.currentframe().f_back
@@ -261,6 +269,12 @@ def codegen_exec(code_block, df_input,
261
269
  else:
262
270
  source = inspect.getsource(code_block)
263
271
 
264
- codes = _TOOL_._get_codes(source, extra_codes, output_file)
272
+ codes = _TOOL_._get_codes(source, extra_codes, output_file,
273
+ style=style, template_file=template_file,
274
+ date=date, asset=asset,
275
+ )
265
276
 
266
- return _TOOL_.exec(codes, df_input)
277
+ if df_input is None:
278
+ return df_input
279
+ else:
280
+ return _TOOL_.exec(codes, df_input)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: expr_codegen
3
- Version: 0.6.4
3
+ Version: 0.7.0
4
4
  Summary: symbol expression to polars expression tool
5
5
  Author-email: wukan <wu-kan@163.com>
6
6
  License: BSD 3-Clause License
@@ -75,9 +75,48 @@ https://exprcodegen.streamlit.app
75
75
 
76
76
  更完整示例访问[alpha_examples](https://github.com/wukan1986/alpha_examples)
77
77
 
78
- ## 使用方法
78
+ ## 使用示例
79
79
 
80
- 运行`demo_cn.py`生成`output.py`,将此文件复制到其它项目中直接`import`使用即可。一般生成的文件不需要再修改。
80
+ ```python
81
+ import sys
82
+
83
+ # from polars_ta.prefix.talib import * # noqa
84
+ from polars_ta.prefix.cdl import * # noqa
85
+ from polars_ta.prefix.ta import * # noqa
86
+ from polars_ta.prefix.tdx import * # noqa
87
+ from polars_ta.prefix.wq import * # noqa
88
+
89
+ from expr_codegen.tool import codegen_exec
90
+
91
+
92
+ def _code_block_():
93
+ # 因子编辑区,可利用IDE的智能提示在此区域编辑因子
94
+
95
+ # 模板中已经默认导入了from polars_ta.prefix下大量的算子,但
96
+ # talib在模板中没有默认导入。这种写法可实现在生成的代码中导入
97
+ from polars_ta.prefix.talib import ts_LINEARREG_SLOPE # noqa
98
+
99
+ # 1. 下划线开头的变量是中间变量,会被自动更名,最终输出时会被剔除
100
+ # 2. 下划线开头的变量可重复使用。多个复杂因子多行书写时有重复中间变时不再冲突
101
+ _avg = ts_mean(corr, 20)
102
+ _std = ts_std_dev(corr, 20)
103
+ _beta = ts_LINEARREG_SLOPE(corr, 20)
104
+
105
+ # 3. 下划线开头的变量支持有环循环赋值。在调试时可快速用注释进行切换
106
+ _avg = cs_mad_zscore_resid(_avg, LOG_MC_ZS, ONE)
107
+ _std = cs_mad_zscore_resid(_std, LOG_MC_ZS, ONE)
108
+ # _beta = cs_mad_zscore_resid(_beta, LOG_MC_ZS, ONE)
109
+
110
+ _corr = cs_zscore(_avg) + cs_zscore(_std)
111
+ CPV = cs_zscore(_corr) + cs_zscore(_beta)
112
+
113
+
114
+ df = None # 替换成真实的polars数据
115
+ df = codegen_exec(_code_block_, df, output_file=sys.stdout) # 打印代码
116
+ df = codegen_exec(_code_block_, df, output_file="output.py") # 保存到文件
117
+ df = codegen_exec(_code_block_, df) # 只执行,不保存代码
118
+
119
+ ```
81
120
 
82
121
  ## 目录结构
83
122
 
@@ -86,8 +125,7 @@ https://exprcodegen.streamlit.app
86
125
  ├─data
87
126
  │ prepare_date.py # 准备数据
88
127
  ├─examples
89
- alpha101.txt # WorldQuant Alpha101示例,可复制到`streamlit`应用
90
- │ demo_cn.py # 中文注释示例。演示如何将表达式转换成代码
128
+ demo_express.py # 速成示例。演示如何将表达式转换成代码
91
129
  │ demo_exec_pl.py # 演示调用转换后代码并绘图
92
130
  │ demo_transformer.py # 演示将第三方表达式转成内部表达式
93
131
  │ output.py # 结果输出。可不修改代码,直接被其它项目导入
@@ -144,7 +182,7 @@ https://exprcodegen.streamlit.app
144
182
 
145
183
  ## 二次开发
146
184
 
147
- 1. 备份后编辑`demo_cn.py`, `import`需要引入的函数
185
+ 1. 备份后编辑`demo_express.py`, `import`需要引入的函数
148
186
  2. 然后`printer.py`有可能需要添加对应函数的打印代码
149
187
  - 注意:需要留意是否要加括号`()`,不加时可能优先级混乱,可以每次都加括号,也可用提供的`parenthesize`简化处理
150
188
 
@@ -166,58 +204,42 @@ https://exprcodegen.streamlit.app
166
204
 
167
205
  以上三种问题本项目都使用`ast`进行了处理,可以简化使用
168
206
 
169
- ## 示例片段
207
+ ## 转译结果示例
170
208
 
171
- 需要转译的部分公式,详细代码请参考 [Demo](examples/demo_cn.py)
172
-
173
- ```python
174
- exprs_src = {
175
- "expr_1": -ts_corr(cs_rank(ts_mean(OPEN, 10)), cs_rank(ts_mean(CLOSE, 10)), 10),
176
- "expr_2": cs_rank(ts_mean(OPEN, 10)) - abs_(log(ts_mean(CLOSE, 10))) + gp_rank(sw_l1, CLOSE),
177
- "expr_3": ts_mean(cs_rank(ts_mean(OPEN, 10)), 10),
178
- "expr_4": cs_rank(ts_mean(cs_rank(OPEN), 10)),
179
- "expr_5": -ts_corr(OPEN, CLOSE, 10),
180
- }
181
- ```
182
-
183
- 转译后的代码片段,详细代码请参考[Polars版](codes)
209
+ 转译后的代码片段,详细代码请参考[Polars版](examples/output_polars.py)
184
210
 
185
211
  ```python
186
212
  def func_0_ts__asset(df: pl.DataFrame) -> pl.DataFrame:
187
- df = df.sort(by=[_DATE_])
188
- # ========================================
189
- df = df.with_columns(
190
- _x_0=1 / ts_delay(OPEN, -1),
191
- LABEL_CC_1=(-CLOSE + ts_delay(CLOSE, -1)) / CLOSE,
192
- )
193
- # ========================================
194
- df = df.with_columns(
195
- LABEL_OO_1=_x_0 * ts_delay(OPEN, -2) - 1,
196
- LABEL_OO_2=_x_0 * ts_delay(OPEN, -3) - 1,
197
- )
198
- return df
213
+ df = df.sort(by=[_DATE_])
214
+ # ========================================
215
+ df = df.with_columns(
216
+ _x_0=1 / ts_delay(OPEN, -1),
217
+ LABEL_CC_1=(-CLOSE + ts_delay(CLOSE, -1)) / CLOSE,
218
+ )
219
+ # ========================================
220
+ df = df.with_columns(
221
+ LABEL_OO_1=_x_0 * ts_delay(OPEN, -2) - 1,
222
+ LABEL_OO_2=_x_0 * ts_delay(OPEN, -3) - 1,
223
+ )
224
+ return df
199
225
  ```
200
226
 
201
227
  转译后的代码片段,详细代码请参考[Pandas版](examples/output_pandas.py)
202
228
 
203
229
  ```python
204
230
  def func_2_cs__date(df: pd.DataFrame) -> pd.DataFrame:
205
- # expr_4 = cs_rank(x_7)
206
- df["expr_4"] = (df["x_7"]).rank(pct=True)
207
- return df
231
+ # expr_4 = cs_rank(x_7)
232
+ df["expr_4"] = (df["x_7"]).rank(pct=True)
233
+ return df
208
234
 
209
235
 
210
236
  def func_3_ts__asset__date(df: pd.DataFrame) -> pd.DataFrame:
211
- # expr_5 = -ts_corr(OPEN, CLOSE, 10)
212
- df["expr_5"] = -(df["OPEN"]).rolling(10).corr(df["CLOSE"])
213
- # expr_6 = ts_delta(OPEN, 10)
214
- df["expr_6"] = df["OPEN"].diff(10)
215
- return df
216
-
237
+ # expr_5 = -ts_corr(OPEN, CLOSE, 10)
238
+ df["expr_5"] = -(df["OPEN"]).rolling(10).corr(df["CLOSE"])
239
+ # expr_6 = ts_delta(OPEN, 10)
240
+ df["expr_6"] = df["OPEN"].diff(10)
241
+ return df
217
242
 
218
- df = df.sort_values(by=["asset", "date"]).groupby(by=["asset"], group_keys=False).apply(func_0_ts__asset__date)
219
- df = df.groupby(by=["date"], group_keys=False).apply(func_0_cs__date)
220
- df = func_0_cl(df)
221
243
  ```
222
244
 
223
245
  ## 本地部署交互网页
@@ -1 +0,0 @@
1
- __version__ = "0.6.4"
File without changes
File without changes