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,540 @@
1
+ # coding=utf-8
2
+ """
3
+ mcts/search.py - MCTS 因子搜索主类(UCB1 + 5 通道反馈 + 谱系追踪)
4
+
5
+ vs 旧 mcts_search.py.MCTSSearch:
6
+ - 旧:UCB1 + 7 硬编码 EXTENSION_OPS + 无谱系
7
+ - 新:UCB1 + 26 动态操作 + 5 通道反馈 + 谱系追踪 + 公式缓存
8
+
9
+ 返回 MCTSSearchResult 含谱系信息(可映射到 TrajectoryPool)
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import logging
15
+ import random
16
+ import time
17
+ from dataclasses import dataclass, field
18
+ from typing import Any, Dict, List, Optional, Tuple
19
+
20
+ import polars as pl
21
+
22
+ from QuantNodes.core.feedback import FactorFeedback
23
+ from QuantNodes.research.quant_alpha.mcts.cache import MCTSCache, MCTSCacheConfig
24
+ from QuantNodes.research.quant_alpha.mcts.extension_ops import (
25
+ ExtensionOpPool,
26
+ )
27
+ from QuantNodes.research.quant_alpha.mcts.feedback import (
28
+ MCTSFeedbackConfig,
29
+ collect_all_channels,
30
+ )
31
+ from QuantNodes.research.quant_alpha.mcts.tree import (
32
+ MCTSTree,
33
+ MCTSNode,
34
+ NodeStatus,
35
+ )
36
+ from QuantNodes.research.quant_alpha.operator_vocab import OperatorVocab
37
+
38
+ logger = logging.getLogger(__name__)
39
+
40
+
41
+ @dataclass
42
+ class MCTSSearchResult:
43
+ """MCTS 搜索结果(含谱系)"""
44
+ tree: MCTSTree
45
+ valid_nodes: List[MCTSNode] = field(default_factory=list)
46
+ best_k_nodes: List[MCTSNode] = field(default_factory=list)
47
+ elapsed_seconds: float = 0.0
48
+ total_iterations: int = 0
49
+
50
+ # 统计
51
+ formula_count: int = 0
52
+ valid_count: int = 0
53
+ rejected_count: int = 0
54
+ pruned_count: int = 0
55
+
56
+ # 反馈缓存(用于分析失败模式)
57
+ feedback_cache: Dict[str, FactorFeedback] = field(default_factory=dict)
58
+
59
+
60
+ @dataclass
61
+ class MCTSSearchConfig:
62
+ """MCTS 搜索配置"""
63
+ iterations: int = 50
64
+ exploration_weight: float = 1.414 # UCB1 c 参数
65
+ max_depth: int = 5 # 树最大深度(防止无限嵌套)
66
+ seed: int = 42
67
+ feedback_config: MCTSFeedbackConfig = field(default_factory=MCTSFeedbackConfig)
68
+ # 控制:是否启用谱系追踪(用于 M3+ TrajectoryPool 集成)
69
+ enable_lineage: bool = True
70
+ # 缓存配置
71
+ cache_config: Optional[MCTSCacheConfig] = None
72
+ # IC/IR 配置
73
+ compute_ic_ir: bool = True
74
+ forward_returns: Tuple[int, ...] = (1, 5, 20)
75
+ date_column: str = "date"
76
+ code_column: str = "code"
77
+ # 互信息去重阈值
78
+ dedup_threshold: float = 0.7
79
+ # PR-5: 结构化逻辑与 LLM 客户端(用于一致性评分)
80
+ structured_logic: Optional[Any] = None
81
+ llm_client: Optional[Any] = None
82
+ # Tier 4 (feature/thinking-chain): 算子先验 + 混合权重
83
+ op_prior: Optional[Any] = None # OpPrior 实例
84
+ prior_mix: float = 0.5 # 0.0=纯均匀, 1.0=纯先验
85
+
86
+
87
+ class MCTSSearch:
88
+ """MCTS 因子搜索(基于 OperatorVocab + 5 通道反馈)"""
89
+
90
+ def __init__(
91
+ self,
92
+ vocab: Optional[OperatorVocab] = None,
93
+ op_pool: Optional[ExtensionOpPool] = None,
94
+ config: Optional[MCTSSearchConfig] = None,
95
+ cache: Optional[MCTSCache] = None,
96
+ ):
97
+ self.vocab = vocab or OperatorVocab.default()
98
+ self.op_pool = op_pool or ExtensionOpPool(vocab=self.vocab)
99
+ self.config = config or MCTSSearchConfig()
100
+ self.rng = random.Random(self.config.seed)
101
+ self.cache = cache
102
+
103
+ # 统计
104
+ self._tree: Optional[MCTSTree] = None
105
+ self._formula_cache: Dict[str, pl.Series] = {}
106
+ self._feedback_cache: Dict[str, FactorFeedback] = {}
107
+
108
+ def search(
109
+ self,
110
+ data: pl.DataFrame,
111
+ seed_formulas: Optional[List[str]] = None,
112
+ date_column: str = "date",
113
+ code_column: str = "code",
114
+ forward_return_column: str = "forward_return",
115
+ ) -> MCTSSearchResult:
116
+ """执行 MCTS 搜索
117
+
118
+ Args:
119
+ data: 行情数据
120
+ seed_formulas: 种子公式(可选)
121
+ date_column: 日期列名
122
+ code_column: 股票代码列名
123
+ forward_return_column: 前瞻收益率列名
124
+
125
+ Returns:
126
+ MCTSSearchResult(含树、valid_nodes、best_k_nodes)
127
+ """
128
+ start_time = time.time()
129
+ config = self.config
130
+
131
+ # 1. 加载共享缓存
132
+ if self.cache is not None:
133
+ self.cache.load(data)
134
+ self._formula_cache = self.cache._formula_cache
135
+ self._feedback_cache = self.cache._feedback_cache
136
+
137
+ # 2. 初始化树
138
+ tree = MCTSTree()
139
+ self._tree = tree
140
+ if self.cache is None:
141
+ self._formula_cache.clear()
142
+ self._feedback_cache.clear()
143
+
144
+ # 3. 注入种子公式
145
+ available_cols = [
146
+ c for c in data.columns
147
+ if c not in (date_column, code_column, forward_return_column)
148
+ ]
149
+ if seed_formulas is None:
150
+ seed_formulas = self.op_pool.get_seed_formulas(available_cols)
151
+
152
+ for formula in seed_formulas:
153
+ if formula in tree.formula_cache:
154
+ continue
155
+ node = MCTSNode(formula=formula, depth=0)
156
+ tree.add_node(node, parent=tree.root)
157
+
158
+ # 4. MCTS 主循环
159
+ for iteration in range(config.iterations):
160
+ # 4.1 SELECT: UCB1 选择
161
+ leaf = self._select(tree.root)
162
+
163
+ # 4.2 EXPAND: 生成子节点
164
+ if not leaf.is_expanded and leaf.depth < config.max_depth:
165
+ new_node = self._expand(leaf, data, available_cols)
166
+ if new_node is not None:
167
+ leaf = new_node
168
+
169
+ # 4.3 EVALUATE: 5 通道反馈 + IC/IR
170
+ self._evaluate(leaf, data, date_column, forward_return_column)
171
+
172
+ # 4.4 BACKUP: 回传评分
173
+ self._backpropagate(leaf)
174
+
175
+ # 5. 保存共享缓存
176
+ if self.cache is not None:
177
+ self.cache.save()
178
+
179
+ # 6. 收集结果
180
+ tree.total_iterations = config.iterations
181
+ valid_nodes = [
182
+ n for n in tree.all_nodes()
183
+ if n.status == NodeStatus.EVALUATED and n.overall_score > 0
184
+ ]
185
+ best_k = tree.best_k(k=10, metric="overall_score")
186
+
187
+ # 7. 互信息去重
188
+ if hasattr(config, 'dedup_threshold') and config.dedup_threshold < 1.0:
189
+ try:
190
+ from QuantNodes.research.quant_alpha.evaluation.evaluators.polars_evaluator import (
191
+ deduplicate_mutual_ic,
192
+ FactorMetrics,
193
+ )
194
+
195
+ def get_values(node: MCTSNode) -> Optional[Any]:
196
+ try:
197
+ return self.vocab.evaluate(node.formula, data)
198
+ except Exception:
199
+ return None
200
+
201
+ # 转换为 FactorMetrics 格式用于去重
202
+ metrics_list = [
203
+ FactorMetrics(
204
+ formula_id=n.entry_id,
205
+ status="success",
206
+ overall_score=n.overall_score,
207
+ ic_mean=n.metadata.get("ic_mean", 0.0),
208
+ ir=n.metadata.get("ir", 0.0),
209
+ )
210
+ for n in best_k
211
+ ]
212
+
213
+ deduped = deduplicate_mutual_ic(
214
+ metrics_list,
215
+ get_values,
216
+ threshold=config.dedup_threshold,
217
+ )
218
+
219
+ # 重建 best_k
220
+ deduped_ids = {m.formula_id for m in deduped}
221
+ best_k = [n for n in best_k if n.entry_id in deduped_ids]
222
+
223
+ except Exception as e:
224
+ logger.warning("MCTS 互信息去重失败: %s", e)
225
+
226
+ elapsed = time.time() - start_time
227
+ stats = tree.stats()
228
+
229
+ return MCTSSearchResult(
230
+ tree=tree,
231
+ valid_nodes=valid_nodes,
232
+ best_k_nodes=best_k,
233
+ elapsed_seconds=elapsed,
234
+ total_iterations=config.iterations,
235
+ formula_count=stats["total_nodes"],
236
+ valid_count=len(valid_nodes),
237
+ rejected_count=stats["by_status"].get("rejected", 0),
238
+ pruned_count=stats["by_status"].get("pruned", 0),
239
+ feedback_cache=self._feedback_cache,
240
+ )
241
+
242
+ def _select(self, root: MCTSNode) -> MCTSNode:
243
+ """UCB1 选择最有潜力的叶子节点
244
+
245
+ 优化:优先选择高 IC/IR 的节点,同时保持探索性。
246
+ """
247
+ node = root
248
+ while node.children:
249
+ # 选择 UCB1 最大的子节点
250
+ unvisited = [c for c in node.children if c.visits == 0]
251
+ if unvisited:
252
+ # 优先选择高 IC/IR 的未访问节点
253
+ def _score(n: MCTSNode) -> float:
254
+ ic_ir = n.metadata.get("ir", 0.0)
255
+ return abs(ic_ir) if ic_ir != 0.0 else 0.0
256
+
257
+ # 50% 概率选择高 IC/IR,50% 概率随机
258
+ if self.rng.random() < 0.5:
259
+ return max(unvisited, key=_score)
260
+ else:
261
+ return self.rng.choice(unvisited)
262
+ # 全已访问:选 UCB1 最大
263
+ best = max(node.children, key=lambda c: c.ucb1(self.config.exploration_weight))
264
+ node = best
265
+ return node
266
+
267
+ def _expand(
268
+ self,
269
+ node: MCTSNode,
270
+ data: pl.DataFrame,
271
+ available_cols: List[str],
272
+ ) -> Optional[MCTSNode]:
273
+ """扩展节点:生成子公式
274
+
275
+ 优化:优先使用高 IC/IR 的节点作为父节点,优先选择有效算子。
276
+
277
+ Returns:
278
+ 新 MCTSNode,None = 公式无效或已存在
279
+ """
280
+ if node.formula == "__ROOT__":
281
+ # 根节点:已经添加种子节点,无需扩展
282
+ return None
283
+
284
+ # 随机选一个扩展操作(Tier 4: 加权采样 if OpPrior configured)
285
+ try:
286
+ if self.config.op_prior is not None:
287
+ op = self.op_pool.sample_weighted(
288
+ op_prior=self.config.op_prior,
289
+ mix_ratio=getattr(self.config, 'prior_mix', 0.5),
290
+ )
291
+ else:
292
+ op = self.op_pool.sample()
293
+ except ValueError:
294
+ return None
295
+
296
+ # 选窗口
297
+ if op.requires_window:
298
+ w = self.op_pool.sample_window()
299
+ else:
300
+ w = None
301
+
302
+ # 选第二输入(仅二元算子)
303
+ if op.max_inputs == 2:
304
+ # 优先选择与当前公式不同的列
305
+ other_cols = [c for c in available_cols if c not in node.formula]
306
+ if other_cols:
307
+ other_col = self.rng.choice(other_cols)
308
+ else:
309
+ other_col = self.rng.choice(available_cols)
310
+ try:
311
+ new_formula = op.template.replace(
312
+ "{f2}", other_col,
313
+ ).replace("{f}", node.formula)
314
+ if op.requires_window and w is not None:
315
+ new_formula = new_formula.replace("{w}", str(w))
316
+ except Exception:
317
+ return None
318
+ else:
319
+ try:
320
+ new_formula = op.instantiate(node.formula, w)
321
+ except Exception:
322
+ return None
323
+
324
+ # 公式缓存去重
325
+ if new_formula in self._tree.formula_cache:
326
+ return None
327
+ if node.formula.count("(") >= 5 * 2: # 防止过深嵌套
328
+ return None
329
+
330
+ # 快速预检查(避免无效公式进入评估)
331
+ precheck_err = self._precheck_formula(new_formula)
332
+ if precheck_err is not None:
333
+ logger.debug("预检查失败: %s (%s)", new_formula[:50], precheck_err)
334
+ return None
335
+
336
+ # 创建子节点
337
+ child = MCTSNode(
338
+ formula=new_formula,
339
+ depth=node.depth + 1,
340
+ )
341
+ node.add_child(child)
342
+ self._tree.add_node(child, parent=node)
343
+ return child
344
+
345
+ def _precheck_formula(self, formula: str) -> Optional[str]:
346
+ """快速预检查,返回错误原因或 None
347
+
348
+ 检查项:
349
+ 1. 括号匹配
350
+ 2. 长度限制
351
+ 3. 未知算子
352
+ """
353
+ # 括号匹配
354
+ if formula.count("(") != formula.count(")"):
355
+ return "bracket mismatch"
356
+
357
+ # 长度限制
358
+ if len(formula) > 500:
359
+ return "too long"
360
+
361
+ # 未知算子
362
+ import re
363
+ from QuantNodes.research.quant_alpha.llm.parser import ALLOWED_OPERATORS
364
+ ops = re.findall(r'\b([a-zA-Z_][a-zA-Z0-9_]*)\s*\(', formula)
365
+ for op in ops:
366
+ if op not in ALLOWED_OPERATORS:
367
+ return f"unknown op: {op}"
368
+
369
+ return None
370
+
371
+ def _evaluate(
372
+ self,
373
+ node: MCTSNode,
374
+ data: pl.DataFrame,
375
+ date_column: str,
376
+ forward_return_column: str = "forward_return",
377
+ ) -> None:
378
+ """评估节点:5 通道反馈 + IC/IR"""
379
+ if node.status != NodeStatus.PENDING:
380
+ return
381
+
382
+ node.status = NodeStatus.EVALUATED
383
+ node.visits += 1
384
+
385
+ # 公式缓存
386
+ if node.formula in self._formula_cache:
387
+ result = self._formula_cache[node.formula]
388
+ exception = None
389
+ else:
390
+ result = None
391
+ exception = None
392
+ try:
393
+ result = self.vocab.evaluate(
394
+ formula=node.formula,
395
+ data=data,
396
+ date_column=date_column,
397
+ )
398
+ self._formula_cache[node.formula] = result
399
+ except Exception as e:
400
+ exception = e
401
+ result = None
402
+
403
+ # 5+3 通道反馈
404
+ expected_length = len(data)
405
+
406
+ # 计算 IC/IR(用于 DECAY 通道)
407
+ ic_metrics = {}
408
+ if self.config.compute_ic_ir and exception is None and result is not None:
409
+ try:
410
+ ic_metrics = self._compute_ic_ir(
411
+ node.formula, data, date_column, forward_return_column
412
+ )
413
+ except Exception as e:
414
+ logger.debug("IC/IR computation failed for %s: %s", node.formula, e)
415
+
416
+ fb = collect_all_channels(
417
+ formula=node.formula,
418
+ result=result,
419
+ expected_length=expected_length,
420
+ config=self.config.feedback_config,
421
+ exception=exception,
422
+ ic_decay=ic_metrics.get("ic_decay"),
423
+ data=data,
424
+ date_column=date_column,
425
+ code_column=self.config.code_column,
426
+ llm_client=self.config.llm_client,
427
+ structured_logic=self.config.structured_logic,
428
+ hypothesis=node.metadata.get("hypothesis"), # Tier 2
429
+ )
430
+ self._feedback_cache[node.formula] = fb
431
+
432
+ # 维度评分
433
+ node.dimension_scores = {
434
+ ch.value: ch_fb.score
435
+ for ch, ch_fb in fb.channels.items()
436
+ }
437
+
438
+ # 综合评分 = 所有通道平均 score
439
+ if fb.channels:
440
+ node.overall_score = sum(
441
+ ch.score for ch in fb.channels.values()
442
+ ) / len(fb.channels)
443
+ else:
444
+ node.overall_score = 0.0
445
+
446
+ # 决策
447
+ if not fb.decision:
448
+ node.status = NodeStatus.REJECTED
449
+
450
+ # 存储 IC/IR 指标(已在前面计算)
451
+ if ic_metrics:
452
+ node.metadata.update(ic_metrics)
453
+
454
+ # 元数据
455
+ node.metadata["feedback_summary"] = fb.summary
456
+ node.metadata["decision"] = fb.decision
457
+ if exception:
458
+ node.metadata["exception"] = str(exception)[:200]
459
+
460
+ def _compute_ic_ir(
461
+ self,
462
+ formula: str,
463
+ data: pl.DataFrame,
464
+ date_column: str,
465
+ forward_return_column: str,
466
+ ) -> Dict[str, float]:
467
+ """计算 IC/IR 指标"""
468
+ from QuantNodes.agent.tools.alpha_evaluate import AlphaEvaluateTool
469
+ import asyncio
470
+
471
+ tool = AlphaEvaluateTool()
472
+ result = asyncio.run(
473
+ tool.execute(
474
+ formulas=[formula],
475
+ data=data,
476
+ date_column=date_column,
477
+ forward_returns=list(self.config.forward_returns),
478
+ )
479
+ )
480
+ if result.get("evaluations") and result["evaluations"][0]["status"] == "success":
481
+ metrics = result["evaluations"][0]["metrics"]
482
+ return {
483
+ "ic_mean": metrics.get("ic_mean", 0.0),
484
+ "ic_std": metrics.get("ic_std", 0.0),
485
+ "ir": metrics.get("ir", 0.0),
486
+ "ic_decay": metrics.get("ic_decay", {}),
487
+ }
488
+ return {"ic_mean": 0.0, "ic_std": 0.0, "ir": 0.0}
489
+
490
+ def _backpropagate(self, node: MCTSNode) -> None:
491
+ """回传评分:更新所有祖先节点的 overall_score
492
+
493
+ 优化:使用加权平均而非最大值,考虑 IC/IR 信息。
494
+ """
495
+ current = node
496
+ while current is not None and current.parent_id is not None:
497
+ parent = self._find_parent(current)
498
+ if parent is None:
499
+ break
500
+ # 使用加权平均:IC/IR 越高,权重越大
501
+ if parent.children:
502
+ def _weighted_score(n: MCTSNode) -> float:
503
+ base = n.overall_score
504
+ ir = abs(n.metadata.get("ir", 0.0))
505
+ # IC/IR 越高,权重越大
506
+ return base * (1.0 + ir)
507
+
508
+ best_child = max(
509
+ parent.children,
510
+ key=_weighted_score,
511
+ )
512
+ parent.overall_score = _weighted_score(best_child)
513
+ current = parent
514
+
515
+ def _find_parent(self, node: MCTSNode) -> Optional[MCTSNode]:
516
+ """通过 parent_id 找到父节点(O(1) via tree index)"""
517
+ if node.parent_id is None:
518
+ return None
519
+ if self._tree is not None:
520
+ return self._tree.get_by_entry_id(node.parent_id)
521
+ # 回退:线性扫描
522
+ for n in self._tree.all_nodes():
523
+ if n.entry_id == node.parent_id:
524
+ return n
525
+ return None
526
+
527
+ def get_feedback(self, formula: str) -> Optional[FactorFeedback]:
528
+ """查询公式的 5 通道反馈"""
529
+ return self._feedback_cache.get(formula)
530
+
531
+ def stats(self) -> Dict[str, Any]:
532
+ """MCTS 搜索统计"""
533
+ if self._tree is None:
534
+ return {"status": "not_initialized"}
535
+ tree_stats = self._tree.stats()
536
+ return {
537
+ **tree_stats,
538
+ "formula_cache_size": len(self._formula_cache),
539
+ "feedback_cache_size": len(self._feedback_cache),
540
+ }