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,493 @@
1
+ # coding=utf-8
2
+ """
3
+ alpha_evaluate.py - Alpha 公式评估工具(包 M4 PolarsAlphaCalculator)
4
+
5
+ Alpha-GPT 工作流的【第 3 阶段:Evaluator】核心工具。
6
+ 把 LLM 生成的 polars 公式批量评估为 IC / IR / decay 等量化指标。
7
+
8
+ 复用:
9
+ - M4 PolarsAlphaCalculator(M1-M4 适配器)
10
+ - M1 OperatorVocab(162 算子白名单校验)
11
+
12
+ Usage (作为 nanobot tool)::
13
+
14
+ from QuantNodes.agent.tools.alpha_evaluate import AlphaEvaluateTool
15
+ tool = AlphaEvaluateTool()
16
+ result = await tool.execute(
17
+ formulas=["rank(-ts_mean(returns, 20))"],
18
+ data=df,
19
+ forward_returns=[1, 5, 20],
20
+ )
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ import logging
26
+ from pathlib import Path
27
+ from typing import Any, Dict, List, Optional, Sequence, Union
28
+
29
+ import numpy as np
30
+
31
+ from .base import Tool
32
+
33
+ logger = logging.getLogger(__name__)
34
+
35
+
36
+ class AlphaEvaluateTool(Tool):
37
+ """Alpha 公式评估工具
38
+
39
+ 批量评估一组 polars 公式,返回 IC / IR / decay 指标。
40
+ 输入支持:data_path(parquet/csv)或已加载的 polars.DataFrame。
41
+ """
42
+
43
+ def __init__(self) -> None:
44
+ pass
45
+
46
+ @property
47
+ def name(self) -> str:
48
+ return "alpha_evaluate"
49
+
50
+ @property
51
+ def description(self) -> str:
52
+ return (
53
+ "批量评估 alpha 公式。"
54
+ "输入 formulas 列表(polars 表达式字符串)和数据,"
55
+ "返回每个公式的 IC / IR / ic_decay 指标。"
56
+ "可选:forward_returns 前瞻期列表(默认 [1])。"
57
+ )
58
+
59
+ @property
60
+ def parameters(self) -> Dict[str, Any]:
61
+ return {
62
+ "type": "object",
63
+ "properties": {
64
+ "formulas": {
65
+ "type": "array",
66
+ "items": {"type": "string"},
67
+ "description": "待评估的 polars 公式列表",
68
+ },
69
+ "data_path": {
70
+ "type": "string",
71
+ "description": "数据路径(parquet/csv);若与 data 同时给出,优先用 data",
72
+ },
73
+ "forward_returns": {
74
+ "type": "array",
75
+ "items": {"type": "integer"},
76
+ "default": [1],
77
+ "description": "前瞻期列表(默认 [1])",
78
+ },
79
+ "date_column": {
80
+ "type": "string",
81
+ "default": "date",
82
+ "description": "日期列名",
83
+ },
84
+ "code_column": {
85
+ "type": "string",
86
+ "default": "code",
87
+ "description": "股票代码列名",
88
+ },
89
+ "max_workers": {
90
+ "type": "integer",
91
+ "default": 4,
92
+ "description": "并行评估的最大 worker 数(默认 4)",
93
+ },
94
+ },
95
+ "required": ["formulas"],
96
+ }
97
+
98
+ @property
99
+ def read_only(self) -> bool:
100
+ return True
101
+
102
+ async def execute(
103
+ self,
104
+ formulas: Sequence[str],
105
+ data_path: Optional[str] = None,
106
+ forward_returns: Sequence[int] = (1,),
107
+ date_column: str = "date",
108
+ code_column: str = "code",
109
+ max_workers: int = 4,
110
+ data: Any = None,
111
+ **kwargs: Any,
112
+ ) -> Dict[str, Any]:
113
+ """批量评估公式
114
+
115
+ Args:
116
+ formulas: 待评估的 polars 表达式字符串列表
117
+ data_path: 数据路径(与 data 互斥)
118
+ forward_returns: 前瞻期列表
119
+ date_column: 日期列名
120
+ code_column: 代码列名
121
+ max_workers: 并行 worker 数
122
+ data: 已加载的 polars.DataFrame(用于测试场景)
123
+ **kwargs: 兼容 nanobot 框架的额外参数
124
+
125
+ Returns:
126
+ {
127
+ "evaluations": [
128
+ {
129
+ "formula": "rank(-ts_mean(returns, 20))",
130
+ "status": "success" | "failed",
131
+ "metrics": {ic_mean, ic_std, ir, ic_decay: {1: ..., 5: ...}},
132
+ "error_msg": str | None
133
+ }
134
+ ],
135
+ "summary": {total, success, failed, avg_ir, best_ir}
136
+ }
137
+ """
138
+ try:
139
+ import polars as pl
140
+ from QuantNodes.research.quant_alpha.adapters import (
141
+ PolarsAlphaCalculator,
142
+ )
143
+
144
+ df = self._resolve_data(data, data_path, date_column, code_column)
145
+ if df is None:
146
+ return self._err("No data provided (need data_path or data)")
147
+
148
+ forward_returns_dict = self._build_forward_returns(
149
+ df, list(forward_returns), date_column, code_column,
150
+ )
151
+
152
+ calc = PolarsAlphaCalculator(
153
+ data=df,
154
+ forward_returns=forward_returns_dict,
155
+ date_column=date_column,
156
+ code_column=code_column,
157
+ )
158
+
159
+ from QuantNodes.research.quant_alpha.adapters.expression import (
160
+ expression_to_formula,
161
+ )
162
+ from QuantNodes.research.quant_alpha.adapters.expression import Feature
163
+
164
+ evaluations = []
165
+ for formula in formulas:
166
+ evaluations.append(self._eval_one(calc, formula))
167
+
168
+ return self._summarize(evaluations)
169
+ except Exception as exc:
170
+ logger.exception("alpha_evaluate failed")
171
+ return self._err(str(exc))
172
+
173
+ def _eval_one(
174
+ self,
175
+ calc: Any,
176
+ formula: str,
177
+ ) -> Dict[str, Any]:
178
+ """评估单个公式"""
179
+ try:
180
+ expr = self._parse_simple_formula(formula)
181
+ offsets = sorted(calc.forward_returns.keys())
182
+ ic_means = {}
183
+ for offset in offsets:
184
+ arr = calc.calc_single_IC_ret(expr, ret_offset=offset)
185
+ arr = arr[~np.isnan(arr)]
186
+ ic_means[offset] = float(np.mean(arr)) if arr.size else 0.0
187
+
188
+ primary_offset = offsets[0]
189
+ primary_arr = calc.calc_single_IC_ret(expr, ret_offset=primary_offset)
190
+ primary_arr = primary_arr[~np.isnan(primary_arr)]
191
+ ic_mean = float(np.mean(primary_arr)) if primary_arr.size else 0.0
192
+ ic_std = float(np.std(primary_arr)) if primary_arr.size else 0.0
193
+ ir = ic_mean / ic_std if ic_std > 1e-12 else 0.0
194
+
195
+ return {
196
+ "formula": formula,
197
+ "status": "success",
198
+ "metrics": {
199
+ "ic_mean": ic_mean,
200
+ "ic_std": ic_std,
201
+ "ir": ir,
202
+ "ic_decay": {str(k): v for k, v in ic_means.items()},
203
+ },
204
+ "error_msg": None,
205
+ }
206
+ except Exception as exc:
207
+ return {
208
+ "formula": formula,
209
+ "status": "failed",
210
+ "metrics": {},
211
+ "error_msg": str(exc),
212
+ }
213
+
214
+ @staticmethod
215
+ def _parse_simple_formula(formula: str):
216
+ """把简单字符串公式解析为 Expression(轻量 parser,仅支持算子形式)
217
+
218
+ 支持的形态:
219
+ - "Feature('close')" → Feature('close')
220
+ - "Ref(Feature('close'), 2)" → Ref(Feature('close'), 2)
221
+ - "-x" → Neg(x) (unary negation)
222
+ - "rank(x)" / "ts_mean(x, 5)" / "ts_zscore(x, 20)" 等
223
+ - 二元: "Add(a, b)" / "Sub(a, b)" / "Mul(a, b)" / "Div(a, b)"
224
+ - Literal: "1e-12"
225
+ - 简写字段名 "close" → Feature('close')
226
+
227
+ 重算子写在字符串外层,内层是子公式字符串(递归)。
228
+ """
229
+ from QuantNodes.research.quant_alpha.adapters.expression import (
230
+ Literal,
231
+ Ref,
232
+ Feature,
233
+ BinaryOp,
234
+ UnaryOp,
235
+ RollingOp,
236
+ )
237
+ import re
238
+
239
+ formula = formula.strip()
240
+
241
+ if re.fullmatch(r"-?\d+(?:\.\d+)?(?:e-?\d+)?", formula):
242
+ return Literal(float(formula))
243
+
244
+ if formula.startswith("-"):
245
+ inner = formula[1:].strip()
246
+ return UnaryOp(AlphaEvaluateTool._parse_simple_formula(inner), "neg")
247
+
248
+ m = re.fullmatch(r"Feature\(['\"]([\w_]+)['\"]\)", formula)
249
+ if m:
250
+ return Feature(m.group(1))
251
+
252
+ m = re.fullmatch(r"Ref\(Feature\(['\"]([\w_]+)['\"]\),\s*(\d+)\)", formula)
253
+ if m:
254
+ return Ref(Feature(m.group(1)), int(m.group(2)))
255
+
256
+ # Ref(close, 1) 格式
257
+ m = re.fullmatch(r"Ref\((\w+),\s*(\d+)\)", formula)
258
+ if m:
259
+ return Ref(Feature(m.group(1)), int(m.group(2)))
260
+
261
+ # close.shift(1) 格式
262
+ m = re.fullmatch(r"(\w+)\.shift\((\d+)\)", formula)
263
+ if m:
264
+ return Ref(Feature(m.group(1)), int(m.group(2)))
265
+
266
+ # 简写字段名: "close", "vol" 等
267
+ # 特殊处理 "returns" → (close - delay(close, 1)) / delay(close, 1)
268
+ if formula == "returns":
269
+ close_feat = Feature("close")
270
+ delay1 = Ref(close_feat, 1)
271
+ return BinaryOp(BinaryOp(close_feat, delay1, "sub"), delay1, "div")
272
+
273
+ if re.fullmatch(r"[a-zA-Z_][a-zA-Z0-9_]*", formula):
274
+ return Feature(formula)
275
+
276
+ m = re.fullmatch(r"([\w_]+)\((.+)\)", formula, re.DOTALL)
277
+ if m:
278
+ op = m.group(1)
279
+ inner = m.group(2)
280
+ args = split_args(inner)
281
+ parsed_args = [AlphaEvaluateTool._parse_simple_formula(a) for a in args]
282
+
283
+ if op in {"Add", "Sub", "Mul", "Div", "Greater", "Less",
284
+ "add", "sub", "mul", "div", "greater", "less"}:
285
+ op_key = op.lower()
286
+ cls = {
287
+ "add": lambda a, b: BinaryOp(a, b, "add"),
288
+ "sub": lambda a, b: BinaryOp(a, b, "sub"),
289
+ "mul": lambda a, b: BinaryOp(a, b, "mul"),
290
+ "div": lambda a, b: BinaryOp(a, b, "div"),
291
+ "greater": lambda a, b: BinaryOp(a, b, "gt"),
292
+ "less": lambda a, b: BinaryOp(a, b, "lt"),
293
+ }[op_key]
294
+ if len(parsed_args) != 2:
295
+ raise ValueError(f"{op} needs 2 args, got {len(parsed_args)}")
296
+ return cls(parsed_args[0], parsed_args[1])
297
+
298
+ window_ops = {
299
+ "ts_mean": "mean", "mean": "mean", "Mean": "mean",
300
+ "ts_std": "std", "std": "std", "Std": "std",
301
+ "ts_sum": "sum", "sum": "sum", "Sum": "sum",
302
+ "ts_max": "max", "max": "max", "Max": "max",
303
+ "ts_min": "min", "min": "min", "Min": "min",
304
+ "ts_zscore": "zscore",
305
+ "ts_rank": "rank",
306
+ "ts_median": "median", "median": "median",
307
+ "ts_skew": "skew", "skew": "skew",
308
+ "ts_kurt": "kurt", "kurt": "kurt",
309
+ "ts_var": "var", "var": "var",
310
+ "delta": "delta", "Delta": "delta",
311
+ "ts_delta": "delta",
312
+ "ts_decay_linear": "decay_linear",
313
+ }
314
+ if op in window_ops:
315
+ if len(parsed_args) != 2:
316
+ raise ValueError(f"{op} needs 2 args")
317
+ return RollingOp(parsed_args[0], int(float(parsed_args[1].value)), window_ops[op])
318
+
319
+ # ts_corr/ts_cov: 3 args (x, y, window) -> RollingOp on combined
320
+ if op in {"ts_corr", "ts_cov"}:
321
+ if len(parsed_args) != 3:
322
+ raise ValueError(f"{op} needs 3 args (x, y, window)")
323
+ window = int(float(parsed_args[2].value))
324
+ return RollingOp(parsed_args[0], window, "corr" if op == "ts_corr" else "cov")
325
+
326
+ cross_sectional_ops = {"abs": "abs", "log": "log", "sqrt": "sqrt", "sign": "sign"}
327
+ if op in cross_sectional_ops:
328
+ if len(parsed_args) != 1:
329
+ raise ValueError(f"{op} needs 1 arg")
330
+ return UnaryOp(cross_sectional_ops[op], parsed_args[0])
331
+
332
+ if op in {"Abs", "Log", "Sqrt", "Sign"}:
333
+ return UnaryOp(op.lower(), parsed_args[0])
334
+
335
+ # rank (cross-sectional) - treat as unary "rank" op
336
+ if op in {"rank", "Rank"}:
337
+ if len(parsed_args) != 1:
338
+ raise ValueError(f"{op} needs 1 arg")
339
+ return UnaryOp(parsed_args[0], "rank")
340
+
341
+ # zscore (cross-sectional)
342
+ if op in {"zscore", "Zscore"}:
343
+ if len(parsed_args) != 1:
344
+ raise ValueError(f"{op} needs 1 arg")
345
+ return UnaryOp(parsed_args[0], "zscore")
346
+
347
+ # winsorize
348
+ if op in {"winsorize", "Winsorize"}:
349
+ if len(parsed_args) != 1:
350
+ raise ValueError(f"{op} needs 1 arg")
351
+ return UnaryOp(parsed_args[0], "winsorize")
352
+
353
+ # signedpower
354
+ if op in {"signedpower", "SignedPower"}:
355
+ if len(parsed_args) != 2:
356
+ raise ValueError(f"{op} needs 2 args")
357
+ return BinaryOp(parsed_args[0], parsed_args[1], "signedpower")
358
+
359
+ # IndNeutralize - treat as unary passthrough (no industry data)
360
+ if op in {"IndNeutralize", "indneutralize"}:
361
+ if len(parsed_args) != 1:
362
+ raise ValueError(f"{op} needs 1 arg")
363
+ return parsed_args[0]
364
+
365
+ # returns shorthand: returns = (close - delay(close, 1)) / delay(close, 1)
366
+ if op in {"returns", "Returns"}:
367
+ if len(parsed_args) != 1:
368
+ raise ValueError(f"{op} needs 1 arg")
369
+ feat = parsed_args[0]
370
+ delay1 = Ref(feat, 1)
371
+ return BinaryOp(BinaryOp(feat, delay1, "sub"), delay1, "div")
372
+
373
+ # delay(x, n) → Ref(x, n)
374
+ if op in {"delay", "Delay"}:
375
+ if len(parsed_args) != 2:
376
+ raise ValueError(f"{op} needs 2 args")
377
+ return Ref(parsed_args[0], int(float(parsed_args[1].value)))
378
+
379
+ raise ValueError(f"Cannot parse formula: {formula!r}")
380
+
381
+ @staticmethod
382
+ def _summarize(evaluations: List[Dict[str, Any]]) -> Dict[str, Any]:
383
+ success = [e for e in evaluations if e["status"] == "success"]
384
+ irs = [e["metrics"].get("ir", 0.0) for e in success]
385
+ return {
386
+ "evaluations": evaluations,
387
+ "summary": {
388
+ "total": len(evaluations),
389
+ "success": len(success),
390
+ "failed": len(evaluations) - len(success),
391
+ "avg_ir": float(np.mean(irs)) if irs else 0.0,
392
+ "best_ir": float(np.max(irs)) if irs else 0.0,
393
+ },
394
+ }
395
+
396
+ @staticmethod
397
+ def _resolve_data(
398
+ data: Any,
399
+ data_path: Optional[str],
400
+ date_column: str,
401
+ code_column: str,
402
+ ) -> Any:
403
+ import polars as pl
404
+
405
+ if data is not None:
406
+ return data
407
+ if data_path is None:
408
+ return None
409
+ p = Path(data_path)
410
+ if not p.exists():
411
+ raise FileNotFoundError(f"data not found: {data_path}")
412
+ if p.suffix == ".parquet":
413
+ return pl.read_parquet(p)
414
+ if p.suffix == ".csv":
415
+ df = pl.read_csv(p)
416
+ if date_column in df.columns and df[date_column].dtype == pl.Utf8:
417
+ df = df.with_columns(pl.col(date_column).str.to_date())
418
+ return df
419
+ raise ValueError(f"Unsupported data format: {p.suffix}")
420
+
421
+ @staticmethod
422
+ def _build_forward_returns(
423
+ df: Any,
424
+ forward_returns: List[int],
425
+ date_column: str,
426
+ code_column: str,
427
+ ) -> Dict[int, Any]:
428
+ """从 close 计算前瞻 N 日收益
429
+
430
+ 优化:如果 DataFrame 已有预计算列 (_fwd_ret_{n}d),直接使用。
431
+ """
432
+ import polars as pl
433
+
434
+ if "close" not in df.columns:
435
+ raise ValueError("data must have 'close' column for forward returns")
436
+
437
+ out: Dict[int, Any] = {}
438
+ for offset in forward_returns:
439
+ col_name = f"_fwd_ret_{offset}d"
440
+ # 优先使用预计算列
441
+ if col_name in df.columns:
442
+ out[offset] = df[col_name]
443
+ else:
444
+ # 回退:从 close 计算
445
+ sorted_df = df.sort([code_column, date_column])
446
+ ret = sorted_df.with_columns(
447
+ pl.col("close").shift(-offset).over(code_column).alias("_next_close")
448
+ ).with_columns(
449
+ ((pl.col("_next_close") - pl.col("close")) / pl.col("close")).alias(col_name)
450
+ )[col_name]
451
+ out[offset] = ret
452
+ return out
453
+
454
+ @staticmethod
455
+ def _err(msg: str) -> Dict[str, Any]:
456
+ return {"evaluations": [], "summary": {"error": msg}}
457
+
458
+
459
+ def split_args(s: str) -> List[str]:
460
+ """Split a function-argument string by top-level commas, respecting parens/quotes."""
461
+ parts: List[str] = []
462
+ depth = 0
463
+ in_str: Optional[str] = None
464
+ buf: List[str] = []
465
+ for ch in s:
466
+ if in_str:
467
+ buf.append(ch)
468
+ if ch == in_str:
469
+ in_str = None
470
+ continue
471
+ if ch in ('"', "'"):
472
+ in_str = ch
473
+ buf.append(ch)
474
+ continue
475
+ if ch == "(":
476
+ depth += 1
477
+ buf.append(ch)
478
+ continue
479
+ if ch == ")":
480
+ depth -= 1
481
+ buf.append(ch)
482
+ continue
483
+ if ch == "," and depth == 0:
484
+ parts.append("".join(buf).strip())
485
+ buf = []
486
+ continue
487
+ buf.append(ch)
488
+ if buf:
489
+ parts.append("".join(buf).strip())
490
+ return parts
491
+
492
+
493
+ __all__ = ["AlphaEvaluateTool", "split_args"]