quantnodes 3.0.0__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.
Files changed (399) hide show
  1. QuantNodes/__init__.py +15 -0
  2. QuantNodes/__main__.py +14 -0
  3. QuantNodes/agent/__init__.py +158 -0
  4. QuantNodes/agent/agents/__init__.py +13 -0
  5. QuantNodes/agent/agents/definition.py +180 -0
  6. QuantNodes/agent/agents/manager.py +73 -0
  7. QuantNodes/agent/config/__init__.py +34 -0
  8. QuantNodes/agent/config/executor.py +958 -0
  9. QuantNodes/agent/config/loader.py +427 -0
  10. QuantNodes/agent/config/templates/bollinger_bands.yaml +84 -0
  11. QuantNodes/agent/config/templates/dual_ma.yaml +72 -0
  12. QuantNodes/agent/config/templates/empty.yaml +56 -0
  13. QuantNodes/agent/config/templates/mean_reversion.yaml +47 -0
  14. QuantNodes/agent/config/templates/mean_reversion_zscore.yaml +90 -0
  15. QuantNodes/agent/config/templates/momentum.yaml +81 -0
  16. QuantNodes/agent/config/templates/momentum_breakout.yaml +84 -0
  17. QuantNodes/agent/config/templates/rsi_strategy.yaml +72 -0
  18. QuantNodes/agent/config/templates/volume_price.yaml +86 -0
  19. QuantNodes/agent/config/types.py +156 -0
  20. QuantNodes/agent/config_mapper.py +293 -0
  21. QuantNodes/agent/core/__init__.py +19 -0
  22. QuantNodes/agent/core/dream.py +47 -0
  23. QuantNodes/agent/core/quant_dream.py +274 -0
  24. QuantNodes/agent/cron_jobs.py +314 -0
  25. QuantNodes/agent/nanobot_bridge.py +242 -0
  26. QuantNodes/agent/permission/__init__.py +30 -0
  27. QuantNodes/agent/permission/defaults.py +36 -0
  28. QuantNodes/agent/permission/evaluate.py +41 -0
  29. QuantNodes/agent/permission/models.py +59 -0
  30. QuantNodes/agent/permission/service.py +133 -0
  31. QuantNodes/agent/providers/__init__.py +11 -0
  32. QuantNodes/agent/providers/base.py +102 -0
  33. QuantNodes/agent/providers/quantnodes.py +610 -0
  34. QuantNodes/agent/providers/rate_limiter.py +326 -0
  35. QuantNodes/agent/providers/registry.py +163 -0
  36. QuantNodes/agent/skills/__init__.py +20 -0
  37. QuantNodes/agent/skills/base.py +118 -0
  38. QuantNodes/agent/skills/bridge.py +73 -0
  39. QuantNodes/agent/skills/factor/__init__.py +14 -0
  40. QuantNodes/agent/skills/factor/correlation.py +99 -0
  41. QuantNodes/agent/skills/factor/group_backtest.py +114 -0
  42. QuantNodes/agent/skills/factor/ic_analysis.py +106 -0
  43. QuantNodes/agent/skills/loader.py +107 -0
  44. QuantNodes/agent/skills/registry.py +105 -0
  45. QuantNodes/agent/skills/strategy/__init__.py +16 -0
  46. QuantNodes/agent/skills/strategy/bollinger.py +86 -0
  47. QuantNodes/agent/skills/strategy/dual_ma.py +82 -0
  48. QuantNodes/agent/skills/strategy/momentum.py +74 -0
  49. QuantNodes/agent/skills/strategy/rsi_reversal.py +99 -0
  50. QuantNodes/agent/skills_quant/__init__.py +14 -0
  51. QuantNodes/agent/skills_quant/backtest-analyze/SKILL.md +42 -0
  52. QuantNodes/agent/skills_quant/config-driven/SKILL.md +72 -0
  53. QuantNodes/agent/skills_quant/factor-research/SKILL.md +40 -0
  54. QuantNodes/agent/skills_quant/quant-dream/SKILL.md +55 -0
  55. QuantNodes/agent/skills_quant/risk-management/SKILL.md +45 -0
  56. QuantNodes/agent/skills_quant/strategy-design/SKILL.md +43 -0
  57. QuantNodes/agent/templates/__init__.py +4 -0
  58. QuantNodes/agent/tools/__init__.py +173 -0
  59. QuantNodes/agent/tools/_workspace.py +51 -0
  60. QuantNodes/agent/tools/alpha_backtest.py +328 -0
  61. QuantNodes/agent/tools/alpha_evaluate.py +493 -0
  62. QuantNodes/agent/tools/backtest.py +226 -0
  63. QuantNodes/agent/tools/base.py +133 -0
  64. QuantNodes/agent/tools/code_search.py +207 -0
  65. QuantNodes/agent/tools/config_backtest.py +401 -0
  66. QuantNodes/agent/tools/context.py +97 -0
  67. QuantNodes/agent/tools/dream_skill.py +77 -0
  68. QuantNodes/agent/tools/echo.py +38 -0
  69. QuantNodes/agent/tools/factor.py +231 -0
  70. QuantNodes/agent/tools/file_ops.py +201 -0
  71. QuantNodes/agent/tools/git_ops.py +190 -0
  72. QuantNodes/agent/tools/operator_lookup.py +218 -0
  73. QuantNodes/agent/tools/output_truncation.py +77 -0
  74. QuantNodes/agent/tools/path_check.py +43 -0
  75. QuantNodes/agent/tools/pipeline.py +62 -0
  76. QuantNodes/agent/tools/registry.py +150 -0
  77. QuantNodes/agent/tools/sandbox.py +62 -0
  78. QuantNodes/agent/tools/shell_safety.py +63 -0
  79. QuantNodes/agent/tools/strategy.py +106 -0
  80. QuantNodes/agent/tools/task.py +171 -0
  81. QuantNodes/agent/tools/web_fetch.py +142 -0
  82. QuantNodes/agent/tools/web_search.py +114 -0
  83. QuantNodes/agent/tools/wiki.py +370 -0
  84. QuantNodes/agent/utils/__init__.py +11 -0
  85. QuantNodes/agent/utils/helpers.py +43 -0
  86. QuantNodes/agent/utils/prompt_templates.py +30 -0
  87. QuantNodes/agent/workflows/__init__.py +20 -0
  88. QuantNodes/agent/workflows/implementations/__init__.py +8 -0
  89. QuantNodes/agent/workflows/implementations/alpha_gpt.py +508 -0
  90. QuantNodes/agent/workflows/implementations/mcts.py +442 -0
  91. QuantNodes/agent/workflows/parsers.py +44 -0
  92. QuantNodes/agent/workflows/registry.py +119 -0
  93. QuantNodes/agent/workflows/step_agent.py +219 -0
  94. QuantNodes/agent/workflows/tool.py +198 -0
  95. QuantNodes/ai/__init__.py +93 -0
  96. QuantNodes/ai/llm/__init__.py +75 -0
  97. QuantNodes/ai/llm/base.py +233 -0
  98. QuantNodes/ai/llm/decorators.py +281 -0
  99. QuantNodes/ai/llm/gateway.py +571 -0
  100. QuantNodes/ai/llm/null.py +76 -0
  101. QuantNodes/ai/llm/openai.py +435 -0
  102. QuantNodes/ai/optimizer.py +405 -0
  103. QuantNodes/ai/prompts/__init__.py +229 -0
  104. QuantNodes/ai/sandbox.py +371 -0
  105. QuantNodes/ai/sandbox_pandas_bridge.py +150 -0
  106. QuantNodes/ai/strategy_gen.py +396 -0
  107. QuantNodes/backtest/__init__.py +64 -0
  108. QuantNodes/backtest/backtest_node.py +188 -0
  109. QuantNodes/backtest/broker_node.py +378 -0
  110. QuantNodes/backtest/config_runner.py +397 -0
  111. QuantNodes/backtest/config_strategy.py +64 -0
  112. QuantNodes/backtest/risk_node.py +360 -0
  113. QuantNodes/backtest/strategy_node.py +268 -0
  114. QuantNodes/cache_node/__init__.py +19 -0
  115. QuantNodes/cache_node/base.py +244 -0
  116. QuantNodes/cache_node/cache_store.py +99 -0
  117. QuantNodes/cache_node/metadata.py +100 -0
  118. QuantNodes/cli/__init__.py +109 -0
  119. QuantNodes/cli/_helpers.py +511 -0
  120. QuantNodes/cli/command.py +110 -0
  121. QuantNodes/cli/commands/__init__.py +69 -0
  122. QuantNodes/cli/commands/agent.py +158 -0
  123. QuantNodes/cli/commands/alpha.py +951 -0
  124. QuantNodes/cli/commands/chat.py +38 -0
  125. QuantNodes/cli/commands/evolve.py +120 -0
  126. QuantNodes/cli/commands/factor.py +569 -0
  127. QuantNodes/cli/commands/init.py +190 -0
  128. QuantNodes/cli/commands/run.py +259 -0
  129. QuantNodes/cli/commands/serve.py +398 -0
  130. QuantNodes/cli/commands/version.py +120 -0
  131. QuantNodes/cli/enhanced.py +146 -0
  132. QuantNodes/conf_node/__init__.py +37 -0
  133. QuantNodes/conf_node/base.py +120 -0
  134. QuantNodes/conf_node/env_config.py +132 -0
  135. QuantNodes/conf_node/ini_config.py +70 -0
  136. QuantNodes/conf_node/json_config.py +69 -0
  137. QuantNodes/conf_node/yaml_config.py +78 -0
  138. QuantNodes/constants.py +17 -0
  139. QuantNodes/core/__init__.py +196 -0
  140. QuantNodes/core/_lookback_helpers.py +49 -0
  141. QuantNodes/core/ast_parser.py +198 -0
  142. QuantNodes/core/base.py +61 -0
  143. QuantNodes/core/cache_manager.py +344 -0
  144. QuantNodes/core/cache_utils.py +150 -0
  145. QuantNodes/core/cond_builder.py +53 -0
  146. QuantNodes/core/config.py +170 -0
  147. QuantNodes/core/constants.py +48 -0
  148. QuantNodes/core/control.py +412 -0
  149. QuantNodes/core/data_preprocessing.py +453 -0
  150. QuantNodes/core/data_source.py +46 -0
  151. QuantNodes/core/events.py +178 -0
  152. QuantNodes/core/evolution/__init__.py +22 -0
  153. QuantNodes/core/evolution/loop.py +583 -0
  154. QuantNodes/core/evolution/operators.py +289 -0
  155. QuantNodes/core/evolution/settings.py +44 -0
  156. QuantNodes/core/expression.py +841 -0
  157. QuantNodes/core/feedback/__init__.py +38 -0
  158. QuantNodes/core/feedback/channels.py +182 -0
  159. QuantNodes/core/feedback/collector.py +91 -0
  160. QuantNodes/core/feedback/dataclass.py +239 -0
  161. QuantNodes/core/feedback/llm_judge.py +138 -0
  162. QuantNodes/core/knowledge/__init__.py +69 -0
  163. QuantNodes/core/knowledge/knowledge_base.py +217 -0
  164. QuantNodes/core/knowledge/lineage_compress.py +196 -0
  165. QuantNodes/core/knowledge/lineage_expand.py +123 -0
  166. QuantNodes/core/knowledge/metrics/__init__.py +43 -0
  167. QuantNodes/core/knowledge/metrics/evaluator.py +176 -0
  168. QuantNodes/core/knowledge/metrics/metrics.py +220 -0
  169. QuantNodes/core/knowledge/rag_prompt.py +196 -0
  170. QuantNodes/core/knowledge/retriever.py +209 -0
  171. QuantNodes/core/lambda_node.py +81 -0
  172. QuantNodes/core/monitoring/__init__.py +22 -0
  173. QuantNodes/core/monitoring/collector.py +292 -0
  174. QuantNodes/core/monitoring/dashboard.py +365 -0
  175. QuantNodes/core/node.py +375 -0
  176. QuantNodes/core/pandas_utils.py +504 -0
  177. QuantNodes/core/parallel/__init__.py +15 -0
  178. QuantNodes/core/parallel/worker.py +140 -0
  179. QuantNodes/core/parallel/worker_process.py +265 -0
  180. QuantNodes/core/path_utils.py +73 -0
  181. QuantNodes/core/pipeline.py +328 -0
  182. QuantNodes/core/plugin.py +135 -0
  183. QuantNodes/core/quality_gate/__init__.py +32 -0
  184. QuantNodes/core/quality_gate/complexity.py +94 -0
  185. QuantNodes/core/quality_gate/consistency.py +26 -0
  186. QuantNodes/core/quality_gate/node.py +97 -0
  187. QuantNodes/core/quality_gate/redundancy.py +51 -0
  188. QuantNodes/core/quality_gate/settings.py +43 -0
  189. QuantNodes/core/quality_gate/zoo.py +98 -0
  190. QuantNodes/core/serializable.py +116 -0
  191. QuantNodes/core/serialization.py +673 -0
  192. QuantNodes/core/tools.py +333 -0
  193. QuantNodes/core/trajectory/__init__.py +25 -0
  194. QuantNodes/core/trajectory/entry.py +116 -0
  195. QuantNodes/core/trajectory/lineage.py +67 -0
  196. QuantNodes/core/trajectory/pool.py +211 -0
  197. QuantNodes/core/trajectory/selector.py +140 -0
  198. QuantNodes/core/visualization/__init__.py +33 -0
  199. QuantNodes/core/visualization/builder.py +233 -0
  200. QuantNodes/core/visualization/gate_breakdown.py +140 -0
  201. QuantNodes/core/visualization/lineage_dag.py +203 -0
  202. QuantNodes/core/visualization/metric_distribution.py +125 -0
  203. QuantNodes/core/visualization/report.py +68 -0
  204. QuantNodes/database_node/__init__.py +69 -0
  205. QuantNodes/database_node/base.py +135 -0
  206. QuantNodes/database_node/clickhouse_node.py +272 -0
  207. QuantNodes/database_node/csv_node.py +83 -0
  208. QuantNodes/database_node/duckdb_node.py +86 -0
  209. QuantNodes/database_node/factory.py +83 -0
  210. QuantNodes/database_node/mysql_node.py +100 -0
  211. QuantNodes/database_node/parquet_node.py +75 -0
  212. QuantNodes/database_node/sqlite_node.py +67 -0
  213. QuantNodes/factor_node/__init__.py +50 -0
  214. QuantNodes/factor_node/factor.py +563 -0
  215. QuantNodes/factor_node/factor_db.py +421 -0
  216. QuantNodes/factor_node/factor_functions/__init__.py +252 -0
  217. QuantNodes/factor_node/factor_functions/_helpers.py +358 -0
  218. QuantNodes/factor_node/factor_functions/_helpers_debug.py +317 -0
  219. QuantNodes/factor_node/factor_functions/composite_ops.py +136 -0
  220. QuantNodes/factor_node/factor_functions/math_ops.py +433 -0
  221. QuantNodes/factor_node/factor_functions/section_ops.py +290 -0
  222. QuantNodes/factor_node/factor_functions/talib_ops.py +1293 -0
  223. QuantNodes/factor_node/factor_functions/time_ops.py +535 -0
  224. QuantNodes/factor_node/factor_operation.py +1115 -0
  225. QuantNodes/factor_node/factor_table.py +1073 -0
  226. QuantNodes/factor_node/quant_nodes_object.py +60 -0
  227. QuantNodes/mcp_server/__init__.py +27 -0
  228. QuantNodes/mcp_server/__main__.py +4 -0
  229. QuantNodes/mcp_server/server.py +272 -0
  230. QuantNodes/methods/__init__.py +28 -0
  231. QuantNodes/methods/pipeline.py +100 -0
  232. QuantNodes/methods/sandbox.py +102 -0
  233. QuantNodes/monitor/__init__.py +27 -0
  234. QuantNodes/monitor/agent_tools/__init__.py +5 -0
  235. QuantNodes/monitor/agent_tools/monitor_tool.py +98 -0
  236. QuantNodes/monitor/agent_tools/schedule_tool.py +98 -0
  237. QuantNodes/monitor/agent_tools/version_tool.py +133 -0
  238. QuantNodes/monitor/monitor/__init__.py +6 -0
  239. QuantNodes/monitor/monitor/alerter.py +60 -0
  240. QuantNodes/monitor/monitor/collector.py +164 -0
  241. QuantNodes/monitor/monitor/dashboard.py +115 -0
  242. QuantNodes/monitor/monitor/drift.py +190 -0
  243. QuantNodes/monitor/scheduler/__init__.py +4 -0
  244. QuantNodes/monitor/scheduler/runner.py +133 -0
  245. QuantNodes/monitor/scheduler/scheduler.py +184 -0
  246. QuantNodes/monitor/storage/__init__.py +16 -0
  247. QuantNodes/monitor/storage/models.py +70 -0
  248. QuantNodes/monitor/storage/repository.py +407 -0
  249. QuantNodes/monitor/version/__init__.py +4 -0
  250. QuantNodes/monitor/version/diff.py +81 -0
  251. QuantNodes/monitor/version/version_manager.py +182 -0
  252. QuantNodes/operator_node/__init__.py +28 -0
  253. QuantNodes/operator_node/base.py +97 -0
  254. QuantNodes/operator_node/query_node.py +129 -0
  255. QuantNodes/operator_node/sql_builder.py +125 -0
  256. QuantNodes/operator_node/sql_utils.py +172 -0
  257. QuantNodes/operator_node/transform.py +130 -0
  258. QuantNodes/operators/__init__.py +90 -0
  259. QuantNodes/operators/_engine.py +108 -0
  260. QuantNodes/operators/composite.py +161 -0
  261. QuantNodes/operators/composite_dag.py +667 -0
  262. QuantNodes/operators/composite_dag_ops.py +343 -0
  263. QuantNodes/operators/composite_dag_pandas_ops.py +382 -0
  264. QuantNodes/operators/custom.py +408 -0
  265. QuantNodes/operators/facade.py +164 -0
  266. QuantNodes/operators/math.py +163 -0
  267. QuantNodes/operators/proxy.py +29 -0
  268. QuantNodes/operators/registry.py +144 -0
  269. QuantNodes/operators/section.py +99 -0
  270. QuantNodes/operators/talib.py +757 -0
  271. QuantNodes/operators/templates.py +95 -0
  272. QuantNodes/operators/time_series.py +136 -0
  273. QuantNodes/prompts/__init__.py +20 -0
  274. QuantNodes/prompts/backtest/__init__.py +12 -0
  275. QuantNodes/prompts/backtest/factor_based.py +86 -0
  276. QuantNodes/prompts/backtest/standard.py +73 -0
  277. QuantNodes/prompts/factor/__init__.py +14 -0
  278. QuantNodes/prompts/factor/correlation.py +77 -0
  279. QuantNodes/prompts/factor/group_backtest.py +86 -0
  280. QuantNodes/prompts/factor/ic_analysis.py +91 -0
  281. QuantNodes/prompts/strategy/__init__.py +18 -0
  282. QuantNodes/prompts/strategy/market_neutral.py +96 -0
  283. QuantNodes/prompts/strategy/mean_reversion.py +107 -0
  284. QuantNodes/prompts/strategy/momentum.py +160 -0
  285. QuantNodes/prompts/strategy/pairs_trading.py +107 -0
  286. QuantNodes/prompts/strategy/trend_following.py +96 -0
  287. QuantNodes/research/README.md +106 -0
  288. QuantNodes/research/__init__.py +154 -0
  289. QuantNodes/research/_legacy_3c/__init__.py +61 -0
  290. QuantNodes/research/_legacy_3c/auto_researcher.py +289 -0
  291. QuantNodes/research/_legacy_3c/factor_evaluator.py +560 -0
  292. QuantNodes/research/_legacy_3c/factor_miner.py +318 -0
  293. QuantNodes/research/_legacy_3c/mcts_search.py +324 -0
  294. QuantNodes/research/factor_test/__init__.py +25 -0
  295. QuantNodes/research/factor_test/config.py +184 -0
  296. QuantNodes/research/factor_test/config_builder.py +276 -0
  297. QuantNodes/research/factor_test/e2e/data_prep.py +163 -0
  298. QuantNodes/research/factor_test/e2e/run_evolution_e2e.py +309 -0
  299. QuantNodes/research/factor_test/evolution_adapter.py +231 -0
  300. QuantNodes/research/factor_test/feedback_wrapper.py +102 -0
  301. QuantNodes/research/factor_test/ifind_db/__init__.py +7 -0
  302. QuantNodes/research/factor_test/ifind_db/fetcher.py +224 -0
  303. QuantNodes/research/factor_test/ifind_db/ifind_database.py +689 -0
  304. QuantNodes/research/factor_test/nodes/__init__.py +1 -0
  305. QuantNodes/research/factor_test/nodes/_base.py +91 -0
  306. QuantNodes/research/factor_test/nodes/adjust_date_node.py +48 -0
  307. QuantNodes/research/factor_test/nodes/configs.py +240 -0
  308. QuantNodes/research/factor_test/nodes/factor_neutralize_node.py +87 -0
  309. QuantNodes/research/factor_test/nodes/factor_preprocess_node.py +222 -0
  310. QuantNodes/research/factor_test/nodes/factor_score_node.py +141 -0
  311. QuantNodes/research/factor_test/nodes/factor_test_report_node.py +153 -0
  312. QuantNodes/research/factor_test/nodes/group_analyzer_node.py +317 -0
  313. QuantNodes/research/factor_test/nodes/ic_analyzer_node.py +112 -0
  314. QuantNodes/research/factor_test/nodes/load_data_node.py +100 -0
  315. QuantNodes/research/factor_test/nodes/long_short_node.py +93 -0
  316. QuantNodes/research/factor_test/nodes/neutralizers.py +222 -0
  317. QuantNodes/research/factor_test/nodes/preprocess_strategies.py +277 -0
  318. QuantNodes/research/factor_test/nodes/risk_correlation_node.py +112 -0
  319. QuantNodes/research/factor_test/nodes/sample_pool_filter_node.py +110 -0
  320. QuantNodes/research/factor_test/nodes/tradability_filter_node.py +92 -0
  321. QuantNodes/research/factor_test/pipeline_runner.py +305 -0
  322. QuantNodes/research/factor_test/pipeline_spec.py +216 -0
  323. QuantNodes/research/factor_test/utils/__init__.py +26 -0
  324. QuantNodes/research/factor_test/utils/constants.py +86 -0
  325. QuantNodes/research/factor_test/utils/data_loader.py +141 -0
  326. QuantNodes/research/factor_test/utils/date_utils.py +232 -0
  327. QuantNodes/research/factor_test/utils/file_loaders.py +150 -0
  328. QuantNodes/research/factor_test/utils/labels.py +37 -0
  329. QuantNodes/research/factor_test/utils/metrics_extractor.py +55 -0
  330. QuantNodes/research/factor_test/utils/performance_metrics.py +175 -0
  331. QuantNodes/research/factor_test/utils/safe_load.py +106 -0
  332. QuantNodes/research/quant_alpha/CHANGELOG.md +80 -0
  333. QuantNodes/research/quant_alpha/README.md +142 -0
  334. QuantNodes/research/quant_alpha/__init__.py +45 -0
  335. QuantNodes/research/quant_alpha/adapters/__init__.py +99 -0
  336. QuantNodes/research/quant_alpha/adapters/calculator.py +503 -0
  337. QuantNodes/research/quant_alpha/adapters/expression.py +387 -0
  338. QuantNodes/research/quant_alpha/alpha101_design/__init__.py +50 -0
  339. QuantNodes/research/quant_alpha/alpha101_design/few_shot_examples.py +243 -0
  340. QuantNodes/research/quant_alpha/alpha101_design/philosophy.py +474 -0
  341. QuantNodes/research/quant_alpha/alpha158_design/__init__.py +63 -0
  342. QuantNodes/research/quant_alpha/alpha158_design/few_shot_examples.py +219 -0
  343. QuantNodes/research/quant_alpha/alpha158_design/philosophy.py +240 -0
  344. QuantNodes/research/quant_alpha/evaluation/__init__.py +47 -0
  345. QuantNodes/research/quant_alpha/evaluation/baselines/__init__.py +8 -0
  346. QuantNodes/research/quant_alpha/evaluation/baselines/g1_handcrafted.py +135 -0
  347. QuantNodes/research/quant_alpha/evaluation/baselines/g2_llm_only.py +269 -0
  348. QuantNodes/research/quant_alpha/evaluation/baselines/g3_alpha_gpt.py +152 -0
  349. QuantNodes/research/quant_alpha/evaluation/clickhouse_data_loader.py +227 -0
  350. QuantNodes/research/quant_alpha/evaluation/contracts.py +376 -0
  351. QuantNodes/research/quant_alpha/evaluation/evaluators/__init__.py +6 -0
  352. QuantNodes/research/quant_alpha/evaluation/evaluators/polars_evaluator.py +545 -0
  353. QuantNodes/research/quant_alpha/evaluation/mock_data_loader.py +226 -0
  354. QuantNodes/research/quant_alpha/evaluation/runner.py +243 -0
  355. QuantNodes/research/quant_alpha/llm/__init__.py +38 -0
  356. QuantNodes/research/quant_alpha/llm/parser.py +681 -0
  357. QuantNodes/research/quant_alpha/logic_driven_pipeline.py +411 -0
  358. QuantNodes/research/quant_alpha/logic_mining/__init__.py +74 -0
  359. QuantNodes/research/quant_alpha/logic_mining/compiler.py +457 -0
  360. QuantNodes/research/quant_alpha/logic_mining/generator.py +366 -0
  361. QuantNodes/research/quant_alpha/logic_mining/models.py +252 -0
  362. QuantNodes/research/quant_alpha/logic_mining/parser.py +287 -0
  363. QuantNodes/research/quant_alpha/logic_mining/pipelines.py +297 -0
  364. QuantNodes/research/quant_alpha/logic_mining/sources.py +149 -0
  365. QuantNodes/research/quant_alpha/mcts/__init__.py +66 -0
  366. QuantNodes/research/quant_alpha/mcts/cache.py +262 -0
  367. QuantNodes/research/quant_alpha/mcts/extension_ops.py +320 -0
  368. QuantNodes/research/quant_alpha/mcts/feedback.py +825 -0
  369. QuantNodes/research/quant_alpha/mcts/op_prior.py +180 -0
  370. QuantNodes/research/quant_alpha/mcts/search.py +540 -0
  371. QuantNodes/research/quant_alpha/mcts/tree.py +201 -0
  372. QuantNodes/research/quant_alpha/operator_vocab/__init__.py +50 -0
  373. QuantNodes/research/quant_alpha/operator_vocab/config.py +54 -0
  374. QuantNodes/research/quant_alpha/operator_vocab/metadata.py +263 -0
  375. QuantNodes/research/quant_alpha/operator_vocab/vocabulary.py +481 -0
  376. QuantNodes/research/quant_alpha/pipeline.py +1027 -0
  377. QuantNodes/research/quant_alpha/types/__init__.py +27 -0
  378. QuantNodes/research/quant_alpha/types/constants.py +28 -0
  379. QuantNodes/research/quant_alpha/types/state.py +205 -0
  380. QuantNodes/research/quant_alpha/workflow/__init__.py +32 -0
  381. QuantNodes/research/quant_alpha/workflow/alpha_gpt.py +911 -0
  382. QuantNodes/research/quant_alpha/workflow/alpha_logics.py +416 -0
  383. QuantNodes/research/quant_alpha/workflow/state.py +27 -0
  384. QuantNodes/research/report_reproducer.py +485 -0
  385. QuantNodes/research/wiki.py +1155 -0
  386. QuantNodes/symbolic/__init__.py +51 -0
  387. QuantNodes/symbolic/compiler.py +113 -0
  388. QuantNodes/symbolic/dialect.py +260 -0
  389. QuantNodes/symbolic/executor.py +147 -0
  390. QuantNodes/symbolic/expression.py +234 -0
  391. QuantNodes/symbolic/functions.py +433 -0
  392. QuantNodes/symbolic/optimizer.py +165 -0
  393. QuantNodes/ui_node/__init__.py +30 -0
  394. QuantNodes/ui_node/base.py +222 -0
  395. quantnodes-3.0.0.dist-info/METADATA +463 -0
  396. quantnodes-3.0.0.dist-info/RECORD +399 -0
  397. quantnodes-3.0.0.dist-info/WHEEL +5 -0
  398. quantnodes-3.0.0.dist-info/entry_points.txt +24 -0
  399. quantnodes-3.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,201 @@
1
+ # coding=utf-8
2
+ """
3
+ mcts/tree.py - MCTS 搜索树(带谱系追踪)
4
+
5
+ vs 旧 mcts_search.py:53-62 的 MCTSNode:
6
+ - 旧:仅 parent: MCTSNode 引用,无 entry_id
7
+ - 新:entry_id (UUID) + parent_id (UUID) + 完整谱系
8
+
9
+ 每节点的 entry_id 可映射到 core/trajectory.TrajectoryEntry
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import math
15
+ import uuid
16
+ from dataclasses import dataclass, field
17
+ from enum import Enum
18
+ from typing import Any, Dict, List, Optional
19
+
20
+
21
+ class NodeStatus(str, Enum):
22
+ """MCTS 节点状态"""
23
+ PENDING = "pending" # 未评估
24
+ EVALUATED = "evaluated" # 已评估(5 通道反馈完成)
25
+ PRUNED = "pruned" # 被质量门拦截
26
+ REJECTED = "rejected" # 被反馈拒绝
27
+
28
+
29
+ @dataclass
30
+ class MCTSNode:
31
+ """MCTS 搜索树节点(带谱系追踪)
32
+
33
+ 关键字段:
34
+ - entry_id: UUID,唯一标识(可映射到 TrajectoryEntry)
35
+ - parent_id: 父节点 entry_id(None = 根节点)
36
+ - formula: 当前节点公式
37
+ - depth: 树深度(根 = 0)
38
+ - children: 子节点列表
39
+ - visits: 访问次数
40
+ - dimension_scores: 5 通道反馈评分
41
+ - overall_score: 综合评分
42
+ - status: 节点状态
43
+ """
44
+ formula: str
45
+ parent_id: Optional[str] = None
46
+ entry_id: str = field(default_factory=lambda: str(uuid.uuid4()))
47
+ depth: int = 0
48
+ children: List["MCTSNode"] = field(default_factory=list)
49
+ visits: int = 0
50
+ dimension_scores: Dict[str, float] = field(default_factory=dict)
51
+ overall_score: float = 0.0
52
+ status: NodeStatus = NodeStatus.PENDING
53
+ is_expanded: bool = False
54
+ metadata: Dict[str, Any] = field(default_factory=dict)
55
+
56
+ # 暂存:UCB1 计算时用的父节点引用(避免 O(n) parent_id 查找)
57
+ _parent_ref: Optional["MCTSNode"] = field(default=None, repr=False, compare=False)
58
+
59
+ def add_child(self, child: "MCTSNode") -> None:
60
+ """添加子节点(同时设置 parent_id 和 _parent_ref)"""
61
+ child.parent_id = self.entry_id
62
+ child._parent_ref = self
63
+ child.depth = self.depth + 1
64
+ self.children.append(child)
65
+ self.is_expanded = True
66
+
67
+ def is_leaf(self) -> bool:
68
+ return len(self.children) == 0
69
+
70
+ def is_root(self) -> bool:
71
+ return self.parent_id is None
72
+
73
+ def ancestors(self) -> List["MCTSNode"]:
74
+ """返回从根到当前节点的祖先链(不含当前节点)"""
75
+ chain = []
76
+ node = self._parent_ref
77
+ while node is not None:
78
+ chain.append(node)
79
+ node = node._parent_ref
80
+ return list(reversed(chain))
81
+
82
+ def lineage_depth(self) -> int:
83
+ """返回谱系深度(从根到当前节点的边数)"""
84
+ return self.depth
85
+
86
+ def ucb1(self, exploration_weight: float = 1.414) -> float:
87
+ """UCB1 评分
88
+
89
+ UCB1 = Q(s) + c * sqrt(ln(N_parent) / N_s)
90
+
91
+ Returns:
92
+ float('inf') 当 visits = 0(优先扩展)
93
+ """
94
+ if self.visits == 0:
95
+ return float("inf")
96
+
97
+ parent = self._parent_ref
98
+ if parent is None or parent.visits == 0:
99
+ return float("inf")
100
+
101
+ exploit = self.overall_score
102
+ explore = exploration_weight * math.sqrt(
103
+ math.log(parent.visits) / self.visits
104
+ )
105
+ return exploit + explore
106
+
107
+ def __repr__(self) -> str:
108
+ preview = self.formula[:50] + "..." if len(self.formula) > 50 else self.formula
109
+ return (
110
+ f"MCTSNode(entry={self.entry_id[:8]}, "
111
+ f"depth={self.depth}, visits={self.visits}, "
112
+ f"score={self.overall_score:.3f}, "
113
+ f"status={self.status.value}, "
114
+ f"formula={preview!r})"
115
+ )
116
+
117
+
118
+ @dataclass
119
+ class MCTSTree:
120
+ """MCTS 搜索树容器
121
+
122
+ vs 旧 mcts_search.py:树结构本身相似,但增加:
123
+ - 完整 entry_id 谱系
124
+ - 节点状态追踪
125
+ - 公式缓存去重
126
+ - entry_id 索引(O(1) 父节点查找)
127
+ """
128
+ root: MCTSNode = field(default_factory=lambda: MCTSNode(
129
+ formula="__ROOT__", depth=-1,
130
+ ))
131
+ formula_cache: Dict[str, MCTSNode] = field(default_factory=dict)
132
+ _entry_index: Dict[str, MCTSNode] = field(default_factory=dict)
133
+ total_iterations: int = 0
134
+
135
+ def add_node(self, node: MCTSNode, parent: Optional[MCTSNode] = None) -> None:
136
+ """添加节点到树
137
+
138
+ Args:
139
+ node: 节点
140
+ parent: 父节点(None = 根节点)
141
+ """
142
+ if parent is None:
143
+ parent = self.root
144
+ parent.add_child(node)
145
+ # 加入公式缓存
146
+ self.formula_cache[node.formula] = node
147
+ # 加入 entry_id 索引
148
+ self._entry_index[node.entry_id] = node
149
+
150
+ def get_by_entry_id(self, entry_id: str) -> Optional[MCTSNode]:
151
+ """按 entry_id 查找节点(O(1) via index)"""
152
+ return self._entry_index.get(entry_id)
153
+
154
+ def get_by_formula(self, formula: str) -> Optional[MCTSNode]:
155
+ """按公式查找节点(O(1) via cache)"""
156
+ return self.formula_cache.get(formula)
157
+
158
+ def all_nodes(self) -> List[MCTSNode]:
159
+ """返回所有节点(DFS)"""
160
+ result = []
161
+ stack = [self.root]
162
+ while stack:
163
+ node = stack.pop()
164
+ if node is not self.root:
165
+ result.append(node)
166
+ stack.extend(node.children)
167
+ return result
168
+
169
+ def leaves(self) -> List[MCTSNode]:
170
+ """返回所有叶子节点"""
171
+ return [n for n in self.all_nodes() if n.is_leaf()]
172
+
173
+ def best_k(self, k: int = 10, metric: str = "overall_score") -> List[MCTSNode]:
174
+ """返回综合评分最高的 k 个节点(按 entry_id 去重)"""
175
+ seen = set()
176
+ unique = []
177
+ nodes = self.all_nodes()
178
+ # 按 metric 降序
179
+ nodes.sort(key=lambda n: getattr(n, metric, 0.0), reverse=True)
180
+ for n in nodes:
181
+ if n.entry_id in seen:
182
+ continue
183
+ seen.add(n.entry_id)
184
+ unique.append(n)
185
+ if len(unique) >= k:
186
+ break
187
+ return unique
188
+
189
+ def stats(self) -> Dict[str, Any]:
190
+ """树统计"""
191
+ nodes = self.all_nodes()
192
+ by_status: Dict[str, int] = {}
193
+ for n in nodes:
194
+ s = n.status.value
195
+ by_status[s] = by_status.get(s, 0) + 1
196
+ return {
197
+ "total_nodes": len(nodes),
198
+ "by_status": by_status,
199
+ "max_depth": max((n.depth for n in nodes), default=0),
200
+ "total_iterations": self.total_iterations,
201
+ }
@@ -0,0 +1,50 @@
1
+ # coding=utf-8
2
+ """
3
+ operator_vocab - 算子词表层
4
+
5
+ 把分散在 3 处的 285 个算子整合成统一接口:
6
+ - L0 Built-in: factor_node/factor_functions/ (157 算子)
7
+ - L0 TA-Lib: factor_node/factor_functions/talib_ops.py (109 算子,需显式 import)
8
+ - L1 Composite: operators/composite_dag.py (20 算子)
9
+
10
+ 主要功能:
11
+ - 统一查询:list_operators / get_operator / get_metadata
12
+ - 算子元数据:12 字段(含 7 个 LLM 友好)
13
+ - Namespace 构建:build_namespace(per-date over() 修复)
14
+ - 端到端评估:evaluate(formula + data → result)
15
+
16
+ 修复 3 个 latent bug:
17
+ 1. ts_corr/ts_cov 的 Series.rolling_corr 不存在
18
+ 2. rank/zscore 全局而非 per-date
19
+ 3. 异常被静默吞掉
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ from QuantNodes.research.quant_alpha.operator_vocab.metadata import (
25
+ OperatorMetadata,
26
+ OperatorCategory,
27
+ )
28
+ from QuantNodes.research.quant_alpha.operator_vocab.config import (
29
+ OperatorVocabConfig,
30
+ )
31
+ from QuantNodes.research.quant_alpha.operator_vocab.vocabulary import (
32
+ OperatorVocab,
33
+ build_namespace,
34
+ list_vocab_operators,
35
+ get_vocab_operator,
36
+ get_vocab_metadata,
37
+ )
38
+
39
+ __all__ = [
40
+ # 主类
41
+ "OperatorVocab",
42
+ "OperatorVocabConfig",
43
+ "OperatorMetadata",
44
+ "OperatorCategory",
45
+ # 便捷函数
46
+ "build_namespace",
47
+ "list_vocab_operators",
48
+ "get_vocab_operator",
49
+ "get_vocab_metadata",
50
+ ]
@@ -0,0 +1,54 @@
1
+ # coding=utf-8
2
+ """
3
+ OperatorVocab 配置 - 控制 namespace 构建与算子查询行为
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ from dataclasses import dataclass, field
9
+ from typing import List, Optional
10
+
11
+
12
+ @dataclass
13
+ class OperatorVocabConfig:
14
+ """OperatorVocab 配置
15
+
16
+ 控制:
17
+ - per-date over() 默认行为(cross_sectional)
18
+ - 启用的算子类别
19
+ - TA-Lib 是否自动加载
20
+ - L0/L1/L2 注册表路径
21
+ """
22
+
23
+ # 截面算子默认行为:True=per-date over(date),False=全局
24
+ # 修复旧 12-lambda namespace 的 BUG 2(rank/zscore 全局错误)
25
+ cross_sectional: bool = True
26
+
27
+ # 启用的算子类别(默认全部)
28
+ enabled_categories: List[str] = field(default_factory=lambda: [
29
+ "point", "time", "section", "multi_section", "talib"
30
+ ])
31
+
32
+ # 是否自动加载 talib_ops(109 算子)
33
+ # 默认 True;如 talib 未安装会自动降级为 False
34
+ talib_enabled: bool = True
35
+
36
+ # eval 沙箱的超时(秒),None 表示不限制
37
+ eval_timeout_seconds: Optional[float] = None
38
+
39
+ # 公式长度上限(字符),None 表示不限制
40
+ # 防止超长公式 DoS
41
+ max_formula_length: Optional[int] = 5000
42
+
43
+ # 公式嵌套深度上限
44
+ # 防止递归嵌套爆炸
45
+ max_formula_depth: int = 20
46
+
47
+ def __post_init__(self):
48
+ # 验证 enabled_categories
49
+ valid = {"point", "time", "section", "multi_section", "talib"}
50
+ for cat in self.enabled_categories:
51
+ if cat not in valid:
52
+ raise ValueError(
53
+ f"Invalid category '{cat}'. Must be one of: {valid}"
54
+ )
@@ -0,0 +1,263 @@
1
+ # coding=utf-8
2
+ """
3
+ 算子元数据 schema - 12 字段(含 7 个 LLM 友好)
4
+
5
+ 扩展自 factor_node/factor_functions/_helpers.py::register_operator 的 5 字段,
6
+ 新增 7 个对 LLM 关键的字段。
7
+
8
+ 字段定义:
9
+ - 基础字段(5 个,对应现有 _OPERATOR_REGISTRY):
10
+ name, category, func, doc, signature, parameters
11
+ - LLM 友好字段(7 个,本文件新增):
12
+ difficulty, category_tags, default_window,
13
+ requires_group_by, output_dtype, examples, composes_with
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ from dataclasses import dataclass, field
19
+ from typing import Any, Callable, Dict, List, Optional
20
+
21
+
22
+ # 与 factor_node.factor_functions._helpers.OperatorCategory 保持一致
23
+ class OperatorCategory:
24
+ """算子类别常量"""
25
+ POINT = "point"
26
+ TIME = "time"
27
+ SECTION = "section"
28
+ MULTI_SECTION = "multi_section"
29
+ TALIB = "talib"
30
+
31
+ @classmethod
32
+ def all(cls) -> List[str]:
33
+ return [cls.POINT, cls.TIME, cls.SECTION, cls.MULTI_SECTION, cls.TALIB]
34
+
35
+ @classmethod
36
+ def is_valid(cls, category: str) -> bool:
37
+ return category in cls.all()
38
+
39
+
40
+ @dataclass
41
+ class OperatorMetadata:
42
+ """算子元数据 — 12 字段 schema
43
+
44
+ 用于:
45
+ - LLM prompt 注入(Alpha-GPT 路线 6)
46
+ - 算子文档自动生成
47
+ - 算子查询/筛选
48
+ - 算子推荐(composes_with)
49
+
50
+ 字段分组:
51
+ - 基础(5):name, category, func, doc, signature, parameters
52
+ - LLM 友好(7):difficulty, category_tags, default_window,
53
+ requires_group_by, output_dtype, examples, composes_with
54
+ """
55
+
56
+ # === 基础字段(5/6) ===
57
+ name: str
58
+ category: str
59
+ func: Optional[Callable] = None
60
+ doc: str = ""
61
+ signature: str = ""
62
+ parameters: List[str] = field(default_factory=list)
63
+
64
+ # === LLM 友好字段(7) ===
65
+ # 难度等级:1=简单(无参/单参),2=中等(2-3 参),3=复杂(4+ 参或嵌套)
66
+ difficulty: int = 1
67
+ # 语义角色标签:central_tendency / dispersion / quantile / polarity /
68
+ # position / transformation / aggregation / groupby
69
+ category_tags: List[str] = field(default_factory=list)
70
+ # 默认窗口建议:时间序列算子的推荐窗口
71
+ default_window: List[int] = field(default_factory=list)
72
+ # 是否需要 group_by(date) 上下文(用于 per-date over() 修复判断)
73
+ requires_group_by: bool = False
74
+ # 输出数据类型:float64 / int64 / bool / object
75
+ output_dtype: str = "float64"
76
+ # few-shot 示例:每项 {"input": ..., "output": ...}
77
+ examples: List[Dict[str, Any]] = field(default_factory=list)
78
+ # 推荐组合的算子名列表
79
+ composes_with: List[str] = field(default_factory=list)
80
+
81
+ def to_dict(self) -> Dict[str, Any]:
82
+ """转为 dict(用于持久化 / LLM 注入)"""
83
+ return {
84
+ "name": self.name,
85
+ "category": self.category,
86
+ "doc": self.doc,
87
+ "signature": self.signature,
88
+ "parameters": list(self.parameters),
89
+ "difficulty": self.difficulty,
90
+ "category_tags": list(self.category_tags),
91
+ "default_window": list(self.default_window),
92
+ "requires_group_by": self.requires_group_by,
93
+ "output_dtype": self.output_dtype,
94
+ "examples": list(self.examples),
95
+ "composes_with": list(self.composes_with),
96
+ }
97
+
98
+ @classmethod
99
+ def from_dict(cls, data: Dict[str, Any]) -> "OperatorMetadata":
100
+ """从 dict 构造"""
101
+ return cls(
102
+ name=data["name"],
103
+ category=data["category"],
104
+ doc=data.get("doc", ""),
105
+ signature=data.get("signature", ""),
106
+ parameters=data.get("parameters", []),
107
+ difficulty=data.get("difficulty", 1),
108
+ category_tags=data.get("category_tags", []),
109
+ default_window=data.get("default_window", []),
110
+ requires_group_by=data.get("requires_group_by", False),
111
+ output_dtype=data.get("output_dtype", "float64"),
112
+ examples=data.get("examples", []),
113
+ composes_with=data.get("composes_with", []),
114
+ )
115
+
116
+ @classmethod
117
+ def from_registry_entry(cls, entry: Dict[str, Any]) -> "OperatorMetadata":
118
+ """从 factor_node 的 _OPERATOR_REGISTRY 条目构造(自动推断 7 字段)
119
+
120
+ Args:
121
+ entry: _OPERATOR_REGISTRY[category][name] 的值,含
122
+ name, category, func, doc, signature, parameters
123
+
124
+ Returns:
125
+ 自动推断 7 字段的 OperatorMetadata
126
+ """
127
+ params = entry.get("parameters", [])
128
+ sig = entry.get("signature", "")
129
+ name = entry["name"]
130
+ category = entry["category"]
131
+
132
+ # 推断 difficulty
133
+ difficulty = _infer_difficulty(params, sig)
134
+
135
+ # 推断 category_tags
136
+ category_tags = _infer_category_tags(name, category, params)
137
+
138
+ # 推断 default_window
139
+ default_window = _infer_default_window(name, params)
140
+
141
+ # 推断 requires_group_by
142
+ requires_group_by = _infer_requires_group_by(name, category)
143
+
144
+ # 推断 output_dtype
145
+ output_dtype = _infer_output_dtype(name, category, params)
146
+
147
+ return cls(
148
+ name=name,
149
+ category=category,
150
+ func=entry.get("func"),
151
+ doc=entry.get("doc", ""),
152
+ signature=sig,
153
+ parameters=params,
154
+ difficulty=difficulty,
155
+ category_tags=category_tags,
156
+ default_window=default_window,
157
+ requires_group_by=requires_group_by,
158
+ output_dtype=output_dtype,
159
+ examples=[],
160
+ composes_with=[],
161
+ )
162
+
163
+
164
+ def _infer_difficulty(params: List[str], signature: str) -> int:
165
+ """推断难度等级
166
+
167
+ - 1:0-1 参数
168
+ - 2:2-3 参数
169
+ - 3:4+ 参数 或嵌套调用
170
+ """
171
+ n = len([p for p in params if p not in ("self", "kwargs", "args")])
172
+ if n <= 1:
173
+ return 1
174
+ if n <= 3:
175
+ return 2
176
+ return 3
177
+
178
+
179
+ def _infer_category_tags(name: str, category: str, params: List[str]) -> List[str]:
180
+ """推断语义角色标签
181
+
182
+ 基于算子名前缀和类别:
183
+ - mean/median/sum → central_tendency
184
+ - std/var/skew/kurt → dispersion
185
+ - quantile/percentile → quantile
186
+ - sign/abs → polarity
187
+ - argmax/argmin → position
188
+ - rank/zscore/winsorize → transformation
189
+ """
190
+ tags = []
191
+ name_lower = name.lower()
192
+
193
+ if any(k in name_lower for k in ("mean", "median", "sum", "sma", "ema")):
194
+ tags.append("central_tendency")
195
+ if any(k in name_lower for k in ("std", "var", "skew", "kurt", "vol")):
196
+ tags.append("dispersion")
197
+ if any(k in name_lower for k in ("quantile", "percentile", "qtl")):
198
+ tags.append("quantile")
199
+ if any(k in name_lower for k in ("sign", "abs", "signedpower")):
200
+ tags.append("polarity")
201
+ if any(k in name_lower for k in ("argmax", "argmin", "idxmax", "idxmin")):
202
+ tags.append("position")
203
+ if any(k in name_lower for k in ("rank", "zscore", "winsorize", "scale", "normalize")):
204
+ tags.append("transformation")
205
+ if any(k in name_lower for k in ("corr", "cov", "regress", "beta")):
206
+ tags.append("correlation")
207
+ if any(k in name_lower for k in ("delta", "diff", "pct_change", "return", "roc")):
208
+ tags.append("momentum")
209
+ if any(k in name_lower for k in ("lag", "lead", "shift", "delay", "ref")):
210
+ tags.append("shift")
211
+
212
+ if category == OperatorCategory.SECTION:
213
+ tags.append("cross_sectional")
214
+ elif category == OperatorCategory.MULTI_SECTION:
215
+ tags.append("groupby")
216
+ elif category == OperatorCategory.TIME:
217
+ tags.append("time_series")
218
+ elif category == OperatorCategory.POINT:
219
+ tags.append("pointwise")
220
+
221
+ return list(set(tags))
222
+
223
+
224
+ def _infer_default_window(name: str, params: List[str]) -> List[int]:
225
+ """推断默认窗口建议
226
+
227
+ 时序算子默认 [5, 10, 20, 60]
228
+ """
229
+ name_lower = name.lower()
230
+ if any(k in name_lower for k in (
231
+ "ts_", "rolling_", "ewm_", "expanding_", "decay_", "lag", "shift", "delta"
232
+ )):
233
+ return [5, 10, 20, 60]
234
+ return []
235
+
236
+
237
+ def _infer_requires_group_by(name: str, category: str) -> bool:
238
+ """推断是否需要 group_by(date) 上下文
239
+
240
+ 截面算子(rank/zscore/winsorize/normalize/IndNeutralize/aggregate)需要。
241
+ """
242
+ name_lower = name.lower()
243
+ if category == OperatorCategory.SECTION:
244
+ return True
245
+ if category == OperatorCategory.MULTI_SECTION:
246
+ return True
247
+ if any(k in name_lower for k in ("rank", "zscore", "winsorize", "normalize", "neutralize")):
248
+ return True
249
+ return False
250
+
251
+
252
+ def _infer_output_dtype(name: str, category: str, params: List[str]) -> str:
253
+ """推断输出数据类型
254
+
255
+ - argmax/argmin/sign/condition → int64 或 bool
256
+ - 其它 → float64
257
+ """
258
+ name_lower = name.lower()
259
+ if any(k in name_lower for k in ("argmax", "argmin", "idxmax", "idxmin", "row_number")):
260
+ return "int64"
261
+ if any(k in name_lower for k in ("sign", "is_", "where", "cond", "isnull", "notnull")):
262
+ return "bool"
263
+ return "float64"