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,841 @@
1
+ # coding=utf-8
2
+ """
3
+ 表达式系统 - 支持符号化表达计算逻辑
4
+
5
+ 本模块提供表达式抽象和 DSL 构建器,支持:
6
+ 1. 运算符重载构建表达式
7
+ 2. AST 安全解析字符串表达式
8
+ 3. 序列化/反序列化(通过 Serializable Mixin)
9
+ 4. 向后兼容 lambda 表达式
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import ast
15
+ import logging
16
+ from abc import ABC, abstractmethod
17
+ from typing import Any, Callable, Dict, Tuple, Type, Union
18
+
19
+ from QuantNodes.core.serializable import Serializable, serializable
20
+
21
+
22
+ logger = logging.getLogger(__name__)
23
+
24
+
25
+ # ============================================================================
26
+ # 安全配置
27
+ # ============================================================================
28
+
29
+ ALLOWED_AST_NODES = {
30
+ ast.Expression, ast.Compare, ast.BoolOp, ast.UnaryOp, ast.BinOp,
31
+ ast.Attribute, ast.Subscript, ast.Call, ast.Name,
32
+ ast.Constant, ast.Load,
33
+ ast.Gt, ast.Lt, ast.Eq, ast.GtE, ast.LtE, ast.NotEq,
34
+ ast.And, ast.Or, ast.Not,
35
+ ast.Add, ast.Sub, ast.Mult, ast.Div, ast.FloorDiv, ast.Mod, ast.Pow,
36
+ ast.USub,
37
+ }
38
+
39
+ FORBIDDEN_METHODS = {
40
+ 'eval', 'exec', '__import__', 'compile', 'open', 'system',
41
+ 'subprocess', 'os', 'sys', 'builtins',
42
+ }
43
+
44
+
45
+ # ============================================================================
46
+ # 表达式基类
47
+ # ============================================================================
48
+
49
+ @serializable
50
+ class Expression(Serializable, ABC):
51
+ """表达式基类,所有计算逻辑的抽象"""
52
+
53
+ @abstractmethod
54
+ def evaluate(self, input_data: Any) -> Any:
55
+ """对输入数据执行表达式求值"""
56
+ pass
57
+
58
+ def _get_serializable_fields(self) -> Dict[str, Any]:
59
+ """序列化字段"""
60
+ return {}
61
+
62
+ @classmethod
63
+ def _from_dict_impl(cls, data: Dict[str, Any]) -> 'Expression':
64
+ """子类实现的反序列化逻辑"""
65
+ raise NotImplementedError(f"{cls.__name__}._from_dict_impl not implemented")
66
+
67
+ @classmethod
68
+ def parse(cls, expr_str: str) -> 'Expression':
69
+ """安全解析字符串表达式"""
70
+ from QuantNodes.core.ast_parser import parse_expression
71
+ return parse_expression(expr_str)
72
+
73
+ def serialize(self) -> Dict[str, Any]:
74
+ """序列化为字典"""
75
+ return {
76
+ "type": self.__class__.__name__,
77
+ **self._get_serializable_fields(),
78
+ }
79
+
80
+ @classmethod
81
+ def deserialize(cls, data: Union[str, Dict, bytes]) -> 'Expression':
82
+ """从字典、JSON 字符串或压缩字节反序列化"""
83
+ if isinstance(data, bytes):
84
+ import zlib
85
+ if len(data) >= 2 and data[0:2] == b'x\x9c':
86
+ try:
87
+ data = zlib.decompress(data)
88
+ except Exception:
89
+ pass
90
+
91
+ if isinstance(data, bytes):
92
+ if data and 0x80 <= data[0] <= 0x8f:
93
+ try:
94
+ import msgpack
95
+ data = msgpack.unpackb(data, raw=False)
96
+ except Exception:
97
+ data = data.decode('utf-8')
98
+ else:
99
+ data = data.decode('utf-8')
100
+
101
+ if isinstance(data, str):
102
+ import json
103
+ data = json.loads(data)
104
+
105
+ type_name = data.get("type")
106
+ if not type_name:
107
+ raise ValueError("Missing 'type' in expression data")
108
+
109
+ target = _EXPRESSION_REGISTRY.get(type_name)
110
+ if target:
111
+ return target._from_dict_impl(data)
112
+
113
+ raise ValueError(f"Unknown expression type: {type_name}")
114
+
115
+ def to_json(self, compress: bool = False, **kwargs) -> str:
116
+ """序列化为 JSON 字符串"""
117
+ import json
118
+ indent = None if compress else kwargs.get('indent', 2)
119
+ kwargs.pop('indent', None)
120
+ return json.dumps(self.serialize(), indent=indent, **kwargs)
121
+
122
+ def to_pickle(self, protocol: int = None) -> bytes:
123
+ """序列化为 pickle 字节流"""
124
+ import pickle
125
+ import warnings
126
+ warnings.warn(
127
+ "Pickle 序列化存在安全风险,仅在可信环境下使用。",
128
+ UserWarning,
129
+ stacklevel=2
130
+ )
131
+ return pickle.dumps(self, protocol=protocol)
132
+
133
+ @classmethod
134
+ def from_json(cls, json_str: str) -> 'Expression':
135
+ """从 JSON 字符串反序列化"""
136
+ import json
137
+ data = json.loads(json_str)
138
+ return cls.deserialize(data)
139
+
140
+ # =========================================================================
141
+ # 便捷序列化方法
142
+ # =========================================================================
143
+
144
+ def to_bytes(self) -> bytes:
145
+ """JSON 序列化(字节形式)"""
146
+ from QuantNodes.core.serialization import serialize_json_bytes
147
+ return serialize_json_bytes(self)
148
+
149
+ def to_compact(self) -> bytes:
150
+ """紧凑序列化(JSON+zlib 压缩)"""
151
+ from QuantNodes.core.serialization import serialize_compact
152
+ return serialize_compact(self)
153
+
154
+ def to_msgpack(self) -> bytes:
155
+ """msgpack 序列化"""
156
+ from QuantNodes.core.serialization import serialize_msgpack
157
+ return serialize_msgpack(self)
158
+
159
+ def to_proto(self) -> bytes:
160
+ """Protobuf 序列化"""
161
+ from QuantNodes.core.serialization import serialize_proto
162
+ return serialize_proto(self)
163
+
164
+ @classmethod
165
+ def from_proto(cls, data: bytes) -> 'Expression':
166
+ """Protobuf 反序列化"""
167
+ from QuantNodes.core.serialization import deserialize_proto
168
+ return deserialize_proto(data)
169
+
170
+ def to_encrypted(self, key: Union[str, bytes]) -> bytes:
171
+ """加密序列化"""
172
+ from QuantNodes.core.serialization import serialize_encrypted
173
+ return serialize_encrypted(self, key)
174
+
175
+ @classmethod
176
+ def from_encrypted(cls, data: bytes, key: Union[str, bytes]) -> 'Expression':
177
+ """加密反序列化"""
178
+ from QuantNodes.core.serialization import deserialize_encrypted
179
+ return deserialize_encrypted(data, key)
180
+
181
+ @classmethod
182
+ def from_pickle(cls, data: bytes) -> 'Expression':
183
+ """从 pickle 字节流反序列化"""
184
+ import pickle
185
+ import warnings
186
+ warnings.warn(
187
+ "Pickle 反序列化存在安全风险,仅反序列化可信来源的数据。",
188
+ UserWarning,
189
+ stacklevel=2
190
+ )
191
+ return pickle.loads(data)
192
+
193
+ # 紧凑格式 - 类似表达式字符串
194
+ def compact(self) -> str:
195
+ """返回紧凑的字符串表示(类似源码形式)"""
196
+ return repr(self)
197
+
198
+ def __add__(self, other: Any) -> 'BinaryOpExpr':
199
+ return BinaryOpExpr(self, "+", _wrap_expr(other))
200
+
201
+ def __radd__(self, other: Any) -> 'BinaryOpExpr':
202
+ return BinaryOpExpr(_wrap_expr(other), "+", self)
203
+
204
+ def __sub__(self, other: Any) -> 'BinaryOpExpr':
205
+ return BinaryOpExpr(self, "-", _wrap_expr(other))
206
+
207
+ def __rsub__(self, other: Any) -> 'BinaryOpExpr':
208
+ return BinaryOpExpr(_wrap_expr(other), "-", self)
209
+
210
+ def __mul__(self, other: Any) -> 'BinaryOpExpr':
211
+ return BinaryOpExpr(self, "*", _wrap_expr(other))
212
+
213
+ def __rmul__(self, other: Any) -> 'BinaryOpExpr':
214
+ return BinaryOpExpr(_wrap_expr(other), "*", self)
215
+
216
+ def __truediv__(self, other: Any) -> 'BinaryOpExpr':
217
+ return BinaryOpExpr(self, "/", _wrap_expr(other))
218
+
219
+ def __rtruediv__(self, other: Any) -> 'BinaryOpExpr':
220
+ return BinaryOpExpr(_wrap_expr(other), "/", self)
221
+
222
+ def __floordiv__(self, other: Any) -> 'BinaryOpExpr':
223
+ return BinaryOpExpr(self, "//", _wrap_expr(other))
224
+
225
+ def __rfloordiv__(self, other: Any) -> 'BinaryOpExpr':
226
+ return BinaryOpExpr(_wrap_expr(other), "//", self)
227
+
228
+ def __mod__(self, other: Any) -> 'BinaryOpExpr':
229
+ return BinaryOpExpr(self, "%", _wrap_expr(other))
230
+
231
+ def __rmod__(self, other: Any) -> 'BinaryOpExpr':
232
+ return BinaryOpExpr(_wrap_expr(other), "%", self)
233
+
234
+ def __pow__(self, other: Any) -> 'BinaryOpExpr':
235
+ return BinaryOpExpr(self, "**", _wrap_expr(other))
236
+
237
+ def __rpow__(self, other: Any) -> 'BinaryOpExpr':
238
+ return BinaryOpExpr(_wrap_expr(other), "**", self)
239
+
240
+ def __neg__(self) -> 'UnaryOpExpr':
241
+ return UnaryOpExpr("-", self)
242
+
243
+ def __pos__(self) -> 'Expression':
244
+ return self
245
+
246
+ def __abs__(self) -> 'UnaryOpExpr':
247
+ return UnaryOpExpr("abs", self)
248
+
249
+ def __gt__(self, other: Any) -> 'ComparisonExpr':
250
+ return ComparisonExpr(self, ">", _wrap_expr(other))
251
+
252
+ def __ge__(self, other: Any) -> 'ComparisonExpr':
253
+ return ComparisonExpr(self, ">=", _wrap_expr(other))
254
+
255
+ def __lt__(self, other: Any) -> 'ComparisonExpr':
256
+ return ComparisonExpr(self, "<", _wrap_expr(other))
257
+
258
+ def __le__(self, other: Any) -> 'ComparisonExpr':
259
+ return ComparisonExpr(self, "<=", _wrap_expr(other))
260
+
261
+ def __eq__(self, other: Any) -> 'ComparisonExpr': # type: ignore
262
+ return ComparisonExpr(self, "==", _wrap_expr(other))
263
+
264
+ def __ne__(self, other: Any) -> 'ComparisonExpr': # type: ignore
265
+ return ComparisonExpr(self, "!=", _wrap_expr(other))
266
+
267
+ def __and__(self, other: Any) -> 'LogicalOpExpr':
268
+ return LogicalOpExpr("and", self, _wrap_expr(other))
269
+
270
+ def __rand__(self, other: Any) -> 'LogicalOpExpr':
271
+ return LogicalOpExpr("and", _wrap_expr(other), self)
272
+
273
+ def __or__(self, other: Any) -> 'LogicalOpExpr':
274
+ return LogicalOpExpr("or", self, _wrap_expr(other))
275
+
276
+ def __ror__(self, other: Any) -> 'LogicalOpExpr':
277
+ return LogicalOpExpr("or", _wrap_expr(other), self)
278
+
279
+ def __invert__(self) -> 'LogicalOpExpr':
280
+ return LogicalOpExpr("not", self)
281
+
282
+ def method(self, name: str, *args: Any, **kwargs: Any) -> 'MethodCallExpr':
283
+ """方法调用"""
284
+ wrapped_args = tuple(_wrap_expr(a) for a in args)
285
+ wrapped_kwargs = {k: _wrap_expr(v) for k, v in kwargs.items()}
286
+ return MethodCallExpr(self, name, wrapped_args, wrapped_kwargs)
287
+
288
+ def __call__(self, input_data: Any) -> Any:
289
+ """支持直接调用求值"""
290
+ return self.evaluate(input_data)
291
+
292
+ def __bool__(self) -> bool:
293
+ """防止 Python 隐式布尔转换(用于 & / | 运算符)"""
294
+ raise TypeError(
295
+ "Expression 对象不能直接转换为布尔值。"
296
+ "如果你在使用 & 或 | 运算符,请确保两边都是 Expression 对象。"
297
+ "如果你想求值表达式,请使用 .evaluate(data) 方法。"
298
+ )
299
+
300
+
301
+ def _wrap_expr(value: Any) -> Expression:
302
+ """将值包装为表达式"""
303
+ if isinstance(value, ExpressionBuilder):
304
+ return value._expr
305
+ if isinstance(value, Expression):
306
+ return value
307
+ return ConstantExpr(value)
308
+
309
+
310
+ # ============================================================================
311
+ # 原子表达式
312
+ # ============================================================================
313
+
314
+ class InputExpr(Expression):
315
+ """输入数据本身 - 代表整个 input_data"""
316
+
317
+ def evaluate(self, input_data: Any) -> Any:
318
+ return input_data
319
+
320
+ def _get_serializable_fields(self) -> Dict[str, Any]:
321
+ return {}
322
+
323
+ @classmethod
324
+ def _from_dict_impl(cls, data: Dict[str, Any]) -> 'InputExpr':
325
+ return InputExpr()
326
+
327
+ def __repr__(self) -> str:
328
+ return "input"
329
+
330
+
331
+ class ConstantExpr(Expression):
332
+ """常量值表达式"""
333
+
334
+ def __init__(self, value: Any):
335
+ self.value = value
336
+
337
+ def evaluate(self, input_data: Any) -> Any:
338
+ return self.value
339
+
340
+ def _get_serializable_fields(self) -> Dict[str, Any]:
341
+ return {"value": self.value}
342
+
343
+ @classmethod
344
+ def _from_dict_impl(cls, data: Dict[str, Any]) -> 'ConstantExpr':
345
+ return ConstantExpr(data["value"])
346
+
347
+ def __repr__(self) -> str:
348
+ return repr(self.value)
349
+
350
+
351
+ class VariableExpr(Expression):
352
+ """变量/列访问:input_data[name]"""
353
+
354
+ def __init__(self, name: str):
355
+ self.name = name
356
+
357
+ def evaluate(self, input_data: Any) -> Any:
358
+ if isinstance(input_data, dict):
359
+ return input_data[self.name]
360
+ return getattr(input_data, self.name)
361
+
362
+ def _get_serializable_fields(self) -> Dict[str, Any]:
363
+ return {"name": self.name}
364
+
365
+ @classmethod
366
+ def _from_dict_impl(cls, data: Dict[str, Any]) -> 'VariableExpr':
367
+ return VariableExpr(data["name"])
368
+
369
+ def __repr__(self) -> str:
370
+ return f"Cond('{self.name}')"
371
+
372
+
373
+ class AttributeExpr(Expression):
374
+ """属性访问:expr.attr"""
375
+
376
+ def __init__(self, expr: Expression, attr: str):
377
+ self.expr = expr
378
+ self.attr = attr
379
+
380
+ def evaluate(self, input_data: Any) -> Any:
381
+ obj = self.expr.evaluate(input_data)
382
+ return getattr(obj, self.attr)
383
+
384
+ def _get_serializable_fields(self) -> Dict[str, Any]:
385
+ return {
386
+ "expr": self.expr.serialize(),
387
+ "attr": self.attr,
388
+ }
389
+
390
+ @classmethod
391
+ def _from_dict_impl(cls, data: Dict[str, Any]) -> 'AttributeExpr':
392
+ return AttributeExpr(
393
+ Expression.deserialize(data["expr"]),
394
+ data["attr"],
395
+ )
396
+
397
+ def __repr__(self) -> str:
398
+ return f"{self.expr}.{self.attr}"
399
+
400
+
401
+ class SubscriptExpr(Expression):
402
+ """下标访问:expr[key]"""
403
+
404
+ def __init__(self, expr: Expression, key: Any):
405
+ self.expr = expr
406
+ self.key = _wrap_expr(key)
407
+
408
+ def evaluate(self, input_data: Any) -> Any:
409
+ obj = self.expr.evaluate(input_data)
410
+ key_val = self.key.evaluate(input_data)
411
+ return obj[key_val]
412
+
413
+ def _get_serializable_fields(self) -> Dict[str, Any]:
414
+ return {
415
+ "expr": self.expr.serialize(),
416
+ "key": self.key.serialize(),
417
+ }
418
+
419
+ @classmethod
420
+ def _from_dict_impl(cls, data: Dict[str, Any]) -> 'SubscriptExpr':
421
+ return SubscriptExpr(
422
+ Expression.deserialize(data["expr"]),
423
+ Expression.deserialize(data["key"]),
424
+ )
425
+
426
+ def __repr__(self) -> str:
427
+ return f"{self.expr}[{self.key}]"
428
+
429
+
430
+
431
+
432
+ # ============================================================================
433
+ # 方法调用表达式
434
+ # ============================================================================
435
+
436
+ class MethodCallExpr(Expression):
437
+ """方法调用表达式:expr.method(*args, **kwargs)"""
438
+
439
+ def __init__(
440
+ self,
441
+ expr: Expression,
442
+ method: str,
443
+ args: Tuple[Expression, ...],
444
+ kwargs: Dict[str, Expression],
445
+ ):
446
+ if method in FORBIDDEN_METHODS:
447
+ raise ValueError(f"Forbidden method: {method}")
448
+ self.expr = expr
449
+ self.method = method
450
+ self.args = args
451
+ self.kwargs = kwargs
452
+
453
+ def evaluate(self, input_data: Any) -> Any:
454
+ obj = self.expr.evaluate(input_data)
455
+ func = getattr(obj, self.method)
456
+ args_val = tuple(a.evaluate(input_data) for a in self.args)
457
+ kwargs_val = {k: v.evaluate(input_data) for k, v in self.kwargs.items()}
458
+ return func(*args_val, **kwargs_val)
459
+
460
+ def _get_serializable_fields(self) -> Dict[str, Any]:
461
+ return {
462
+ "expr": self.expr.serialize(),
463
+ "method": self.method,
464
+ "args": [a.serialize() for a in self.args],
465
+ "kwargs": {k: v.serialize() for k, v in self.kwargs.items()},
466
+ }
467
+
468
+ @classmethod
469
+ def _from_dict_impl(cls, data: Dict[str, Any]) -> 'MethodCallExpr':
470
+ return MethodCallExpr(
471
+ Expression.deserialize(data["expr"]),
472
+ data["method"],
473
+ tuple(Expression.deserialize(a) for a in data["args"]),
474
+ {k: Expression.deserialize(v) for k, v in data["kwargs"].items()},
475
+ )
476
+
477
+ def __repr__(self) -> str:
478
+ args_str = ", ".join(repr(a) for a in self.args)
479
+ kwargs_str = ", ".join(f"{k}={v}" for k, v in self.kwargs.items())
480
+ all_args = ", ".join(filter(None, [args_str, kwargs_str]))
481
+ return f"{self.expr}.{self.method}({all_args})"
482
+
483
+
484
+ # ============================================================================
485
+ # 运算表达式
486
+ # ============================================================================
487
+
488
+ class BinaryOpExpr(Expression):
489
+ """二元运算表达式"""
490
+
491
+ _OP_MAP = {
492
+ "+": lambda a, b: a + b,
493
+ "-": lambda a, b: a - b,
494
+ "*": lambda a, b: a * b,
495
+ "/": lambda a, b: a / b,
496
+ "//": lambda a, b: a // b,
497
+ "%": lambda a, b: a % b,
498
+ "**": lambda a, b: a ** b,
499
+ }
500
+
501
+ def __init__(self, left: Expression, op: str, right: Expression):
502
+ self.left = left
503
+ self.op = op
504
+ self.right = right
505
+ if op not in self._OP_MAP:
506
+ raise ValueError(f"Unknown operator: {op}")
507
+
508
+ def evaluate(self, input_data: Any) -> Any:
509
+ left_val = self.left.evaluate(input_data)
510
+ right_val = self.right.evaluate(input_data)
511
+ return self._OP_MAP[self.op](left_val, right_val)
512
+
513
+ def _get_serializable_fields(self) -> Dict[str, Any]:
514
+ return {
515
+ "left": self.left.serialize(),
516
+ "op": self.op,
517
+ "right": self.right.serialize(),
518
+ }
519
+
520
+ @classmethod
521
+ def _from_dict_impl(cls, data: Dict[str, Any]) -> 'BinaryOpExpr':
522
+ return BinaryOpExpr(
523
+ Expression.deserialize(data["left"]),
524
+ data["op"],
525
+ Expression.deserialize(data["right"]),
526
+ )
527
+
528
+ def __repr__(self) -> str:
529
+ return f"({self.left} {self.op} {self.right})"
530
+
531
+
532
+ class UnaryOpExpr(Expression):
533
+ """一元运算表达式"""
534
+
535
+ _OP_MAP = {
536
+ "-": lambda x: -x,
537
+ "+": lambda x: x,
538
+ "abs": lambda x: abs(x),
539
+ }
540
+
541
+ def __init__(self, op: str, operand: Expression):
542
+ self.op = op
543
+ self.operand = operand
544
+ if op not in self._OP_MAP:
545
+ raise ValueError(f"Unknown operator: {op}")
546
+
547
+ def evaluate(self, input_data: Any) -> Any:
548
+ val = self.operand.evaluate(input_data)
549
+ return self._OP_MAP[self.op](val)
550
+
551
+ def _get_serializable_fields(self) -> Dict[str, Any]:
552
+ return {
553
+ "op": self.op,
554
+ "operand": self.operand.serialize(),
555
+ }
556
+
557
+ @classmethod
558
+ def _from_dict_impl(cls, data: Dict[str, Any]) -> 'UnaryOpExpr':
559
+ return UnaryOpExpr(
560
+ data["op"],
561
+ Expression.deserialize(data["operand"]),
562
+ )
563
+
564
+ def __repr__(self) -> str:
565
+ return f"{self.op}({self.operand})"
566
+
567
+
568
+ class ComparisonExpr(Expression):
569
+ """比较运算表达式"""
570
+
571
+ _OP_MAP = {
572
+ ">": lambda a, b: a > b,
573
+ ">=": lambda a, b: a >= b,
574
+ "<": lambda a, b: a < b,
575
+ "<=": lambda a, b: a <= b,
576
+ "==": lambda a, b: a == b,
577
+ "!=": lambda a, b: a != b,
578
+ }
579
+
580
+ def __init__(self, left: Expression, op: str, right: Expression):
581
+ self.left = left
582
+ self.op = op
583
+ self.right = right
584
+ if op not in self._OP_MAP:
585
+ raise ValueError(f"Unknown operator: {op}")
586
+
587
+ def evaluate(self, input_data: Any) -> bool:
588
+ left_val = self.left.evaluate(input_data)
589
+ right_val = self.right.evaluate(input_data)
590
+ return self._OP_MAP[self.op](left_val, right_val)
591
+
592
+ def _get_serializable_fields(self) -> Dict[str, Any]:
593
+ return {
594
+ "left": self.left.serialize(),
595
+ "op": self.op,
596
+ "right": self.right.serialize(),
597
+ }
598
+
599
+ @classmethod
600
+ def _from_dict_impl(cls, data: Dict[str, Any]) -> 'ComparisonExpr':
601
+ return ComparisonExpr(
602
+ Expression.deserialize(data["left"]),
603
+ data["op"],
604
+ Expression.deserialize(data["right"]),
605
+ )
606
+
607
+ def __repr__(self) -> str:
608
+ return f"({self.left} {self.op} {self.right})"
609
+
610
+
611
+ class LogicalOpExpr(Expression):
612
+ """逻辑运算表达式"""
613
+
614
+ _OP_MAP = {
615
+ "and": lambda *args: all(args),
616
+ "or": lambda *args: any(args),
617
+ "not": lambda x: not x,
618
+ }
619
+
620
+ def __init__(self, op: str, *operands: Expression):
621
+ self.op = op
622
+ self.operands = operands
623
+ if op not in self._OP_MAP:
624
+ raise ValueError(f"Unknown operator: {op}")
625
+
626
+ def evaluate(self, input_data: Any) -> bool:
627
+ vals = tuple(op.evaluate(input_data) for op in self.operands)
628
+ return self._OP_MAP[self.op](*vals)
629
+
630
+ def _get_serializable_fields(self) -> Dict[str, Any]:
631
+ return {
632
+ "op": self.op,
633
+ "operands": [op.serialize() for op in self.operands],
634
+ }
635
+
636
+ @classmethod
637
+ def _from_dict_impl(cls, data: Dict[str, Any]) -> 'LogicalOpExpr':
638
+ return LogicalOpExpr(
639
+ data["op"],
640
+ *(Expression.deserialize(op) for op in data["operands"]),
641
+ )
642
+
643
+ def __repr__(self) -> str:
644
+ if self.op == "not":
645
+ return f"~{self.operands[0]}"
646
+ return f"({(' ' + self.op + ' ').join(repr(op) for op in self.operands)})"
647
+
648
+
649
+ class LambdaExpression(Expression):
650
+ """包装 Callable,用于向后兼容"""
651
+
652
+ def __init__(self, func: Callable[[Any], Any]):
653
+ self.func = func
654
+
655
+ def evaluate(self, input_data: Any) -> Any:
656
+ return self.func(input_data)
657
+
658
+ def _get_serializable_fields(self) -> Dict[str, Any]:
659
+ return {
660
+ "name": self.func.__name__ if hasattr(self.func, "__name__") else str(self.func),
661
+ }
662
+
663
+ @classmethod
664
+ def _from_dict_impl(cls, data: Dict[str, Any]) -> 'LambdaExpression':
665
+ raise RuntimeError("LambdaExpression cannot be deserialized")
666
+
667
+ def __repr__(self) -> str:
668
+ if hasattr(self.func, "__name__"):
669
+ return f"lambda({self.func.__name__})"
670
+ return f"lambda({str(self.func)})"
671
+
672
+
673
+
674
+
675
+ # ============================================================================
676
+ # DSL 构建器
677
+ # ============================================================================
678
+
679
+ class ExpressionBuilder:
680
+ """
681
+ 表达式构建器,提供链式 API
682
+
683
+ 使用方式:
684
+ >>> Cond('close') > 50 # input_data['close'] > 50
685
+ >>> Cond.attr('metrics').sharpe # input_data.metrics.sharpe
686
+ >>> Cond('value').mean() # input_data['value'].mean()
687
+ """
688
+
689
+ def __init__(self, expr: Expression):
690
+ self._expr = expr
691
+
692
+ def attr(self, name: str) -> 'ExpressionBuilder':
693
+ """按属性名访问"""
694
+ return ExpressionBuilder(AttributeExpr(self._expr, name))
695
+
696
+ def method(self, name: str, *args: Any, **kwargs: Any) -> 'ExpressionBuilder':
697
+ """方法调用"""
698
+ return ExpressionBuilder(self._expr.method(name, *args, **kwargs))
699
+
700
+ def constant(self, value: Any) -> 'ExpressionBuilder':
701
+ """常量值"""
702
+ return ExpressionBuilder(ConstantExpr(value))
703
+
704
+ def __getattr__(self, name: str) -> 'ExpressionBuilder':
705
+ """支持 Cond.metrics 形式的属性访问"""
706
+ return ExpressionBuilder(AttributeExpr(self._expr, name))
707
+
708
+ def __getitem__(self, key: Any) -> 'ExpressionBuilder':
709
+ """支持下标访问 Cond['close']"""
710
+ return ExpressionBuilder(SubscriptExpr(self._expr, key))
711
+
712
+ # ------------------------------------------------------------------------
713
+ # 运算符转发
714
+ # ------------------------------------------------------------------------
715
+
716
+ def __add__(self, other: Any) -> 'ExpressionBuilder':
717
+ return ExpressionBuilder(self._expr + other)
718
+
719
+ def __radd__(self, other: Any) -> 'ExpressionBuilder':
720
+ return ExpressionBuilder(other + self._expr)
721
+
722
+ def __sub__(self, other: Any) -> 'ExpressionBuilder':
723
+ return ExpressionBuilder(self._expr - other)
724
+
725
+ def __rsub__(self, other: Any) -> 'ExpressionBuilder':
726
+ return ExpressionBuilder(other - self._expr)
727
+
728
+ def __mul__(self, other: Any) -> 'ExpressionBuilder':
729
+ return ExpressionBuilder(self._expr * other)
730
+
731
+ def __rmul__(self, other: Any) -> 'ExpressionBuilder':
732
+ return ExpressionBuilder(other * self._expr)
733
+
734
+ def __truediv__(self, other: Any) -> 'ExpressionBuilder':
735
+ return ExpressionBuilder(self._expr / other)
736
+
737
+ def __rtruediv__(self, other: Any) -> 'ExpressionBuilder':
738
+ return ExpressionBuilder(other / self._expr)
739
+
740
+ def __floordiv__(self, other: Any) -> 'ExpressionBuilder':
741
+ return ExpressionBuilder(self._expr // other)
742
+
743
+ def __rfloordiv__(self, other: Any) -> 'ExpressionBuilder':
744
+ return ExpressionBuilder(other // self._expr)
745
+
746
+ def __mod__(self, other: Any) -> 'ExpressionBuilder':
747
+ return ExpressionBuilder(self._expr % other)
748
+
749
+ def __rmod__(self, other: Any) -> 'ExpressionBuilder':
750
+ return ExpressionBuilder(other % self._expr)
751
+
752
+ def __pow__(self, other: Any) -> 'ExpressionBuilder':
753
+ return ExpressionBuilder(self._expr ** other)
754
+
755
+ def __rpow__(self, other: Any) -> 'ExpressionBuilder':
756
+ return ExpressionBuilder(other ** self._expr)
757
+
758
+ def __neg__(self) -> 'ExpressionBuilder':
759
+ return ExpressionBuilder(-self._expr)
760
+
761
+ def __pos__(self) -> 'ExpressionBuilder':
762
+ return ExpressionBuilder(+self._expr)
763
+
764
+ def __abs__(self) -> 'ExpressionBuilder':
765
+ return ExpressionBuilder(abs(self._expr))
766
+
767
+ def __gt__(self, other: Any) -> 'ExpressionBuilder':
768
+ return ExpressionBuilder(self._expr > other)
769
+
770
+ def __ge__(self, other: Any) -> 'ExpressionBuilder':
771
+ return ExpressionBuilder(self._expr >= other)
772
+
773
+ def __lt__(self, other: Any) -> 'ExpressionBuilder':
774
+ return ExpressionBuilder(self._expr < other)
775
+
776
+ def __le__(self, other: Any) -> 'ExpressionBuilder':
777
+ return ExpressionBuilder(self._expr <= other)
778
+
779
+ def __eq__(self, other: Any) -> 'ExpressionBuilder': # type: ignore
780
+ return ExpressionBuilder(self._expr == other)
781
+
782
+ def __ne__(self, other: Any) -> 'ExpressionBuilder': # type: ignore
783
+ return ExpressionBuilder(self._expr != other)
784
+
785
+ def __and__(self, other: Any) -> 'ExpressionBuilder':
786
+ return ExpressionBuilder(self._expr & other)
787
+
788
+ def __rand__(self, other: Any) -> 'ExpressionBuilder':
789
+ return ExpressionBuilder(other & self._expr)
790
+
791
+ def __or__(self, other: Any) -> 'ExpressionBuilder':
792
+ return ExpressionBuilder(self._expr | other)
793
+
794
+ def __ror__(self, other: Any) -> 'ExpressionBuilder':
795
+ return ExpressionBuilder(other | self._expr)
796
+
797
+ def __invert__(self) -> 'ExpressionBuilder':
798
+ return ExpressionBuilder(~self._expr)
799
+
800
+ def __repr__(self) -> str:
801
+ return repr(self._expr)
802
+
803
+ def evaluate(self, input_data: Any) -> Any:
804
+ return self._expr.evaluate(input_data)
805
+
806
+ def serialize(self) -> Dict[str, Any]:
807
+ return self._expr.serialize()
808
+
809
+ def __call__(self, input_data: Any) -> Any:
810
+ return self._expr.evaluate(input_data)
811
+
812
+ def __bool__(self) -> bool:
813
+ """防止 Python 隐式布尔转换"""
814
+ return self._expr.__bool__()
815
+
816
+
817
+ # ============================================================================
818
+ # 表达式类注册表 - 用于反序列化
819
+ # ============================================================================
820
+
821
+ _EXPRESSION_REGISTRY: Dict[str, Type] = {}
822
+
823
+
824
+ def _register_expression_class(cls: Type) -> Type:
825
+ """注册表达式类用于反序列化"""
826
+ _EXPRESSION_REGISTRY[cls.__name__] = cls
827
+ return cls
828
+
829
+
830
+ # 注册所有表达式类
831
+ _register_expression_class(InputExpr)
832
+ _register_expression_class(ConstantExpr)
833
+ _register_expression_class(VariableExpr)
834
+ _register_expression_class(AttributeExpr)
835
+ _register_expression_class(SubscriptExpr)
836
+ _register_expression_class(MethodCallExpr)
837
+ _register_expression_class(BinaryOpExpr)
838
+ _register_expression_class(UnaryOpExpr)
839
+ _register_expression_class(ComparisonExpr)
840
+ _register_expression_class(LogicalOpExpr)
841
+ _register_expression_class(LambdaExpression)