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,673 @@
1
+ # coding=utf-8
2
+ """
3
+ 序列化工具模块 - 提供多种序列化方案
4
+
5
+ 方案对比:
6
+ | 方案 | 安全 | 可读 | 速度 | 跨语言 | 零依赖 | 推荐场景 |
7
+ |-------------|------|------|------|--------|--------|------------------------|
8
+ | JSON | ✅ | ✅ | ⭐⭐ | ✅ | ✅ | 默认、调试、跨系统交互 |
9
+ | JSON+zlib | ✅ | ⚠️ | ⭐⭐⭐| ✅ | ✅ | 网络传输、持久化存储 |
10
+ | msgpack | ✅ | ❌ | ⭐⭐⭐⭐ | ✅ | ❌ | 高性能场景(可选依赖) |
11
+ | pickle | ⚠️ | ❌ | ⭐⭐⭐⭐ | ❌ | ✅ | 仅限可信内部环境 |
12
+
13
+ 使用建议:
14
+ - 开发/调试 -> serialize_json()
15
+ - 网络传输 -> serialize_compact()
16
+ - 极致性能 -> serialize_msgpack() (需要 msgpack)
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ import json
22
+ import zlib
23
+ import warnings
24
+ from typing import Union, Optional
25
+
26
+ from QuantNodes.core.expression import Expression
27
+
28
+
29
+ # ============================================================================
30
+ # 序列化方案
31
+ # ============================================================================
32
+
33
+ def serialize_json(expr, indent: Optional[int] = 2) -> str:
34
+ """
35
+ JSON 序列化 - 默认方案
36
+
37
+ 特点:安全、可读、跨语言、零依赖
38
+ """
39
+ return json.dumps(expr.serialize(), indent=indent, ensure_ascii=False)
40
+
41
+
42
+ def serialize_json_bytes(expr: Expression) -> bytes:
43
+ """JSON 序列化(字节形式)"""
44
+ return serialize_json(expr, indent=None).encode('utf-8')
45
+
46
+
47
+ def serialize_compact(expr, compress_level: int = 6) -> bytes:
48
+ """
49
+ 紧凑序列化 - 推荐用于网络传输
50
+
51
+ JSON + zlib 压缩,零额外依赖
52
+ 压缩率通常可达 30%-50%
53
+ """
54
+ json_bytes = serialize_json_bytes(expr)
55
+ return zlib.compress(json_bytes, level=compress_level)
56
+
57
+
58
+ def serialize_msgpack(expr) -> bytes:
59
+ """
60
+ msgpack 序列化 - 极致性能
61
+
62
+ 要求:pip install msgpack
63
+ 特点:比 JSON 小 30-40%,速度快 2-3 倍
64
+ """
65
+ try:
66
+ import msgpack
67
+ except ImportError:
68
+ raise ImportError(
69
+ "msgpack 未安装。请运行: pip install msgpack"
70
+ ) from None
71
+ return msgpack.packb(expr.serialize(), use_bin_type=True)
72
+
73
+
74
+ def serialize_pickle(expr: Expression, protocol: int = 4) -> bytes:
75
+ """
76
+ Pickle 序列化 - 仅限内部可信环境
77
+
78
+ 警告:存在代码执行安全风险,仅反序列化可信来源的数据!
79
+ """
80
+ import pickle
81
+ warnings.warn(
82
+ "Pickle 序列化存在安全风险,仅在可信内部环境使用。"
83
+ "建议优先使用 serialize_compact() 或 serialize_json()。",
84
+ UserWarning,
85
+ stacklevel=2
86
+ )
87
+ return pickle.dumps(expr, protocol=protocol)
88
+
89
+
90
+ # ============================================================================
91
+ # 反序列化方案
92
+ # ============================================================================
93
+
94
+ def deserialize_json(data: Union[str, bytes]) -> Expression:
95
+ """从 JSON 反序列化"""
96
+ if isinstance(data, bytes):
97
+ data = data.decode('utf-8')
98
+ expr_data = json.loads(data)
99
+ return Expression.from_dict(expr_data)
100
+
101
+
102
+ def deserialize_compact(data: bytes) -> Expression:
103
+ """从紧凑格式(JSON + zlib)反序列化"""
104
+ json_bytes = zlib.decompress(data)
105
+ return deserialize_json(json_bytes)
106
+
107
+
108
+ def deserialize_msgpack(data: bytes) -> Expression:
109
+ """从 msgpack 反序列化"""
110
+ try:
111
+ import msgpack
112
+ except ImportError:
113
+ raise ImportError(
114
+ "msgpack 未安装。请运行: pip install msgpack"
115
+ ) from None
116
+ expr_data = msgpack.unpackb(data, raw=False)
117
+ return Expression.deserialize(expr_data)
118
+
119
+
120
+ def deserialize_pickle(data: bytes) -> Expression:
121
+ """
122
+ 从 pickle 反序列化
123
+
124
+ 警告:仅反序列化可信来源的数据!
125
+ """
126
+ import pickle
127
+ warnings.warn(
128
+ "Pickle 反序列化存在安全风险,仅反序列化可信来源的数据。",
129
+ UserWarning,
130
+ stacklevel=2
131
+ )
132
+ return pickle.loads(data)
133
+
134
+
135
+ # ============================================================================
136
+ # 自动检测反序列化
137
+ # ============================================================================
138
+
139
+ def deserialize_auto(data: Union[str, bytes]) -> Expression:
140
+ """
141
+ 自动检测格式并反序列化
142
+
143
+ 支持:JSON(str/bytes), JSON+zlib(bytes), msgpack(bytes), pickle(bytes)
144
+ """
145
+ if isinstance(data, str):
146
+ return deserialize_json(data)
147
+
148
+ if not isinstance(data, bytes):
149
+ raise TypeError(f"不支持的数据类型: {type(data)}")
150
+
151
+ # 尝试 zlib 压缩格式
152
+ if len(data) >= 2 and data[0:2] == b'x\x9c': # zlib 魔数
153
+ try:
154
+ return deserialize_compact(data)
155
+ except Exception:
156
+ pass
157
+
158
+ # 尝试 msgpack (第一个字节通常是 map 标记 0x80-0x8f)
159
+ if data and 0x80 <= data[0] <= 0x8f:
160
+ try:
161
+ return deserialize_msgpack(data)
162
+ except Exception:
163
+ pass
164
+
165
+ # 尝试 JSON
166
+ try:
167
+ return deserialize_json(data)
168
+ except Exception:
169
+ pass
170
+
171
+ # 最后尝试 pickle(带警告)
172
+ return deserialize_pickle(data)
173
+
174
+
175
+ # ============================================================================
176
+ # Protobuf 序列化 - 高性能跨语言方案
177
+ # ============================================================================
178
+
179
+ _PROTOBUF_AVAILABLE = False
180
+ try:
181
+ import importlib.util
182
+ _PROTOBUF_AVAILABLE = importlib.util.find_spec("google.protobuf") is not None
183
+ except ImportError:
184
+ pass
185
+
186
+
187
+ # TODO [未完成]: 动态生成表达式的 protobuf schema
188
+ #
189
+ # 设计思路:
190
+ # - 当前实现:使用 struct_pb2.Struct 进行通用序列化(见 serialize_proto)
191
+ # - 预期目标:大规模场景下生成专属 .proto 文件以提升性能
192
+ #
193
+ # 完整实现需要:
194
+ # 1. 定义 Expression 的 protobuf 消息结构
195
+ # 2. 动态生成 .proto 描述符
196
+ # 3. 使用 protoc 编译或动态编译
197
+ #
198
+ # 当前状态:stub - 只有 pass,无实际功能
199
+ # 优先级:低 - 当前实现已满足需求
200
+ def _get_proto_descriptor():
201
+ """
202
+ 动态生成表达式的 protobuf schema
203
+
204
+ 说明:不需要预编译 .proto 文件,动态构建描述符
205
+ """
206
+ # 简单实现:先序列化为 dict 再用 protobuf 打包
207
+ # 完整实现需要生成 .proto 文件并编译
208
+ pass
209
+
210
+
211
+ def serialize_proto(expr) -> bytes:
212
+ """
213
+ Protobuf 序列化
214
+
215
+ 要求:pip install protobuf
216
+ 特点:高性能、跨语言、强类型、前向兼容
217
+ """
218
+ if not _PROTOBUF_AVAILABLE:
219
+ raise ImportError(
220
+ "protobuf 未安装。请运行: pip install protobuf"
221
+ )
222
+
223
+ from google.protobuf import struct_pb2
224
+
225
+ data = expr.serialize()
226
+ struct = struct_pb2.Struct()
227
+ struct.update(data)
228
+ return struct.SerializeToString()
229
+
230
+
231
+ def _fix_numbers(obj):
232
+ """递归修复数字类型:Protobuf 会把整数转成浮点数,转换回来"""
233
+ if isinstance(obj, dict):
234
+ return {k: _fix_numbers(v) for k, v in obj.items()}
235
+ elif isinstance(obj, list):
236
+ return [_fix_numbers(v) for v in obj]
237
+ elif isinstance(obj, float) and obj.is_integer():
238
+ return int(obj)
239
+ return obj
240
+
241
+
242
+ def deserialize_proto(data: bytes) -> Expression:
243
+ """从 Protobuf 反序列化"""
244
+ if not _PROTOBUF_AVAILABLE:
245
+ raise ImportError(
246
+ "protobuf 未安装。请运行: pip install protobuf"
247
+ )
248
+
249
+ from google.protobuf import struct_pb2
250
+
251
+ struct = struct_pb2.Struct()
252
+ struct.ParseFromString(data)
253
+
254
+ # 转换为 dict
255
+ from google.protobuf.json_format import MessageToDict
256
+ data_dict = MessageToDict(struct, preserving_proto_field_name=True)
257
+
258
+ # 修复被转成浮点数的整数
259
+ data_dict = _fix_numbers(data_dict)
260
+ return Expression.deserialize(data_dict)
261
+
262
+
263
+ # ============================================================================
264
+ # 加密序列化 - 用于敏感策略保护
265
+ # ============================================================================
266
+
267
+ def serialize_encrypted(
268
+ expr: Expression,
269
+ key: Union[str, bytes],
270
+ algorithm: str = 'AES-GCM'
271
+ ) -> bytes:
272
+ """
273
+ 加密序列化 - 保护敏感策略表达式
274
+
275
+ Args:
276
+ expr: 表达式对象
277
+ key: 加密密钥(字符串或 bytes)
278
+ algorithm: 加密算法(默认 AES-GCM,带认证)
279
+
280
+ 要求:使用 Python 标准库 cryptography
281
+ pip install cryptography
282
+
283
+ 安全特性:
284
+ ✅ AES-256-GCM 加密
285
+ ✅ 带认证标签,防止篡改
286
+ ✅ 随机 nonce,相同明文每次加密结果不同
287
+ ✅ 密钥派生(PBKDF2),支持字符串密码
288
+ """
289
+ try:
290
+ from cryptography.hazmat.primitives.ciphers.aead import AESGCM
291
+ from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
292
+ from cryptography.hazmat.primitives import hashes
293
+ from cryptography.hazmat.backends import default_backend
294
+ except ImportError:
295
+ raise ImportError(
296
+ "cryptography 未安装。请运行: pip install cryptography"
297
+ ) from None
298
+
299
+ import os
300
+
301
+ # 1. 先序列化为紧凑 JSON
302
+ plaintext = expr.to_json(indent=None).encode('utf-8')
303
+
304
+ # 2. 处理密钥
305
+ if isinstance(key, str):
306
+ # 字符串密码 -> 使用 PBKDF2 派生密钥
307
+ salt = os.urandom(16)
308
+ kdf = PBKDF2HMAC(
309
+ algorithm=hashes.SHA256(),
310
+ length=32, # AES-256
311
+ salt=salt,
312
+ iterations=100000,
313
+ backend=default_backend(),
314
+ )
315
+ key_bytes = kdf.derive(key.encode('utf-8'))
316
+ key_type = b'P' # PBKDF2 派生的密钥
317
+ else:
318
+ # 直接使用 bytes 密钥
319
+ key_bytes = key
320
+ salt = b''
321
+ key_type = b'R' # 原始密钥
322
+
323
+ # 3. AES-GCM 加密
324
+ nonce = os.urandom(12) # 96 bits = NIST 推荐
325
+ aesgcm = AESGCM(key_bytes)
326
+ ciphertext = aesgcm.encrypt(nonce, plaintext, None)
327
+
328
+ # 4. 打包:[key_type(1)] + [salt_len(1)] + [salt] + [nonce] + [ciphertext]
329
+ # 格式说明:
330
+ # - key_type: 'P' = 密码派生, 'R' = 原始密钥
331
+ # - salt_len: salt 的长度(原始密钥时为 0)
332
+ # - salt: PBKDF2 的盐值(16 字节)
333
+ # - nonce: AES-GCM 的 nonce(12 字节)
334
+ # - ciphertext: 加密数据 + 16 字节认证标签
335
+ salt_len = len(salt)
336
+ return b''.join([
337
+ key_type,
338
+ bytes([salt_len]),
339
+ salt,
340
+ nonce,
341
+ ciphertext,
342
+ ])
343
+
344
+
345
+ def deserialize_encrypted(
346
+ data: bytes,
347
+ key: Union[str, bytes]
348
+ ) -> Expression:
349
+ """
350
+ 解密反序列化
351
+
352
+ Args:
353
+ data: 加密的字节数据
354
+ key: 解密密钥(字符串或 bytes)
355
+
356
+ Raises:
357
+ cryptography.exceptions.InvalidTag: 密钥错误或数据被篡改
358
+ """
359
+ try:
360
+ from cryptography.hazmat.primitives.ciphers.aead import AESGCM
361
+ from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
362
+ from cryptography.hazmat.primitives import hashes
363
+ from cryptography.hazmat.backends import default_backend
364
+ except ImportError:
365
+ raise ImportError(
366
+ "cryptography 未安装。请运行: pip install cryptography"
367
+ ) from None
368
+
369
+ # 1. 解包
370
+ key_type = data[0:1]
371
+ salt_len = data[1]
372
+ offset = 2
373
+
374
+ salt = data[offset:offset + salt_len]
375
+ offset += salt_len
376
+
377
+ nonce = data[offset:offset + 12]
378
+ offset += 12
379
+
380
+ ciphertext = data[offset:]
381
+
382
+ # 2. 处理密钥
383
+ if key_type == b'P':
384
+ # PBKDF2 密钥派生
385
+ if not isinstance(key, str):
386
+ raise ValueError("数据使用字符串密码加密,请提供字符串密钥")
387
+ kdf = PBKDF2HMAC(
388
+ algorithm=hashes.SHA256(),
389
+ length=32,
390
+ salt=salt,
391
+ iterations=100000,
392
+ backend=default_backend(),
393
+ )
394
+ key_bytes = kdf.derive(key.encode('utf-8'))
395
+ else:
396
+ # 原始密钥
397
+ if isinstance(key, str):
398
+ raise ValueError("数据使用原始密钥加密,请提供 bytes 密钥")
399
+ key_bytes = key
400
+
401
+ # 3. AES-GCM 解密(自动验证认证标签)
402
+ aesgcm = AESGCM(key_bytes)
403
+ plaintext = aesgcm.decrypt(nonce, ciphertext, None)
404
+
405
+ # 4. 反序列化
406
+ return Expression.deserialize(plaintext)
407
+
408
+
409
+ # ============================================================================
410
+ # 节点序列化方案
411
+ # ============================================================================
412
+
413
+ def serialize_node_json(node, indent: Optional[int] = 2) -> str:
414
+ """
415
+ 节点 JSON 序列化
416
+
417
+ Args:
418
+ node: BaseNode 实例
419
+ indent: 缩进空格数,None 表示紧凑格式
420
+
421
+ Returns:
422
+ JSON 字符串
423
+ """
424
+ return json.dumps(node.serialize(), indent=indent, ensure_ascii=False)
425
+
426
+
427
+ def serialize_node_json_bytes(node) -> bytes:
428
+ """节点 JSON 序列化(字节形式)"""
429
+ return serialize_node_json(node, indent=None).encode('utf-8')
430
+
431
+
432
+ def serialize_node_compact(node, compress_level: int = 6) -> bytes:
433
+ """
434
+ 节点紧凑序列化 - 推荐用于网络传输/持久化
435
+
436
+ JSON + zlib 压缩,零额外依赖
437
+ 压缩率通常可达 30%-50%
438
+ """
439
+ json_bytes = serialize_node_json_bytes(node)
440
+ return zlib.compress(json_bytes, level=compress_level)
441
+
442
+
443
+ def serialize_node_msgpack(node) -> bytes:
444
+ """
445
+ 节点 msgpack 序列化 - 极致性能
446
+
447
+ 要求:pip install msgpack
448
+ """
449
+ try:
450
+ import msgpack
451
+ except ImportError:
452
+ raise ImportError(
453
+ "msgpack 未安装。请运行: pip install msgpack"
454
+ ) from None
455
+ return msgpack.packb(node.serialize(), use_bin_type=True)
456
+
457
+
458
+ # ============================================================================
459
+ # 节点反序列化方案
460
+ # ============================================================================
461
+
462
+ def deserialize_node_json(data: Union[str, bytes]):
463
+ """
464
+ 从 JSON 反序列化节点
465
+
466
+ Args:
467
+ data: JSON 字符串或字节
468
+
469
+ Returns:
470
+ BaseNode 实例
471
+ """
472
+ from QuantNodes.core.node import BaseNode
473
+
474
+ if isinstance(data, bytes):
475
+ data = data.decode('utf-8')
476
+ node_data = json.loads(data)
477
+ return BaseNode.deserialize(node_data)
478
+
479
+
480
+ def deserialize_node_compact(data: bytes):
481
+ """
482
+ 从紧凑格式(JSON + zlib)反序列化节点
483
+
484
+ Args:
485
+ data: 压缩的字节数据
486
+
487
+ Returns:
488
+ BaseNode 实例
489
+ """
490
+
491
+ json_bytes = zlib.decompress(data)
492
+ return deserialize_node_json(json_bytes)
493
+
494
+
495
+ def deserialize_node_msgpack(data: bytes):
496
+ """
497
+ 从 msgpack 反序列化节点
498
+
499
+ Args:
500
+ data: msgpack 字节数据
501
+
502
+ Returns:
503
+ BaseNode 实例
504
+ """
505
+ from QuantNodes.core.node import BaseNode
506
+
507
+ try:
508
+ import msgpack
509
+ except ImportError:
510
+ raise ImportError(
511
+ "msgpack 未安装。请运行: pip install msgpack"
512
+ ) from None
513
+ node_data = msgpack.unpackb(data, raw=False)
514
+ return BaseNode.deserialize(node_data)
515
+
516
+
517
+ # ============================================================================
518
+ # 节点自动检测反序列化
519
+ # ============================================================================
520
+
521
+ def deserialize_node_auto(data: Union[str, bytes]):
522
+ """
523
+ 自动检测格式并反序列化节点
524
+
525
+ 支持:JSON(str/bytes), JSON+zlib(bytes), msgpack(bytes)
526
+ """
527
+ if isinstance(data, str):
528
+ return deserialize_node_json(data)
529
+
530
+ if not isinstance(data, bytes):
531
+ raise TypeError(f"不支持的数据类型: {type(data)}")
532
+
533
+ # 尝试 zlib 压缩格式
534
+ if len(data) >= 2 and data[0:2] == b'x\x9c':
535
+ try:
536
+ return deserialize_node_compact(data)
537
+ except Exception:
538
+ pass
539
+
540
+ # 尝试 msgpack (第一个字节通常是 map 标记 0x80-0x8f)
541
+ if data and 0x80 <= data[0] <= 0x8f:
542
+ try:
543
+ return deserialize_node_msgpack(data)
544
+ except Exception:
545
+ pass
546
+
547
+ # 尝试 JSON
548
+ return deserialize_node_json(data)
549
+
550
+
551
+ # ============================================================================
552
+ # 节点加密序列化
553
+ # ============================================================================
554
+
555
+ def serialize_node_encrypted(node, key: Union[str, bytes]) -> bytes:
556
+ """
557
+ 节点加密序列化 - 保护敏感策略
558
+
559
+ Args:
560
+ node: BaseNode 实例
561
+ key: 加密密钥(字符串或 bytes)
562
+
563
+ 要求:pip install cryptography
564
+ """
565
+ try:
566
+ from cryptography.hazmat.primitives.ciphers.aead import AESGCM
567
+ from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
568
+ from cryptography.hazmat.primitives import hashes
569
+ from cryptography.hazmat.backends import default_backend
570
+ except ImportError:
571
+ raise ImportError(
572
+ "cryptography 未安装。请运行: pip install cryptography"
573
+ ) from None
574
+
575
+ import os
576
+
577
+ # 1. 先序列化为紧凑 JSON
578
+ plaintext = node.serialize()
579
+ plaintext_bytes = json.dumps(plaintext, separators=(',', ':')).encode('utf-8')
580
+
581
+ # 2. 处理密钥
582
+ if isinstance(key, str):
583
+ salt = os.urandom(16)
584
+ kdf = PBKDF2HMAC(
585
+ algorithm=hashes.SHA256(),
586
+ length=32,
587
+ salt=salt,
588
+ iterations=100000,
589
+ backend=default_backend(),
590
+ )
591
+ key_bytes = kdf.derive(key.encode('utf-8'))
592
+ key_type = b'P'
593
+ else:
594
+ key_bytes = key
595
+ salt = b''
596
+ key_type = b'R'
597
+
598
+ # 3. AES-GCM 加密
599
+ nonce = os.urandom(12)
600
+ aesgcm = AESGCM(key_bytes)
601
+ ciphertext = aesgcm.encrypt(nonce, plaintext_bytes, None)
602
+
603
+ # 4. 打包
604
+ salt_len = len(salt)
605
+ return b''.join([
606
+ key_type,
607
+ bytes([salt_len]),
608
+ salt,
609
+ nonce,
610
+ ciphertext,
611
+ ])
612
+
613
+
614
+ def deserialize_node_encrypted(data: bytes, key: Union[str, bytes]):
615
+ """
616
+ 解密反序列化节点
617
+
618
+ Args:
619
+ data: 加密的字节数据
620
+ key: 解密密钥
621
+ """
622
+ try:
623
+ from cryptography.hazmat.primitives.ciphers.aead import AESGCM
624
+ from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
625
+ from cryptography.hazmat.primitives import hashes
626
+ from cryptography.hazmat.backends import default_backend
627
+ except ImportError:
628
+ raise ImportError(
629
+ "cryptography 未安装。请运行: pip install cryptography"
630
+ ) from None
631
+
632
+ # 1. 解包
633
+ key_type = data[0:1]
634
+ salt_len = data[1]
635
+ offset = 2
636
+
637
+ salt = data[offset:offset + salt_len]
638
+ offset += salt_len
639
+
640
+ nonce = data[offset:offset + 12]
641
+ offset += 12
642
+
643
+ ciphertext = data[offset:]
644
+
645
+ # 2. 处理密钥
646
+ if key_type == b'P':
647
+ if not isinstance(key, str):
648
+ raise ValueError("数据使用字符串密码加密,请提供字符串密钥")
649
+ kdf = PBKDF2HMAC(
650
+ algorithm=hashes.SHA256(),
651
+ length=32,
652
+ salt=salt,
653
+ iterations=100000,
654
+ backend=default_backend(),
655
+ )
656
+ key_bytes = kdf.derive(key.encode('utf-8'))
657
+ else:
658
+ if isinstance(key, str):
659
+ raise ValueError("数据使用原始密钥加密,请提供 bytes 密钥")
660
+ key_bytes = key
661
+
662
+ # 3. AES-GCM 解密
663
+ aesgcm = AESGCM(key_bytes)
664
+ plaintext = aesgcm.decrypt(nonce, ciphertext, None)
665
+
666
+ # 4. 反序列化
667
+ return deserialize_node_json(plaintext)
668
+
669
+
670
+ # 注:原 _update_expression_serialization() 已删除 (Phase F, 2026-06-20)。
671
+ # 该函数原本通过 monkey patching 给 Expression 类注入 to_proto/from_proto 等方法,
672
+ # 已被 expression.py 中的直接实现取代 (expression.py:159-179), 无外部 caller。
673
+ # 详见 git log: 历史 commit 9b8a64c 引入后, 2026-05 改写为直接方法。