cnhkmcp 2.3.3__py3-none-any.whl → 2.3.5__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.
- cnhkmcp/__init__.py +1 -1
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/main.py +7 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242//321/211/320/266/320/246/321/206/320/274/320/261/321/210/342/224/220/320/240/321/210/320/261/320/234/321/206/320/231/320/243/321/205/342/225/235/320/220/321/206/320/230/320/241.py +8 -0
- cnhkmcp/untracked/APP/Tranformer/validator.py +149 -32
- cnhkmcp/untracked/APP/ace_lib.py +8 -0
- cnhkmcp/untracked/APP/blueprints/parsetab.py +60 -0
- cnhkmcp/untracked/APP/blueprints/validator.py +1080 -0
- cnhkmcp/untracked/APP/requirements.txt +0 -0
- cnhkmcp/untracked/APP/static/decoder.js +164 -38
- cnhkmcp/untracked/APP/static/simulator.js +15 -15
- cnhkmcp/untracked/APP/templates/feature_engineering.html +78 -78
- cnhkmcp/untracked/APP/templates/idea_house.html +49 -49
- cnhkmcp/untracked/APP/templates/index.html +58 -58
- cnhkmcp/untracked/APP/templates/inspiration_house.html +64 -64
- cnhkmcp/untracked/APP/templates/paper_analysis.html +21 -21
- cnhkmcp/untracked/APP/templates/simulator.html +38 -38
- cnhkmcp/untracked/APP/templates/transformer_web.html +24 -24
- cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-data-feature-engineering/SKILL.md +15 -15
- cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental28_GLB_delay1/fundamental28_GLB_1_idea_1769927658009727000.json +10 -0
- cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental28_GLB_delay1/fundamental28_GLB_1_idea_1769927658519220600.json +10 -0
- cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental28_GLB_delay1/fundamental28_GLB_1_idea_1769927659002708800.json +10 -0
- cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental28_GLB_delay1/fundamental28_GLB_1_idea_1769927659510920900.json +10 -0
- cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental28_GLB_delay1/fundamental28_GLB_1_idea_1769927659982673800.json +10 -0
- cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/scripts/validator.py +153 -32
- cnhkmcp/untracked/APP//321/210/342/224/220/320/240/321/210/320/261/320/234/321/206/320/231/320/243/321/205/342/225/235/320/220/321/206/320/230/320/241.py +54 -0
- cnhkmcp/untracked/arxiv_api.py +7 -0
- cnhkmcp/untracked/back_up/forum_functions.py +8 -0
- cnhkmcp/untracked/forum_functions.py +8 -0
- cnhkmcp/untracked/mcp/321/206/320/246/320/227/321/204/342/225/227/342/225/242/321/210/320/276/342/225/221/321/205/320/255/320/253/321/207/320/231/320/2302_/321/205/320/266/320/222/321/206/320/256/320/254/321/205/320/236/320/257/321/207/320/231/320/230/321/205/320/240/320/277/321/205/320/232/320/270/321/204/342/225/225/320/235/321/204/342/225/221/320/226/321/206/342/225/241/320/237/321/210/320/267/320/230/321/205/320/251/320/270/321/205/342/226/221/342/226/222/321/210/320/277/320/245/321/210/342/224/220/320/251/321/204/342/225/225/320/272/forum_functions.py +8 -0
- cnhkmcp/untracked/mcp/321/206/320/246/320/227/321/204/342/225/227/342/225/242/321/210/320/276/342/225/221/321/205/320/255/320/253/321/207/320/231/320/2302_/321/205/320/266/320/222/321/206/320/256/320/254/321/205/320/236/320/257/321/207/320/231/320/230/321/205/320/240/320/277/321/205/320/232/320/270/321/204/342/225/225/320/235/321/204/342/225/221/320/226/321/206/342/225/241/320/237/321/210/320/267/320/230/321/205/320/251/320/270/321/205/342/226/221/342/226/222/321/210/320/277/320/245/321/210/342/224/220/320/251/321/204/342/225/225/320/272/platform_functions.py +8 -1
- cnhkmcp/untracked/platform_functions.py +7 -0
- cnhkmcp/untracked/skills/alpha-expression-verifier/scripts/validator.py +149 -32
- cnhkmcp/untracked/skills/{brain-inspectTemplate-create-Setting → brain-inspectRawTemplate-create-Setting}/SKILL.md +8 -2
- cnhkmcp/untracked/skills/brain-inspectRawTemplate-create-Setting/ace.log +0 -0
- cnhkmcp/untracked/skills/brain-inspectRawTemplate-create-Setting/idea_context.json +15 -0
- cnhkmcp/untracked/skills/brain-inspectRawTemplate-create-Setting/scripts/__init__.py +0 -0
- cnhkmcp/untracked/skills/{brain-inspectTemplate-create-Setting → brain-inspectRawTemplate-create-Setting}/scripts/parse_idea_file.py +33 -1
- cnhkmcp/untracked/skills/brain-inspectRawTemplate-create-Setting/scripts/parsetab.py +60 -0
- cnhkmcp/untracked/skills/brain-inspectRawTemplate-create-Setting/scripts/validator.py +1086 -0
- cnhkmcp/untracked//321/211/320/225/320/235/321/207/342/225/234/320/276/321/205/320/231/320/235/321/210/342/224/220/320/240/321/210/320/261/320/234/321/206/320/230/320/241_/321/205/320/276/320/231/321/210/320/263/320/225/321/205/342/224/220/320/225/321/210/320/266/320/221/321/204/342/225/233/320/255/321/210/342/225/241/320/246/321/205/320/234/320/225.py +8 -0
- {cnhkmcp-2.3.3.dist-info → cnhkmcp-2.3.5.dist-info}/METADATA +1 -1
- {cnhkmcp-2.3.3.dist-info → cnhkmcp-2.3.5.dist-info}/RECORD +59 -47
- /cnhkmcp/untracked/{skills/brain-inspectTemplate-create-Setting → APP/hkSimulator}/ace.log +0 -0
- /cnhkmcp/untracked/{skills/brain-inspectTemplate-create-Setting/scripts/__init__.py → APP/hkSimulator/autosim_20260201_172428.log} +0 -0
- /cnhkmcp/untracked/skills/{brain-inspectTemplate-create-Setting → brain-inspectRawTemplate-create-Setting}/.gitignore +0 -0
- /cnhkmcp/untracked/skills/{brain-inspectTemplate-create-Setting → brain-inspectRawTemplate-create-Setting}/ace_lib.py +0 -0
- /cnhkmcp/untracked/skills/{brain-inspectTemplate-create-Setting → brain-inspectRawTemplate-create-Setting}/config.json +0 -0
- /cnhkmcp/untracked/skills/{brain-inspectTemplate-create-Setting → brain-inspectRawTemplate-create-Setting}/fundamental28_GLB_1_idea_1769874845978315000.json +0 -0
- /cnhkmcp/untracked/skills/{brain-inspectTemplate-create-Setting → brain-inspectRawTemplate-create-Setting}/helpful_functions.py +0 -0
- /cnhkmcp/untracked/skills/{brain-inspectTemplate-create-Setting → brain-inspectRawTemplate-create-Setting}/scripts/build_alpha_list.py +0 -0
- /cnhkmcp/untracked/skills/{brain-inspectTemplate-create-Setting → brain-inspectRawTemplate-create-Setting}/scripts/fetch_sim_options.py +0 -0
- /cnhkmcp/untracked/skills/{brain-inspectTemplate-create-Setting → brain-inspectRawTemplate-create-Setting}/scripts/load_credentials.py +0 -0
- /cnhkmcp/untracked/skills/{brain-inspectTemplate-create-Setting → brain-inspectRawTemplate-create-Setting}/scripts/process_template.py +0 -0
- /cnhkmcp/untracked/skills/{brain-inspectTemplate-create-Setting → brain-inspectRawTemplate-create-Setting}/scripts/resolve_settings.py +0 -0
- /cnhkmcp/untracked/skills/{brain-inspectTemplate-create-Setting → brain-inspectRawTemplate-create-Setting}/sim_options_snapshot.json +0 -0
- {cnhkmcp-2.3.3.dist-info → cnhkmcp-2.3.5.dist-info}/WHEEL +0 -0
- {cnhkmcp-2.3.3.dist-info → cnhkmcp-2.3.5.dist-info}/entry_points.txt +0 -0
- {cnhkmcp-2.3.3.dist-info → cnhkmcp-2.3.5.dist-info}/licenses/LICENSE +0 -0
- {cnhkmcp-2.3.3.dist-info → cnhkmcp-2.3.5.dist-info}/top_level.txt +0 -0
cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/scripts/validator.py
CHANGED
|
@@ -65,51 +65,65 @@ supported_functions = {
|
|
|
65
65
|
'ts_delay': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
66
66
|
'ts_corr': {'min_args': 3, 'max_args': 3, 'arg_types': ['expression', 'expression', 'number']},
|
|
67
67
|
'ts_zscore': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
68
|
-
'ts_returns': {'min_args': 2, 'max_args': 3, 'arg_types': ['expression', 'number', 'number'], 'param_names': ['x', 'd', 'mode']},
|
|
68
|
+
'ts_returns': {'min_args': 2, 'max_args': 3, 'arg_types': ['expression', 'number', 'number'], 'param_names': ['x', 'd', 'mode'], 'keyword_only': True},
|
|
69
69
|
'ts_product': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
70
|
-
|
|
70
|
+
# Platform: ts_backfill(x, d)
|
|
71
|
+
'ts_backfill': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number'], 'param_names': ['x', 'd']},
|
|
71
72
|
'days_from_last_change': {'min_args': 1, 'max_args': 1, 'arg_types': ['expression']},
|
|
72
73
|
'last_diff_value': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
73
|
-
|
|
74
|
-
'
|
|
74
|
+
# Platform: ts_scale(x, d, constant=0)
|
|
75
|
+
'ts_scale': {'min_args': 2, 'max_args': 3, 'arg_types': ['expression', 'number', 'number'], 'param_names': ['x', 'd', 'constant'], 'keyword_only': True},
|
|
76
|
+
# Platform: ts_entropy(x, d)
|
|
77
|
+
'ts_entropy': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number'], 'param_names': ['x', 'd']},
|
|
75
78
|
'ts_step': {'min_args': 1, 'max_args': 1, 'arg_types': ['number']},
|
|
76
79
|
'ts_sum': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
77
80
|
'ts_co_kurtosis': {'min_args': 3, 'max_args': 3, 'arg_types': ['expression', 'expression', 'number']},
|
|
78
81
|
'inst_tvr': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
79
|
-
'ts_decay_exp_window': {'min_args': 2, 'max_args': 3, 'arg_types': ['expression', 'number', 'number'], 'param_names': ['x', 'd', 'factor']},
|
|
82
|
+
'ts_decay_exp_window': {'min_args': 2, 'max_args': 3, 'arg_types': ['expression', 'number', 'number'], 'param_names': ['x', 'd', 'factor'], 'keyword_only': True},
|
|
80
83
|
'ts_av_diff': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
81
84
|
'ts_kurtosis': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
82
|
-
|
|
85
|
+
# Platform: ts_min_max_diff(x, d, f=0.5)
|
|
86
|
+
'ts_min_max_diff': {'min_args': 2, 'max_args': 3, 'arg_types': ['expression', 'number', 'number'], 'param_names': ['x', 'd', 'f'], 'keyword_only': True},
|
|
83
87
|
'ts_arg_max': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
84
88
|
'ts_max': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
85
|
-
|
|
86
|
-
'
|
|
89
|
+
# Platform: ts_min_max_cps(x, d, f=2)
|
|
90
|
+
'ts_min_max_cps': {'min_args': 2, 'max_args': 3, 'arg_types': ['expression', 'number', 'number'], 'param_names': ['x', 'd', 'f'], 'keyword_only': True},
|
|
91
|
+
# Platform: ts_rank(x, d, constant=0)
|
|
92
|
+
'ts_rank': {'min_args': 2, 'max_args': 3, 'arg_types': ['expression', 'number', 'number'], 'param_names': ['x', 'd', 'constant'], 'keyword_only': True},
|
|
87
93
|
'ts_ir': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
88
94
|
'ts_theilsen': {'min_args': 3, 'max_args': 3, 'arg_types': ['expression', 'expression', 'number']},
|
|
89
|
-
|
|
90
|
-
'
|
|
91
|
-
|
|
95
|
+
# Platform: hump_decay(x, p=0)
|
|
96
|
+
'hump_decay': {'min_args': 1, 'max_args': 2, 'arg_types': ['expression', 'number'], 'param_names': ['x', 'p'], 'keyword_only': True},
|
|
97
|
+
# Platform: ts_weighted_decay(x, k=0.5)
|
|
98
|
+
'ts_weighted_decay': {'min_args': 1, 'max_args': 2, 'arg_types': ['expression', 'number'], 'param_names': ['x', 'k'], 'keyword_only': True},
|
|
99
|
+
# Platform: ts_quantile(x, d, driver="gaussian")
|
|
100
|
+
'ts_quantile': {'min_args': 2, 'max_args': 3, 'arg_types': ['expression', 'number', 'string'], 'param_names': ['x', 'd', 'driver'], 'keyword_only': True},
|
|
92
101
|
'ts_min': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
93
102
|
'ts_count_nans': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
94
103
|
'ts_covariance': {'min_args': 3, 'max_args': 3, 'arg_types': ['expression', 'expression', 'number']},
|
|
95
104
|
'ts_co_skewness': {'min_args': 3, 'max_args': 3, 'arg_types': ['expression', 'expression', 'number']},
|
|
96
105
|
'ts_min_diff': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
97
|
-
|
|
98
|
-
'
|
|
99
|
-
|
|
106
|
+
# Platform: ts_decay_linear(x, d, dense=false)
|
|
107
|
+
'ts_decay_linear': {'min_args': 2, 'max_args': 3, 'arg_types': ['expression', 'number', 'boolean'], 'param_names': ['x', 'd', 'dense'], 'keyword_only': True},
|
|
108
|
+
# Platform: jump_decay(x, d, sensitivity=0.5, force=0.1)
|
|
109
|
+
'jump_decay': {'min_args': 2, 'max_args': 4, 'arg_types': ['expression', 'number', 'number', 'number'], 'param_names': ['x', 'd', 'sensitivity', 'force'], 'keyword_only': True},
|
|
110
|
+
# Platform: ts_moment(x, d, k=0)
|
|
111
|
+
'ts_moment': {'min_args': 2, 'max_args': 3, 'arg_types': ['expression', 'number', 'number'], 'param_names': ['x', 'd', 'k'], 'keyword_only': True},
|
|
100
112
|
'ts_arg_min': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
101
|
-
'ts_regression': {'min_args': 3, 'max_args': 5, 'arg_types': ['expression', 'expression', 'number', 'number', 'number'], 'param_names': ['y', 'x', 'd', 'lag', 'rettype']},
|
|
113
|
+
'ts_regression': {'min_args': 3, 'max_args': 5, 'arg_types': ['expression', 'expression', 'number', 'number', 'number'], 'param_names': ['y', 'x', 'd', 'lag', 'rettype'], 'keyword_only': True},
|
|
102
114
|
'ts_skewness': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
103
115
|
'ts_max_diff': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
104
116
|
'kth_element': {'min_args': 3, 'max_args': 3, 'arg_types': ['expression', 'number', 'number']},
|
|
105
117
|
'hump': {'min_args': 1, 'max_args': 2, 'arg_types': ['expression', 'number'], 'param_names': ['x', 'hump']},
|
|
106
118
|
'ts_median': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
107
119
|
'ts_delta': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
108
|
-
|
|
109
|
-
'
|
|
110
|
-
'
|
|
111
|
-
'
|
|
112
|
-
'
|
|
120
|
+
# Platform: ts_poly_regression(y, x, d, k=1) and k must be keyword if provided
|
|
121
|
+
'ts_poly_regression': {'min_args': 3, 'max_args': 4, 'arg_types': ['expression', 'expression', 'number', 'number'], 'param_names': ['y', 'x', 'd', 'k'], 'keyword_only': True, 'keyword_only_from': 3},
|
|
122
|
+
'ts_target_tvr_decay': {'min_args': 1, 'max_args': 4, 'arg_types': ['expression', 'number', 'number', 'number'], 'param_names': ['x', 'lambda_min', 'lambda_max', 'target_tvr'], 'keyword_only': True},
|
|
123
|
+
'ts_target_tvr_delta_limit': {'min_args': 2, 'max_args': 5, 'arg_types': ['expression', 'expression', 'number', 'number', 'number'], 'param_names': ['x', 'y', 'lambda_min', 'lambda_max', 'target_tvr'], 'keyword_only': True},
|
|
124
|
+
'ts_target_tvr_hump': {'min_args': 1, 'max_args': 4, 'arg_types': ['expression', 'number', 'number', 'number'], 'param_names': ['x', 'lambda_min', 'lambda_max', 'target_tvr'], 'keyword_only': True},
|
|
125
|
+
# Platform: ts_delta_limit(x, y, limit_volume=0.1)
|
|
126
|
+
'ts_delta_limit': {'min_args': 2, 'max_args': 3, 'arg_types': ['expression', 'expression', 'number'], 'param_names': ['x', 'y', 'limit_volume'], 'keyword_only': True},
|
|
113
127
|
|
|
114
128
|
# Special 类别函数
|
|
115
129
|
'inst_pnl': {'min_args': 1, 'max_args': 1, 'arg_types': ['expression']},
|
|
@@ -276,6 +290,10 @@ class ExpressionValidator:
|
|
|
276
290
|
self.parser = yacc.yacc(module=self, debug=False)
|
|
277
291
|
# 错误信息存储
|
|
278
292
|
self.errors = []
|
|
293
|
+
# Cache for unit inference (unit/scalar/category)
|
|
294
|
+
self._unit_cache: Dict[int, str] = {}
|
|
295
|
+
# Cache for derived category detection (bucket/group_cartesian_product outputs)
|
|
296
|
+
self._derived_category_cache: Dict[int, bool] = {}
|
|
279
297
|
|
|
280
298
|
# 词法分析器规则
|
|
281
299
|
tokens = ('FUNCTION', 'FIELD', 'NUMBER', 'LPAREN', 'RPAREN',
|
|
@@ -509,6 +527,12 @@ class ExpressionValidator:
|
|
|
509
527
|
return self._validate_add(args, is_in_group_arg)
|
|
510
528
|
|
|
511
529
|
errors = []
|
|
530
|
+
|
|
531
|
+
# Keyword-only enforcement for optional parameters.
|
|
532
|
+
# If enabled, only the required leading arguments can be positional.
|
|
533
|
+
keyword_only_from = function_info.get('keyword_only_from')
|
|
534
|
+
if keyword_only_from is None and function_info.get('keyword_only'):
|
|
535
|
+
keyword_only_from = function_info.get('min_args', 0)
|
|
512
536
|
|
|
513
537
|
# 检查参数数量
|
|
514
538
|
if len(args) < function_info['min_args']:
|
|
@@ -545,12 +569,14 @@ class ExpressionValidator:
|
|
|
545
569
|
errors.append(f"函数 {function_name} 不存在参数 '{arg['name']}'")
|
|
546
570
|
elif arg['type'] == 'positional':
|
|
547
571
|
# 位置参数(字典形式)
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
572
|
+
if keyword_only_from is not None and positional_index >= keyword_only_from:
|
|
573
|
+
param_name = None
|
|
574
|
+
if 'param_names' in function_info and positional_index < len(function_info['param_names']):
|
|
575
|
+
param_name = function_info['param_names'][positional_index]
|
|
576
|
+
if param_name:
|
|
577
|
+
errors.append(f"函数 {function_name} 的第{positional_index+1}个参数必须使用命名参数 '{param_name}='")
|
|
578
|
+
else:
|
|
579
|
+
errors.append(f"函数 {function_name} 的第{positional_index+1}个参数必须使用命名参数")
|
|
554
580
|
else:
|
|
555
581
|
# 验证位置参数的类型
|
|
556
582
|
if positional_index < len(function_info['arg_types']):
|
|
@@ -564,12 +590,14 @@ class ExpressionValidator:
|
|
|
564
590
|
positional_index += 1
|
|
565
591
|
else:
|
|
566
592
|
# 位置参数(直接ASTNode形式)
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
593
|
+
if keyword_only_from is not None and positional_index >= keyword_only_from:
|
|
594
|
+
param_name = None
|
|
595
|
+
if 'param_names' in function_info and positional_index < len(function_info['param_names']):
|
|
596
|
+
param_name = function_info['param_names'][positional_index]
|
|
597
|
+
if param_name:
|
|
598
|
+
errors.append(f"函数 {function_name} 的第{positional_index+1}个参数必须使用命名参数 '{param_name}='")
|
|
599
|
+
else:
|
|
600
|
+
errors.append(f"函数 {function_name} 的第{positional_index+1}个参数必须使用命名参数")
|
|
573
601
|
else:
|
|
574
602
|
# 验证位置参数的类型
|
|
575
603
|
if positional_index < len(function_info['arg_types']):
|
|
@@ -583,6 +611,16 @@ class ExpressionValidator:
|
|
|
583
611
|
def _validate_arg_type(self, arg: ASTNode, expected_type: str, arg_index: int, function_name: str, is_in_group_arg: bool = False) -> List[str]:
|
|
584
612
|
"""验证参数类型是否符合预期"""
|
|
585
613
|
errors = []
|
|
614
|
+
|
|
615
|
+
# Unit compatibility check
|
|
616
|
+
# bucket()/group_cartesian_product() output a derived category (grouping key).
|
|
617
|
+
# It can only be consumed where a category/grouping key is expected (typically by group_* operators).
|
|
618
|
+
# It must not flow into normal Unit[] inputs like ts_mean's first argument.
|
|
619
|
+
if self._is_derived_category(arg) and expected_type != 'category':
|
|
620
|
+
errors.append(
|
|
621
|
+
f"Incompatible unit for input of \"{function_name}\" at index {arg_index}, expected \"Unit[]\", found \"Unit[Group:1]\""
|
|
622
|
+
)
|
|
623
|
+
return errors
|
|
586
624
|
|
|
587
625
|
# 首先检查是否是group类型字段,如果是则只能用于Group类型函数
|
|
588
626
|
# 但是如果当前函数是group_xxx或在group函数的参数链中,则允许使用
|
|
@@ -618,6 +656,86 @@ class ExpressionValidator:
|
|
|
618
656
|
|
|
619
657
|
return errors
|
|
620
658
|
|
|
659
|
+
def _infer_unit(self, node: ASTNode) -> str:
|
|
660
|
+
"""Infer the Unit kind of an AST node.
|
|
661
|
+
|
|
662
|
+
Returns:
|
|
663
|
+
'unit' - regular numeric time-series Unit[]
|
|
664
|
+
'scalar' - literals (numbers/booleans/strings)
|
|
665
|
+
'category' - category/grouping keys (industry/sector or derived via bucket/cartesian)
|
|
666
|
+
"""
|
|
667
|
+
if node is None:
|
|
668
|
+
return 'unit'
|
|
669
|
+
|
|
670
|
+
cache_key = id(node)
|
|
671
|
+
cached = self._unit_cache.get(cache_key)
|
|
672
|
+
if cached is not None:
|
|
673
|
+
return cached
|
|
674
|
+
|
|
675
|
+
unit = 'unit'
|
|
676
|
+
|
|
677
|
+
if node.node_type in {'number', 'boolean', 'string'}:
|
|
678
|
+
unit = 'scalar'
|
|
679
|
+
elif node.node_type in {'field', 'identifier'}:
|
|
680
|
+
unit = 'unit'
|
|
681
|
+
elif node.node_type == 'category':
|
|
682
|
+
unit = 'category'
|
|
683
|
+
elif node.node_type in {'unop', 'binop'}:
|
|
684
|
+
child_units = [self._infer_unit(child) for child in node.children if hasattr(child, 'node_type')]
|
|
685
|
+
unit = 'category' if 'category' in child_units else 'unit'
|
|
686
|
+
elif node.node_type == 'function':
|
|
687
|
+
fname = node.value
|
|
688
|
+
# Group-building functions create derived category outputs
|
|
689
|
+
if fname in {'bucket', 'group_cartesian_product'}:
|
|
690
|
+
unit = 'category'
|
|
691
|
+
else:
|
|
692
|
+
# Default: propagate from the first positional argument if available
|
|
693
|
+
first_arg = None
|
|
694
|
+
for child in node.children:
|
|
695
|
+
if isinstance(child, dict):
|
|
696
|
+
if child.get('type') == 'positional':
|
|
697
|
+
first_arg = child.get('value')
|
|
698
|
+
break
|
|
699
|
+
else:
|
|
700
|
+
first_arg = child
|
|
701
|
+
break
|
|
702
|
+
|
|
703
|
+
if hasattr(first_arg, 'node_type'):
|
|
704
|
+
unit = self._infer_unit(first_arg)
|
|
705
|
+
else:
|
|
706
|
+
unit = 'unit'
|
|
707
|
+
|
|
708
|
+
self._unit_cache[cache_key] = unit
|
|
709
|
+
return unit
|
|
710
|
+
|
|
711
|
+
def _is_derived_category(self, node: ASTNode) -> bool:
|
|
712
|
+
"""Return True if node is a derived category/grouping key (e.g., bucket/cartesian output)."""
|
|
713
|
+
if node is None:
|
|
714
|
+
return False
|
|
715
|
+
|
|
716
|
+
cache_key = id(node)
|
|
717
|
+
cached = self._derived_category_cache.get(cache_key)
|
|
718
|
+
if cached is not None:
|
|
719
|
+
return cached
|
|
720
|
+
|
|
721
|
+
derived = False
|
|
722
|
+
if node.node_type == 'function' and node.value in {'bucket', 'group_cartesian_product'}:
|
|
723
|
+
derived = True
|
|
724
|
+
elif node.node_type in {'unop', 'binop'}:
|
|
725
|
+
derived = any(
|
|
726
|
+
self._is_derived_category(child)
|
|
727
|
+
for child in node.children
|
|
728
|
+
if hasattr(child, 'node_type')
|
|
729
|
+
)
|
|
730
|
+
elif node.node_type == 'function':
|
|
731
|
+
derived = any(
|
|
732
|
+
self._is_derived_category(child.get('value')) if isinstance(child, dict) else self._is_derived_category(child)
|
|
733
|
+
for child in node.children
|
|
734
|
+
)
|
|
735
|
+
|
|
736
|
+
self._derived_category_cache[cache_key] = derived
|
|
737
|
+
return derived
|
|
738
|
+
|
|
621
739
|
def _validate_add(self, args: List[Any], is_in_group_arg: bool = False) -> List[str]:
|
|
622
740
|
"""Validate add(x, y, ..., filter=false).
|
|
623
741
|
|
|
@@ -885,6 +1003,9 @@ class ExpressionValidator:
|
|
|
885
1003
|
"""
|
|
886
1004
|
# 重置错误列表
|
|
887
1005
|
self.errors = []
|
|
1006
|
+
# Reset unit inference cache for this expression
|
|
1007
|
+
self._unit_cache = {}
|
|
1008
|
+
self._derived_category_cache = {}
|
|
888
1009
|
|
|
889
1010
|
try:
|
|
890
1011
|
expression = expression.strip()
|
|
@@ -7,6 +7,14 @@ A complete web application for decoding string templates with WorldQuant BRAIN i
|
|
|
7
7
|
import subprocess
|
|
8
8
|
import sys
|
|
9
9
|
import os
|
|
10
|
+
import io
|
|
11
|
+
|
|
12
|
+
# try set gbk problem
|
|
13
|
+
try:
|
|
14
|
+
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
|
15
|
+
except Exception as e:
|
|
16
|
+
print(e)
|
|
17
|
+
pass
|
|
10
18
|
|
|
11
19
|
def install_requirements():
|
|
12
20
|
"""Install required packages from requirements.txt if they're missing"""
|
|
@@ -128,6 +136,7 @@ try:
|
|
|
128
136
|
import queue
|
|
129
137
|
import uuid
|
|
130
138
|
from datetime import datetime
|
|
139
|
+
from blueprints.validator import ExpressionValidator
|
|
131
140
|
print("📚 Core packages imported successfully!")
|
|
132
141
|
|
|
133
142
|
# Import ace_lib for simulation options
|
|
@@ -407,6 +416,51 @@ def test_simulator_connection():
|
|
|
407
416
|
'error': f'Connection failed: {str(e)}'
|
|
408
417
|
})
|
|
409
418
|
|
|
419
|
+
@app.route('/api/validate_expressions', methods=['POST'])
|
|
420
|
+
def validate_expressions():
|
|
421
|
+
"""Validate a list of expressions using ExpressionValidator"""
|
|
422
|
+
try:
|
|
423
|
+
data = request.json
|
|
424
|
+
expressions = data.get('expressions', [])
|
|
425
|
+
|
|
426
|
+
if not isinstance(expressions, list):
|
|
427
|
+
return jsonify({'error': 'Expressions must be a list'}), 400
|
|
428
|
+
|
|
429
|
+
validator = ExpressionValidator()
|
|
430
|
+
results = []
|
|
431
|
+
valid_count = 0
|
|
432
|
+
invalid_count = 0
|
|
433
|
+
|
|
434
|
+
# Validate all expressions
|
|
435
|
+
expressions_to_validate = expressions
|
|
436
|
+
|
|
437
|
+
for expr in expressions_to_validate:
|
|
438
|
+
validation_result = validator.check_expression(expr)
|
|
439
|
+
if validation_result['valid']:
|
|
440
|
+
valid_count += 1
|
|
441
|
+
results.append({
|
|
442
|
+
'expression': expr,
|
|
443
|
+
'valid': True
|
|
444
|
+
})
|
|
445
|
+
else:
|
|
446
|
+
invalid_count += 1
|
|
447
|
+
results.append({
|
|
448
|
+
'expression': expr,
|
|
449
|
+
'valid': False,
|
|
450
|
+
'errors': validation_result['errors']
|
|
451
|
+
})
|
|
452
|
+
|
|
453
|
+
return jsonify({
|
|
454
|
+
'results': results,
|
|
455
|
+
'summary': {
|
|
456
|
+
'total': len(expressions_to_validate),
|
|
457
|
+
'valid': valid_count,
|
|
458
|
+
'invalid': invalid_count
|
|
459
|
+
}
|
|
460
|
+
})
|
|
461
|
+
except Exception as e:
|
|
462
|
+
return jsonify({'error': str(e)}), 500
|
|
463
|
+
|
|
410
464
|
@app.route('/api/simulator/run', methods=['POST'])
|
|
411
465
|
def run_simulator_with_params():
|
|
412
466
|
"""Run simulator with user-provided parameters in a new terminal"""
|
cnhkmcp/untracked/arxiv_api.py
CHANGED
|
@@ -3,6 +3,13 @@ import xml.etree.ElementTree as ET
|
|
|
3
3
|
import os
|
|
4
4
|
import sys
|
|
5
5
|
import argparse
|
|
6
|
+
import io
|
|
7
|
+
# try set gbk problem
|
|
8
|
+
try:
|
|
9
|
+
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
|
10
|
+
except Exception as e:
|
|
11
|
+
print(e)
|
|
12
|
+
pass
|
|
6
13
|
|
|
7
14
|
def search_arxiv(query, max_results=10):
|
|
8
15
|
"""Search arXiv for papers"""
|
|
@@ -22,6 +22,14 @@ from selenium.common.exceptions import TimeoutException, NoSuchElementException
|
|
|
22
22
|
import requests
|
|
23
23
|
import os
|
|
24
24
|
import shutil
|
|
25
|
+
import io
|
|
26
|
+
|
|
27
|
+
# try set gbk problem
|
|
28
|
+
try:
|
|
29
|
+
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
|
30
|
+
except Exception as e:
|
|
31
|
+
print(e)
|
|
32
|
+
pass
|
|
25
33
|
|
|
26
34
|
# Initialize forum MCP server
|
|
27
35
|
try:
|
|
@@ -15,6 +15,14 @@ from bs4 import BeautifulSoup
|
|
|
15
15
|
from playwright.async_api import async_playwright
|
|
16
16
|
import requests
|
|
17
17
|
import os
|
|
18
|
+
import io
|
|
19
|
+
|
|
20
|
+
# try set gbk problem
|
|
21
|
+
try:
|
|
22
|
+
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
|
23
|
+
except Exception as e:
|
|
24
|
+
print(e)
|
|
25
|
+
pass
|
|
18
26
|
|
|
19
27
|
def log(message: str, level: str = "INFO"):
|
|
20
28
|
"""Log message with timestamp."""
|
|
@@ -15,6 +15,14 @@ from bs4 import BeautifulSoup
|
|
|
15
15
|
from playwright.async_api import async_playwright
|
|
16
16
|
import requests
|
|
17
17
|
import os
|
|
18
|
+
import io
|
|
19
|
+
|
|
20
|
+
# try set gbk problem
|
|
21
|
+
try:
|
|
22
|
+
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
|
23
|
+
except Exception as e:
|
|
24
|
+
print(e)
|
|
25
|
+
pass
|
|
18
26
|
|
|
19
27
|
def log(message: str, level: str = "INFO"):
|
|
20
28
|
"""Log message with timestamp."""
|
|
@@ -18,7 +18,7 @@ import os
|
|
|
18
18
|
import sys
|
|
19
19
|
import math
|
|
20
20
|
from time import sleep
|
|
21
|
-
|
|
21
|
+
import io
|
|
22
22
|
import requests
|
|
23
23
|
import pandas as pd
|
|
24
24
|
from mcp.server.fastmcp import FastMCP
|
|
@@ -29,6 +29,13 @@ from pathlib import Path
|
|
|
29
29
|
# Import the new forum client
|
|
30
30
|
from forum_functions import forum_client
|
|
31
31
|
|
|
32
|
+
# try set gbk problem
|
|
33
|
+
try:
|
|
34
|
+
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
|
35
|
+
except Exception as e:
|
|
36
|
+
print(e)
|
|
37
|
+
pass
|
|
38
|
+
|
|
32
39
|
# Configure logging
|
|
33
40
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
|
34
41
|
logger = logging.getLogger(__name__)
|
|
@@ -18,6 +18,13 @@ import os
|
|
|
18
18
|
import sys
|
|
19
19
|
import math
|
|
20
20
|
from time import sleep
|
|
21
|
+
import io
|
|
22
|
+
# try set gbk problem
|
|
23
|
+
try:
|
|
24
|
+
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
|
25
|
+
except Exception as e:
|
|
26
|
+
print(e)
|
|
27
|
+
pass
|
|
21
28
|
|
|
22
29
|
import requests
|
|
23
30
|
import pandas as pd
|