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,481 @@
1
+ # coding=utf-8
2
+ """
3
+ OperatorVocab 主类 - 统一算子查询/调用/元数据化接口
4
+
5
+ 修复 factor_evaluator._compute_factor 的 3 个 latent bug:
6
+ 1. ts_corr/ts_cov 的 Series.rolling_corr 不存在 → 改用 .rolling_corr() 在 DataFrame
7
+ 2. rank/zscore 全局而非 per-date → 默认 over(date_column)
8
+ 3. 异常被静默吞掉 → 完整错误抛出(带上下文)
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import logging
14
+ import threading
15
+ from typing import Any, Callable, Dict, List, Optional, TYPE_CHECKING
16
+
17
+ import polars as pl
18
+
19
+ from QuantNodes.research.quant_alpha.operator_vocab.config import (
20
+ OperatorVocabConfig,
21
+ )
22
+ from QuantNodes.research.quant_alpha.operator_vocab.metadata import (
23
+ OperatorCategory,
24
+ OperatorMetadata,
25
+ _infer_category_tags,
26
+ _infer_default_window,
27
+ _infer_difficulty,
28
+ _infer_output_dtype,
29
+ _infer_requires_group_by,
30
+ )
31
+
32
+ if TYPE_CHECKING:
33
+ pass
34
+
35
+ logger = logging.getLogger(__name__)
36
+
37
+
38
+ # 模块级单例(线程安全)
39
+ _default_vocab: Optional["OperatorVocab"] = None
40
+ _default_vocab_lock = threading.Lock()
41
+
42
+
43
+ def _max_nesting_depth(formula: str) -> int:
44
+ """计算公式的最大嵌套深度
45
+
46
+ 例如:
47
+ "rank(close)" → 1
48
+ "rank(ts_mean(close, 5))" → 2
49
+ "rank(ts_mean(ts_delta(close, 1), 5))" → 3
50
+ """
51
+ max_depth = 0
52
+ current_depth = 0
53
+ for char in formula:
54
+ if char == "(":
55
+ current_depth += 1
56
+ max_depth = max(max_depth, current_depth)
57
+ elif char == ")":
58
+ current_depth -= 1
59
+ if current_depth < 0:
60
+ return -1 # 不平衡
61
+ return max_depth
62
+
63
+
64
+ class OperatorVocab:
65
+ """统一算子词表 — 自动挖掘的统一接口
66
+
67
+ 把分散在 3 处的 285 个算子整合成统一查询/调用/元数据化接口。
68
+ 详见 docs/quant_alpha/PROJECT_PLAN.md §3 路线 0。
69
+ """
70
+
71
+ def __init__(self, config: Optional[OperatorVocabConfig] = None):
72
+ self.config = config or OperatorVocabConfig()
73
+ self._l0_registry: Optional[Dict[str, Dict[str, Any]]] = None
74
+ self._l1_specs: Optional[Dict[str, Any]] = None
75
+ self._metadata_cache: Dict[str, OperatorMetadata] = {}
76
+ self._lock = threading.Lock()
77
+
78
+ @classmethod
79
+ def default(cls) -> "OperatorVocab":
80
+ """模块级默认实例(线程安全单例)"""
81
+ global _default_vocab
82
+ if _default_vocab is None:
83
+ with _default_vocab_lock:
84
+ if _default_vocab is None:
85
+ _default_vocab = cls()
86
+ return _default_vocab
87
+
88
+ def reset_default_cache(self) -> None:
89
+ """重置默认实例缓存(仅用于测试)"""
90
+ global _default_vocab
91
+ with _default_vocab_lock:
92
+ _default_vocab = None
93
+
94
+ # ==================================================================
95
+ # 注册表加载
96
+ # ==================================================================
97
+
98
+ def _ensure_l0_loaded(self) -> Dict[str, Dict[str, Any]]:
99
+ """懒加载 L0 注册表"""
100
+ if self._l0_registry is not None:
101
+ return self._l0_registry
102
+
103
+ with self._lock:
104
+ if self._l0_registry is not None:
105
+ return self._l0_registry
106
+
107
+ from QuantNodes.factor_node.factor_functions._helpers import (
108
+ _OPERATOR_REGISTRY,
109
+ )
110
+
111
+ self._l0_registry = {}
112
+ for cat in self.config.enabled_categories:
113
+ if cat == "talib" and not self.config.talib_enabled:
114
+ continue
115
+ if cat in _OPERATOR_REGISTRY:
116
+ self._l0_registry.update(_OPERATOR_REGISTRY[cat])
117
+
118
+ return self._l0_registry
119
+
120
+ def _ensure_l1_loaded(self) -> Dict[str, Any]:
121
+ """懒加载 L1 composite 注册表"""
122
+ if self._l1_specs is not None:
123
+ return self._l1_specs
124
+
125
+ with self._lock:
126
+ if self._l1_specs is not None:
127
+ return self._l1_specs
128
+
129
+ try:
130
+ from QuantNodes.operators.composite_dag import (
131
+ list_composite_ops as _list_composite,
132
+ )
133
+
134
+ self._l1_specs = {
135
+ spec.name: spec
136
+ for spec in (_list_composite() or [])
137
+ }
138
+ except (ImportError, AttributeError) as e:
139
+ logger.debug("L1 composite registry unavailable: %s", e)
140
+ self._l1_specs = {}
141
+
142
+ return self._l1_specs
143
+
144
+ # ==================================================================
145
+ # 公开 API:查询
146
+ # ==================================================================
147
+
148
+ def list_operators(self, category: Optional[str] = None) -> List[str]:
149
+ """列出所有算子
150
+
151
+ Args:
152
+ category: 可选过滤(point/time/section/multi_section/talib)
153
+
154
+ Returns:
155
+ 算子名列表
156
+ """
157
+ l0 = self._ensure_l0_loaded()
158
+ if category is None:
159
+ return sorted(l0.keys())
160
+ if not OperatorCategory.is_valid(category):
161
+ raise ValueError(f"Invalid category: {category}")
162
+ return sorted(name for name, entry in l0.items() if entry.get("category") == category)
163
+
164
+ def get_operator(self, name: str) -> Optional[Callable]:
165
+ """按名称获取算子函数"""
166
+ l0 = self._ensure_l0_loaded()
167
+ entry = l0.get(name)
168
+ if entry is not None:
169
+ return entry.get("func")
170
+ return None
171
+
172
+ def get_metadata(self, name: str) -> Optional[OperatorMetadata]:
173
+ """按名称获取算子元数据(带缓存)"""
174
+ if name in self._metadata_cache:
175
+ return self._metadata_cache[name]
176
+
177
+ l0 = self._ensure_l0_loaded()
178
+ entry = l0.get(name)
179
+ if entry is None:
180
+ return None
181
+
182
+ meta = OperatorMetadata.from_registry_entry(entry)
183
+ self._metadata_cache[name] = meta
184
+ return meta
185
+
186
+ def list_metadata(
187
+ self, category: Optional[str] = None
188
+ ) -> List[OperatorMetadata]:
189
+ """列出所有算子的元数据"""
190
+ names = self.list_operators(category)
191
+ return [self.get_metadata(n) for n in names if self.get_metadata(n) is not None]
192
+
193
+ # ==================================================================
194
+ # 公开 API:build_namespace
195
+ # ==================================================================
196
+
197
+ def build_namespace(
198
+ self,
199
+ data: pl.DataFrame,
200
+ date_column: str = "date",
201
+ code_column: str = "code",
202
+ cross_sectional: Optional[bool] = None,
203
+ ) -> Dict[str, Any]:
204
+ """构造 eval 沙箱 namespace
205
+
206
+ 修复因子:
207
+ 1. ts_corr/ts_cov:使用正确 Series API(pl.DataFrame.rolling_corr 不行,
208
+ 改用 (c1 - c1.mean()).rolling_corr((c2 - c2.mean()), window))
209
+ 2. rank/zscore 默认 per-date over(date_column)
210
+ 3. 异常不静默吞掉(eval 错误直接抛)
211
+
212
+ Args:
213
+ data: 行情数据
214
+ date_column: 日期列名
215
+ code_column: 股票代码列名(暂未使用,预留)
216
+ cross_sectional: 是否 per-date 截面
217
+ None = 用 config 默认(默认 True,修复旧 BUG 2)
218
+ True = per-date over(date_column)
219
+ False = 全局(与旧 12-lambda 行为一致)
220
+
221
+ Returns:
222
+ eval 沙箱 namespace dict
223
+ """
224
+ if cross_sectional is None:
225
+ cross_sectional = self.config.cross_sectional
226
+
227
+ namespace: Dict[str, Any] = {"pl": pl, "data": data}
228
+
229
+ # 注入所有列(Series 形式)
230
+ for col in data.columns:
231
+ namespace[col] = data[col]
232
+
233
+ # 列名 alias: LLM 倾向用语义化名称(volume/turnover),data 列名更短
234
+ # 加 alias 让 LLM 生成公式时两种命名都能跑通
235
+ # mapping: alias(注入namespace的名字)<- col(data列名)
236
+ _col_aliases = {
237
+ "volume": "vol", # 成交量(LLM 友好名 volume, data 列名 vol)
238
+ }
239
+ for alias, col in _col_aliases.items():
240
+ if col in data.columns and alias not in data.columns:
241
+ namespace[alias] = data[col]
242
+
243
+ # 注入 returns 快捷方式
244
+ if "close" in data.columns:
245
+ close = data["close"]
246
+ namespace["returns"] = (close - close.shift(1)) / (close.shift(1) + 1e-12)
247
+
248
+ # 注入 L0 算子(基于注册表)
249
+ l0 = self._ensure_l0_loaded()
250
+ for name, entry in l0.items():
251
+ func = entry.get("func")
252
+ if func is not None:
253
+ namespace[name] = func
254
+
255
+ # 注入 per-date over() 修复的截面算子
256
+ if cross_sectional:
257
+ date_col = date_column
258
+
259
+ def _to_series(x: Any) -> pl.Series:
260
+ """Expr → Series(用 data 物化);Series → 自身"""
261
+ if isinstance(x, pl.Expr):
262
+ return data.select(x).to_series()
263
+ return x
264
+
265
+ def _rank_per_date(x: Any) -> pl.Series:
266
+ """per-date rank(修复 BUG 2)
267
+
268
+ 支持 Series 或 Expr 输入:
269
+ - Series: 直接使用
270
+ - Expr: 用 data.select 物化
271
+ """
272
+ s = _to_series(x)
273
+ tmp = pl.DataFrame({
274
+ "_x": s,
275
+ "_d": data[date_col],
276
+ })
277
+ return tmp.select(
278
+ pl.col("_x").rank(method="average").over("_d").alias("_r")
279
+ )["_r"]
280
+
281
+ def _zscore_per_date(x: Any) -> pl.Series:
282
+ """per-date zscore(修复 BUG 2)"""
283
+ s = _to_series(x)
284
+ tmp = pl.DataFrame({
285
+ "_x": s,
286
+ "_d": data[date_col],
287
+ })
288
+ return tmp.select(
289
+ (
290
+ (pl.col("_x") - pl.col("_x").mean().over("_d"))
291
+ / (pl.col("_x").std().over("_d") + 1e-8)
292
+ ).alias("_z")
293
+ )["_z"]
294
+
295
+ def _winsorize_per_date(
296
+ x: Any, lower: float = 0.01, upper: float = 0.99
297
+ ) -> pl.Series:
298
+ """per-date winsorize(修复 BUG 2)"""
299
+ s = _to_series(x)
300
+ tmp = pl.DataFrame({
301
+ "_x": s,
302
+ "_d": data[date_col],
303
+ })
304
+ lo = pl.col("_x").quantile(lower).over("_d")
305
+ hi = pl.col("_x").quantile(upper).over("_d")
306
+ return tmp.select(
307
+ pl.col("_x").clip(lo, hi).alias("_w")
308
+ )["_w"]
309
+
310
+ # 覆盖 section_ops 的 rank/zscore/winsorize(per-date 修复)
311
+ namespace["rank"] = _rank_per_date
312
+ namespace["zscore"] = _zscore_per_date
313
+ namespace["winsorize"] = _winsorize_per_date
314
+ # IndNeutralize per-date 修复:在 L0 注册表基础上
315
+ # 加一层 over([date_col, ind_class])
316
+ l0 = self._ensure_l0_loaded()
317
+ base_ind_neutralize = l0.get("IndNeutralize", {}).get("func")
318
+
319
+ def _IndNeutralize_per_date(x, ind_class="citic_1"):
320
+ s = _to_series(x)
321
+ tmp = pl.DataFrame({
322
+ "_x": s,
323
+ "_d": data[date_col],
324
+ "_ind": data[ind_class],
325
+ })
326
+ return tmp.select(
327
+ (pl.col("_x") - pl.col("_x").mean().over(["_d", "_ind"])).alias("_r")
328
+ )["_r"]
329
+
330
+ namespace["IndNeutralize"] = _IndNeutralize_per_date
331
+ # ts_corr / ts_cov 走 L0 注册表(用 rolling_corr on Expr)
332
+ else:
333
+ # 全局(与旧 12-lambda 行为一致)
334
+ # 同样支持 Expr 输入
335
+ def _rank_global(x: Any) -> pl.Series:
336
+ s = x.to_series() if isinstance(x, pl.Expr) else x
337
+ return s.rank(method="average")
338
+
339
+ def _zscore_global(x: Any) -> pl.Series:
340
+ s = x.to_series() if isinstance(x, pl.Expr) else x
341
+ return (s - s.mean()) / (s.std() + 1e-8)
342
+
343
+ def _winsorize_global(
344
+ x: Any, lower: float = 0.01, upper: float = 0.99
345
+ ) -> pl.Series:
346
+ s = x.to_series() if isinstance(x, pl.Expr) else x
347
+ return s.quantile(lower).clip(s.quantile(lower), s.quantile(upper))
348
+
349
+ namespace["rank"] = _rank_global
350
+ namespace["zscore"] = _zscore_global
351
+ namespace["winsorize"] = _winsorize_global
352
+
353
+ return namespace
354
+
355
+ # ==================================================================
356
+ # 公开 API:端到端 evaluate
357
+ # ==================================================================
358
+
359
+ def evaluate(
360
+ self,
361
+ formula: str,
362
+ data: pl.DataFrame,
363
+ date_column: str = "date",
364
+ code_column: str = "code",
365
+ cross_sectional: Optional[bool] = None,
366
+ ) -> Optional[pl.Series]:
367
+ """端到端评估公式
368
+
369
+ Args:
370
+ formula: 因子公式字符串
371
+ data: 行情数据
372
+ date_column: 日期列名
373
+ code_column: 股票代码列名
374
+ cross_sectional: 是否 per-date 截面
375
+
376
+ Returns:
377
+ 因子值(pl.Series)或 None(评估失败)
378
+ """
379
+ # 安全检查:公式长度
380
+ if (
381
+ self.config.max_formula_length is not None
382
+ and len(formula) > self.config.max_formula_length
383
+ ):
384
+ raise ValueError(
385
+ f"Formula length {len(formula)} exceeds limit "
386
+ f"{self.config.max_formula_length}"
387
+ )
388
+
389
+ # 安全检查:嵌套深度(用栈计算最大嵌套层数)
390
+ depth = _max_nesting_depth(formula)
391
+ if depth > self.config.max_formula_depth:
392
+ raise ValueError(
393
+ f"Formula nesting depth {depth} exceeds limit "
394
+ f"{self.config.max_formula_depth}"
395
+ )
396
+
397
+ try:
398
+ namespace = self.build_namespace(
399
+ data=data,
400
+ date_column=date_column,
401
+ code_column=code_column,
402
+ cross_sectional=cross_sectional,
403
+ )
404
+ result = eval(formula, {"__builtins__": {}}, namespace)
405
+
406
+ if isinstance(result, pl.Series):
407
+ return result
408
+ if isinstance(result, pl.Expr):
409
+ return data.select(result).to_series()
410
+ if isinstance(result, (int, float, bool)):
411
+ # 标量结果:扩展为 Series
412
+ return pl.Series("_scalar", [result] * len(data))
413
+ return None
414
+
415
+ except Exception as e:
416
+ # 不再静默吞掉(修复 BUG 3),但允许调用方捕获
417
+ logger.debug(
418
+ "Formula evaluation failed: formula=%r, error=%s",
419
+ formula,
420
+ e,
421
+ )
422
+ raise
423
+
424
+ # ==================================================================
425
+ # 统计
426
+ # ==================================================================
427
+
428
+ def stats(self) -> Dict[str, Any]:
429
+ """词表统计信息"""
430
+ l0 = self._ensure_l0_loaded()
431
+ l1 = self._ensure_l1_loaded()
432
+
433
+ by_category: Dict[str, int] = {}
434
+ for entry in l0.values():
435
+ cat = entry.get("category", "unknown")
436
+ by_category[cat] = by_category.get(cat, 0) + 1
437
+
438
+ return {
439
+ "l0_total": len(l0),
440
+ "l1_total": len(l1),
441
+ "by_category": by_category,
442
+ "config": {
443
+ "cross_sectional": self.config.cross_sectional,
444
+ "talib_enabled": self.config.talib_enabled,
445
+ "enabled_categories": list(self.config.enabled_categories),
446
+ },
447
+ }
448
+
449
+
450
+ # ==================================================================
451
+ # 模块级便捷函数
452
+ # ==================================================================
453
+
454
+ def build_namespace(
455
+ data: pl.DataFrame,
456
+ date_column: str = "date",
457
+ code_column: str = "code",
458
+ cross_sectional: bool = True,
459
+ ) -> Dict[str, Any]:
460
+ """便捷函数:使用默认 vocab 构建 namespace"""
461
+ return OperatorVocab.default().build_namespace(
462
+ data=data,
463
+ date_column=date_column,
464
+ code_column=code_column,
465
+ cross_sectional=cross_sectional,
466
+ )
467
+
468
+
469
+ def list_vocab_operators(category: Optional[str] = None) -> List[str]:
470
+ """便捷函数:列出默认 vocab 算子"""
471
+ return OperatorVocab.default().list_operators(category=category)
472
+
473
+
474
+ def get_vocab_operator(name: str) -> Optional[Callable]:
475
+ """便捷函数:按名称获取默认 vocab 算子"""
476
+ return OperatorVocab.default().get_operator(name)
477
+
478
+
479
+ def get_vocab_metadata(name: str) -> Optional[OperatorMetadata]:
480
+ """便捷函数:按名称获取默认 vocab 元数据"""
481
+ return OperatorVocab.default().get_metadata(name)