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,366 @@
1
+ # coding=utf-8
2
+ """
3
+ generator.py - 外层循环的两个 Agent
4
+
5
+ 基于 AlphaLogics 论文 (arXiv 2603.20247) §3.3 实现。
6
+
7
+ 两个外层 Agent:
8
+ - MarketLogicGeneratorAgent: 生成新/重构逻辑
9
+ - MarketLogicRefinementDirectionAgent: 逻辑层反馈
10
+
11
+ Usage::
12
+
13
+ from QuantNodes.research.quant_alpha.logic_mining.generator import (
14
+ MarketLogicGenerator, MarketLogicRefinementDirection,
15
+ )
16
+
17
+ generator = MarketLogicGenerator(llm_client=llm)
18
+ new_logic = generator.generate(library, history, evidence)
19
+
20
+ refiner = MarketLogicRefinementDirection(llm_client=llm)
21
+ feedback = refiner.refine(current_logic, history, evidence)
22
+ """
23
+
24
+ from __future__ import annotations
25
+
26
+ import json
27
+ import logging
28
+ from dataclasses import dataclass, field
29
+ from datetime import datetime
30
+ from typing import Any, Dict, List, Optional, Tuple
31
+
32
+ from QuantNodes.research.quant_alpha.logic_mining.models import (
33
+ LogicBehavior,
34
+ LogicCondition,
35
+ LogicPerformanceEvidence,
36
+ WikiLogicStructured,
37
+ )
38
+ from QuantNodes.research.quant_alpha.logic_mining.parser import (
39
+ parse_json_response,
40
+ )
41
+
42
+ # WikiLogic 在 research.wiki 中定义,会引用 logic_mining.models,
43
+ # 故在此延迟导入以避免循环依赖。
44
+ def _get_wiki_logic_class():
45
+ from QuantNodes.research.wiki import WikiLogic
46
+ return WikiLogic
47
+
48
+ def _get_logic_source_class():
49
+ from QuantNodes.research.wiki import LogicSource
50
+ return LogicSource
51
+
52
+ logger = logging.getLogger(__name__)
53
+
54
+ __all__ = [
55
+ "MarketLogicGenerator",
56
+ "MarketLogicRefinementDirection",
57
+ "generate_logic_name",
58
+ ]
59
+
60
+
61
+ def _call_llm(llm_client: Any, agent_id: str, prompt: str, default_response: str) -> str:
62
+ """调用 LLM,无客户端或失败时返回 mock"""
63
+ if llm_client is None:
64
+ return default_response
65
+ try:
66
+ if hasattr(llm_client, "complete"):
67
+ return llm_client.complete(agent_id=agent_id, prompt=prompt)
68
+ return llm_client(prompt)
69
+ except Exception as e:
70
+ logger.warning("LLM call failed for %s: %s, falling back to mock", agent_id, e)
71
+ return default_response
72
+
73
+
74
+ def _build_generator_prompt(
75
+ library: List[WikiLogic],
76
+ current_logic: Optional[WikiLogic],
77
+ history: List[WikiLogic],
78
+ evidence: List[LogicPerformanceEvidence],
79
+ round_idx: int,
80
+ ) -> str:
81
+ """MarketLogicGeneratorAgent prompt"""
82
+ lib_names = [l.name for l in library[:10]]
83
+ history_names = [l.name for l in history[:10]]
84
+ ev_summary = [
85
+ {"round": e.refinement_round, "best_ir": e.best_ir, "n": e.n_factors_explored}
86
+ for e in evidence[:10]
87
+ ]
88
+
89
+ return (
90
+ f"Generate a NEW market logic H_new for round {round_idx}.\n\n"
91
+ f"Current library (top 10): {lib_names}\n"
92
+ f"History: {history_names}\n"
93
+ f"Evidence history: {ev_summary}\n\n"
94
+ f"Output STRICT JSON:\n"
95
+ f"{{\n"
96
+ f' "name": "logic_name_v{round_idx}",\n'
97
+ f' "predicates": [{{"variable": "close", "op": "ts_mean", '
98
+ f'"threshold": 0, "window": 20}}],\n'
99
+ f' "behavior": {{"target": "forward_return_5", "direction": -1, "horizon": 5}},\n'
100
+ f' "operator_whitelist": ["ts_mean", "rank", "sub", "div"],\n'
101
+ f' "parameter_ranges": {{"ts_mean": [5, 60]}},\n'
102
+ f' "sign_constraint": -1\n'
103
+ f"}}"
104
+ )
105
+
106
+
107
+ def _build_refiner_prompt(
108
+ current_logic: WikiLogic,
109
+ history: List[WikiLogic],
110
+ evidence: List[LogicPerformanceEvidence],
111
+ ) -> str:
112
+ """MarketLogicRefinementDirectionAgent prompt"""
113
+ ev_current = current_logic.performance_evidence
114
+ current_ir = ev_current.best_ir if ev_current else 0.0
115
+
116
+ return (
117
+ f"Provide refinement direction for current logic.\n\n"
118
+ f"Current logic: {current_logic.name}\n"
119
+ f"Current best_ir: {current_ir}\n"
120
+ f"History: {[l.name for l in history[:5]]}\n"
121
+ f"Evidence: {[(e.refinement_round, e.best_ir) for e in evidence[:5]]}\n\n"
122
+ f"Output STRICT JSON:\n"
123
+ f"{{\n"
124
+ f' "diagnosis": "logic_too_broad or logic_too_narrow or well_calibrated",\n'
125
+ f' "direction": "tighten_threshold or broaden_operators or refine_window",\n'
126
+ f' "suggested_changes": {{"parameter_ranges": {{"ts_mean": [10, 30]}}}}\n'
127
+ f"}}"
128
+ )
129
+
130
+
131
+ def _structured_from_dict(data: Dict[str, Any]) -> WikiLogicStructured:
132
+ """从 dict 构建 WikiLogicStructured"""
133
+ predicates = []
134
+ for p in data.get("predicates", []):
135
+ predicates.append(LogicCondition(
136
+ variable=p["variable"],
137
+ op=p["op"],
138
+ threshold=p.get("threshold", 0.0),
139
+ window=p.get("window"),
140
+ weight=p.get("weight", 1.0),
141
+ second_variable=p.get("second_variable"),
142
+ ))
143
+
144
+ beh_data = data.get("behavior", {})
145
+ behavior = LogicBehavior(
146
+ target=beh_data.get("target", "forward_return_5"),
147
+ direction=beh_data.get("direction", 1),
148
+ horizon=beh_data.get("horizon", 5),
149
+ )
150
+
151
+ param_ranges = None
152
+ if data.get("parameter_ranges"):
153
+ param_ranges = {k: tuple(v) for k, v in data["parameter_ranges"].items()}
154
+
155
+ return WikiLogicStructured(
156
+ predicates=predicates,
157
+ behavior=behavior,
158
+ operator_whitelist=data.get("operator_whitelist"),
159
+ parameter_ranges=param_ranges,
160
+ sign_constraint=data.get("sign_constraint"),
161
+ )
162
+
163
+
164
+ def generate_logic_name(base: str, round_idx: int) -> str:
165
+ """生成逻辑名称"""
166
+ return f"{base}_v{round_idx}"
167
+
168
+
169
+ @dataclass
170
+ class MarketLogicGenerator:
171
+ """MarketLogicGeneratorAgent
172
+
173
+ 在初始轮基于 ℋ_init 发散生成;后续轮基于 ℋ_lib + 历史证据做有方向的生成/重构。
174
+ """
175
+ llm_client: Any = None
176
+ base_name: str = "alpha_logic"
177
+
178
+ def generate(
179
+ self,
180
+ library: List[WikiLogic],
181
+ current_logic: Optional[WikiLogic] = None,
182
+ history: Optional[List[WikiLogic]] = None,
183
+ evidence: Optional[List[LogicPerformanceEvidence]] = None,
184
+ round_idx: int = 1,
185
+ ) -> WikiLogic:
186
+ """生成新逻辑
187
+
188
+ Args:
189
+ library: 当前全部逻辑库 ℋ_lib
190
+ current_logic: 当前逻辑 H_current
191
+ history: 历史逻辑列表
192
+ evidence: 历史证据列表
193
+ round_idx: 轮次
194
+
195
+ Returns:
196
+ 新的 WikiLogic
197
+ """
198
+ history = history or []
199
+ evidence = evidence or []
200
+
201
+ # Mock 响应:基于 evidence 趋势生成
202
+ mock_response = self._mock_generate_response(
203
+ library, current_logic, history, evidence, round_idx
204
+ )
205
+
206
+ # 调用 LLM
207
+ prompt = _build_generator_prompt(library, current_logic, history, evidence, round_idx)
208
+ raw = _call_llm(
209
+ self.llm_client, "market-logic-generator", prompt, mock_response
210
+ )
211
+ result = parse_json_response(raw)
212
+ if not result.ok:
213
+ logger.warning("MarketLogicGenerator parse failed: %s, using mock data", result.error)
214
+ data = json.loads(mock_response)
215
+ else:
216
+ data = result.data
217
+
218
+ # 构建 WikiLogic
219
+ name = data.get("name") or generate_logic_name(self.base_name, round_idx)
220
+ try:
221
+ structured = _structured_from_dict(data)
222
+ except Exception as e:
223
+ logger.warning("Failed to build WikiLogicStructured: %s", e)
224
+ structured = None
225
+
226
+ parent = current_logic.name if current_logic else None
227
+ WikiLogic = _get_wiki_logic_class()
228
+ LogicSource = _get_logic_source_class()
229
+ return WikiLogic(
230
+ name=name,
231
+ content=f"Auto-generated logic at round {round_idx}",
232
+ source=LogicSource.RESEARCH_REPORT,
233
+ extracted_formula=None,
234
+ validation_status="pending",
235
+ structured=structured,
236
+ parent_logic=parent,
237
+ refinement_round=round_idx,
238
+ created_at=datetime.now().isoformat(),
239
+ )
240
+
241
+ def _mock_generate_response(
242
+ self,
243
+ library: List[WikiLogic],
244
+ current_logic: Optional[WikiLogic],
245
+ history: List[WikiLogic],
246
+ evidence: List[LogicPerformanceEvidence],
247
+ round_idx: int,
248
+ ) -> str:
249
+ """Mock 响应:基于历史证据趋势生成"""
250
+ # 基于当前逻辑变体
251
+ if current_logic and current_logic.structured:
252
+ base_predicates = [p.to_dict() for p in current_logic.structured.predicates]
253
+ beh = current_logic.structured.behavior.to_dict()
254
+ whitelist = current_logic.structured.operator_whitelist or ["rank"]
255
+ param_ranges = None
256
+ if current_logic.structured.parameter_ranges:
257
+ param_ranges = {
258
+ k: list(v)
259
+ for k, v in current_logic.structured.parameter_ranges.items()
260
+ }
261
+ sign = current_logic.structured.sign_constraint
262
+ else:
263
+ base_predicates = [{"variable": "close", "op": "ts_mean", "threshold": 0, "window": 20}]
264
+ beh = {"target": "forward_return_5", "direction": -1, "horizon": 5}
265
+ whitelist = ["ts_mean", "rank", "sub", "div", "sign"]
266
+ param_ranges = {"ts_mean": [5, 60]}
267
+ sign = -1
268
+
269
+ # 根据 evidence 调整
270
+ if evidence and len(evidence) >= 2:
271
+ # IR 提升则保持方向,否则反转
272
+ if evidence[-1].best_ir > evidence[-2].best_ir:
273
+ # 继续优化
274
+ pass
275
+ else:
276
+ # 反转方向
277
+ sign = -sign if sign else 1
278
+
279
+ return json.dumps({
280
+ "name": generate_logic_name(self.base_name, round_idx),
281
+ "predicates": base_predicates,
282
+ "behavior": beh,
283
+ "operator_whitelist": whitelist,
284
+ "parameter_ranges": param_ranges or {},
285
+ "sign_constraint": sign,
286
+ })
287
+
288
+
289
+ @dataclass
290
+ class MarketLogicRefinementDirection:
291
+ """MarketLogicRefinementDirectionAgent
292
+
293
+ 综合所有该逻辑名下因子的回测表现,识别"逻辑过宽/过窄/与市场结构错配"的部分。
294
+ """
295
+ llm_client: Any = None
296
+
297
+ def refine(
298
+ self,
299
+ current_logic: WikiLogic,
300
+ history: Optional[List[WikiLogic]] = None,
301
+ evidence: Optional[List[LogicPerformanceEvidence]] = None,
302
+ ) -> Dict[str, Any]:
303
+ """生成逻辑层反馈
304
+
305
+ Args:
306
+ current_logic: 当前逻辑
307
+ history: 历史逻辑
308
+ evidence: 历史证据
309
+
310
+ Returns:
311
+ {
312
+ "diagnosis": str,
313
+ "direction": str,
314
+ "suggested_changes": Dict
315
+ }
316
+ """
317
+ history = history or []
318
+ evidence = evidence or []
319
+
320
+ # Mock 响应
321
+ mock_response = self._mock_refine_response(current_logic, evidence)
322
+
323
+ # 调用 LLM
324
+ prompt = _build_refiner_prompt(current_logic, history, evidence)
325
+ raw = _call_llm(
326
+ self.llm_client, "market-logic-refinement", prompt, mock_response
327
+ )
328
+ result = parse_json_response(raw)
329
+ if not result.ok:
330
+ logger.warning("Refinement parse failed: %s, using mock", result.error)
331
+ data = json.loads(mock_response)
332
+ else:
333
+ data = result.data
334
+
335
+ return {
336
+ "diagnosis": data.get("diagnosis", "well_calibrated"),
337
+ "direction": data.get("direction", "no_change"),
338
+ "suggested_changes": data.get("suggested_changes", {}),
339
+ }
340
+
341
+ def _mock_refine_response(
342
+ self,
343
+ current_logic: WikiLogic,
344
+ evidence: List[LogicPerformanceEvidence],
345
+ ) -> str:
346
+ """Mock 响应:基于 IR 趋势给出建议"""
347
+ if not evidence:
348
+ diagnosis = "well_calibrated"
349
+ direction = "no_change"
350
+ elif len(evidence) >= 2 and evidence[-1].best_ir < evidence[-2].best_ir:
351
+ diagnosis = "logic_too_broad"
352
+ direction = "tighten_threshold"
353
+ elif len(evidence) >= 2 and evidence[-1].best_ir == evidence[-2].best_ir:
354
+ diagnosis = "saturated"
355
+ direction = "refine_window"
356
+ else:
357
+ diagnosis = "well_calibrated"
358
+ direction = "no_change"
359
+
360
+ return json.dumps({
361
+ "diagnosis": diagnosis,
362
+ "direction": direction,
363
+ "suggested_changes": {
364
+ "parameter_ranges": {"ts_mean": [10, 30]},
365
+ },
366
+ })
@@ -0,0 +1,252 @@
1
+ # coding=utf-8
2
+ """
3
+ models.py - 逻辑结构化数据模型
4
+
5
+ 基于 AlphaLogics 论文的逻辑表示 H = ⟨𝒞, ℬ⟩。
6
+
7
+ Usage::
8
+
9
+ from QuantNodes.research.quant_alpha.logic_mining.models import (
10
+ LogicCondition, LogicBehavior, WikiLogicStructured,
11
+ )
12
+
13
+ logic = WikiLogicStructured(
14
+ predicates=[
15
+ LogicCondition(variable="open", op="rank", threshold=0),
16
+ LogicCondition(variable="volume", op="ts_corr", threshold=-0.5, window=10),
17
+ ],
18
+ behavior=LogicBehavior(target="forward_return_5", direction=-1, horizon=5),
19
+ operator_whitelist=["rank", "ts_corr", "sign"],
20
+ parameter_ranges={"ts_corr": (5, 30)},
21
+ sign_constraint=-1,
22
+ )
23
+ """
24
+
25
+ from __future__ import annotations
26
+
27
+ from dataclasses import dataclass, field
28
+ from typing import Any, Dict, List, Optional, Tuple
29
+
30
+ __all__ = [
31
+ "LogicCondition",
32
+ "LogicBehavior",
33
+ "WikiLogicStructured",
34
+ "LogicPerformanceEvidence",
35
+ "LogicAbstractionResult",
36
+ ]
37
+
38
+
39
+ @dataclass
40
+ class LogicCondition:
41
+ """单条谓词 (v, op, θ, w)
42
+
43
+ 对应论文中的条件谓词: variable op threshold
44
+ """
45
+
46
+ variable: str # 市场变量名: "close", "volume", "open", "high", "low"
47
+ op: str # 算子名: "ts_corr", "ts_mean", "rank"
48
+ threshold: float # 阈值 θ
49
+ window: Optional[int] = None # 时序算子的窗口 d
50
+ weight: float = 1.0 # 权重 w
51
+ second_variable: Optional[str] = None # 双变量算子的第二个变量
52
+
53
+ def to_dict(self) -> Dict[str, Any]:
54
+ """转换为字典"""
55
+ d = {
56
+ "variable": self.variable,
57
+ "op": self.op,
58
+ "threshold": self.threshold,
59
+ "weight": self.weight,
60
+ }
61
+ if self.window is not None:
62
+ d["window"] = self.window
63
+ if self.second_variable is not None:
64
+ d["second_variable"] = self.second_variable
65
+ return d
66
+
67
+ @classmethod
68
+ def from_dict(cls, data: Dict[str, Any]) -> LogicCondition:
69
+ """从字典创建"""
70
+ return cls(
71
+ variable=data["variable"],
72
+ op=data["op"],
73
+ threshold=data.get("threshold", 0.0),
74
+ window=data.get("window"),
75
+ weight=data.get("weight", 1.0),
76
+ second_variable=data.get("second_variable"),
77
+ )
78
+
79
+
80
+ @dataclass
81
+ class LogicBehavior:
82
+ """ℬ = (y, d, h): 行为三元组
83
+
84
+ - target: 预测目标 (forward_return_1/5/20)
85
+ - direction: 信号方向 (+1/-1)
86
+ - horizon: 持有期天数
87
+ """
88
+
89
+ target: str # "forward_return_1" / "forward_return_5" / "forward_return_20"
90
+ direction: int # +1(信号方向与目标一致)/ -1(反向)
91
+ horizon: int # 持有期天数
92
+
93
+ def to_dict(self) -> Dict[str, Any]:
94
+ """转换为字典"""
95
+ return {
96
+ "target": self.target,
97
+ "direction": self.direction,
98
+ "horizon": self.horizon,
99
+ }
100
+
101
+ @classmethod
102
+ def from_dict(cls, data: Dict[str, Any]) -> LogicBehavior:
103
+ """从字典创建"""
104
+ return cls(
105
+ target=data["target"],
106
+ direction=data["direction"],
107
+ horizon=data["horizon"],
108
+ )
109
+
110
+
111
+ @dataclass
112
+ class WikiLogicStructured:
113
+ """H_struct: 规范化后的结构化逻辑
114
+
115
+ 对应论文中的逻辑表示 H = ⟨𝒞, ℬ⟩。
116
+ 可通过 compile_to_constraint() 编译为 Γ 约束。
117
+ """
118
+
119
+ predicates: List[LogicCondition] # 条件谓词列表 (𝒞)
120
+ behavior: LogicBehavior # 行为目标 (ℬ)
121
+ operator_whitelist: Optional[List[str]] = None # 允许的算子族
122
+ parameter_ranges: Optional[Dict[str, Tuple[float, float]]] = None # 参数范围
123
+ sign_constraint: Optional[int] = None # +1 / -1 / None
124
+
125
+ def to_dict(self) -> Dict[str, Any]:
126
+ """转换为字典(便于 JSON 序列化)"""
127
+ d: Dict[str, Any] = {
128
+ "predicates": [p.to_dict() for p in self.predicates],
129
+ "behavior": self.behavior.to_dict(),
130
+ }
131
+ if self.operator_whitelist is not None:
132
+ d["operator_whitelist"] = self.operator_whitelist
133
+ if self.parameter_ranges is not None:
134
+ d["parameter_ranges"] = {
135
+ k: list(v) for k, v in self.parameter_ranges.items()
136
+ }
137
+ if self.sign_constraint is not None:
138
+ d["sign_constraint"] = self.sign_constraint
139
+ return d
140
+
141
+ @classmethod
142
+ def from_dict(cls, data: Dict[str, Any]) -> WikiLogicStructured:
143
+ """从字典创建"""
144
+ predicates = [LogicCondition.from_dict(p) for p in data.get("predicates", [])]
145
+ behavior = LogicBehavior.from_dict(data["behavior"])
146
+
147
+ param_ranges = None
148
+ if "parameter_ranges" in data and data["parameter_ranges"] is not None:
149
+ param_ranges = {
150
+ k: tuple(v) for k, v in data["parameter_ranges"].items()
151
+ }
152
+
153
+ return cls(
154
+ predicates=predicates,
155
+ behavior=behavior,
156
+ operator_whitelist=data.get("operator_whitelist"),
157
+ parameter_ranges=param_ranges,
158
+ sign_constraint=data.get("sign_constraint"),
159
+ )
160
+
161
+ def get_operators(self) -> List[str]:
162
+ """从谓词中提取所有使用的算子"""
163
+ ops = set()
164
+ for p in self.predicates:
165
+ ops.add(p.op)
166
+ return sorted(ops)
167
+
168
+ def get_variables(self) -> List[str]:
169
+ """从谓词中提取所有使用的变量"""
170
+ vars_ = set()
171
+ for p in self.predicates:
172
+ vars_.add(p.variable)
173
+ if p.second_variable:
174
+ vars_.add(p.second_variable)
175
+ return sorted(vars_)
176
+
177
+
178
+ @dataclass
179
+ class LogicPerformanceEvidence:
180
+ """聚合的 per-logic 回测证据 E^Logic
181
+
182
+ 对应论文中每条逻辑下所有因子的回测证据聚合。
183
+
184
+ Attributes:
185
+ n_factors_explored: 探索过的因子数
186
+ best_ir: 最佳 IR
187
+ best_ic: 最佳 IC
188
+ best_factor_id: 最佳因子 ID
189
+ mean_ir: 平均 IR
190
+ refinement_round: 第几轮聚合的证据
191
+ timestamp: 时间戳
192
+ """
193
+ n_factors_explored: int = 0
194
+ best_ir: float = 0.0
195
+ best_ic: float = 0.0
196
+ best_factor_id: Optional[str] = None
197
+ mean_ir: float = 0.0
198
+ refinement_round: int = 0
199
+ timestamp: Optional[str] = None
200
+
201
+ def to_dict(self) -> Dict[str, Any]:
202
+ """转换为字典"""
203
+ return {
204
+ "n_factors_explored": self.n_factors_explored,
205
+ "best_ir": self.best_ir,
206
+ "best_ic": self.best_ic,
207
+ "best_factor_id": self.best_factor_id,
208
+ "mean_ir": self.mean_ir,
209
+ "refinement_round": self.refinement_round,
210
+ "timestamp": self.timestamp,
211
+ }
212
+
213
+ @classmethod
214
+ def from_dict(cls, data: Dict[str, Any]) -> LogicPerformanceEvidence:
215
+ """从字典创建"""
216
+ return cls(
217
+ n_factors_explored=data.get("n_factors_explored", 0),
218
+ best_ir=data.get("best_ir", 0.0),
219
+ best_ic=data.get("best_ic", 0.0),
220
+ best_factor_id=data.get("best_factor_id"),
221
+ mean_ir=data.get("mean_ir", 0.0),
222
+ refinement_round=data.get("refinement_round", 0),
223
+ timestamp=data.get("timestamp"),
224
+ )
225
+
226
+
227
+ @dataclass
228
+ class LogicAbstractionResult:
229
+ """Logic Mining 三段式 Agent 的输出
230
+
231
+ Attributes:
232
+ formula_structure: FormulaStructureAgent 输出
233
+ financial_semantics: FinancialSemanticsMappingAgent 输出
234
+ structured_logic: MarketLogicAbstractionAgent 输出
235
+ source_formula: 原始公式
236
+ source_lib: 来源库 ("alpha101" / "alpha158" / "alpha191")
237
+ """
238
+ formula_structure: Dict[str, Any] = field(default_factory=dict)
239
+ financial_semantics: Dict[str, Any] = field(default_factory=dict)
240
+ structured_logic: Optional[WikiLogicStructured] = None
241
+ source_formula: str = ""
242
+ source_lib: str = ""
243
+
244
+ def to_dict(self) -> Dict[str, Any]:
245
+ """转换为字典"""
246
+ return {
247
+ "formula_structure": self.formula_structure,
248
+ "financial_semantics": self.financial_semantics,
249
+ "structured_logic": self.structured_logic.to_dict() if self.structured_logic else None,
250
+ "source_formula": self.source_formula,
251
+ "source_lib": self.source_lib,
252
+ }