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,398 @@
1
+ # coding=utf-8
2
+ """``quantnodes serve / stop / status / logs`` — backend lifecycle.
3
+
4
+ v3.1.0: Zero-subprocess architecture.
5
+
6
+ Commands:
7
+ serve — 启动 FastAPI (+ nanobot gateway), 可选前端/ MCP
8
+ stop — 通过 pidfile 停止 serve
9
+ status — 打印 health + /api/agent/status JSON
10
+ logs — tail -f logs/quantnodes_serve.log
11
+
12
+ Design:
13
+ - serve 直接调用 uvicorn.Server.run() (同进程, 无子进程)
14
+ - --daemon 时双 fork 脱离终端, 写 .quantnodes.pid
15
+ - --frontend 时 spawn npm dev server (subprocess, lifespan 管理)
16
+ - --mcp 时 spawn MCP server (subprocess, 供外部客户端)
17
+ - 前台时 Ctrl+C 直接终止 (所有组件 in-process)
18
+ """
19
+ from __future__ import annotations
20
+
21
+ import json
22
+ import os
23
+ import signal
24
+ import subprocess
25
+ import sys
26
+ from pathlib import Path
27
+ from typing import Optional
28
+
29
+ from QuantNodes.cli.command import Command
30
+
31
+ from QuantNodes.constants import DEFAULT_WEBSOCKET_PORT
32
+
33
+ from .._helpers import (
34
+ DEFAULT_API_PORT,
35
+ DEFAULT_FRONTEND_PORT,
36
+ DEFAULT_GATEWAY_PORT,
37
+ DEFAULT_HOST,
38
+ PIDFILE_NAME,
39
+ get_project_root,
40
+ is_pid_alive,
41
+ is_port_free,
42
+ print_nanobot_install_hint,
43
+ read_pidfile,
44
+ remove_pidfile,
45
+ wait_for_health,
46
+ write_pidfile,
47
+ )
48
+
49
+
50
+ def _read_gateway_token() -> str:
51
+ """Read the gateway tokenIssueSecret from .agent/nanobot_config.json."""
52
+ try:
53
+ cfg_path = get_project_root() / ".agent" / "nanobot_config.json"
54
+ if cfg_path.exists():
55
+ cfg = json.loads(cfg_path.read_text(encoding="utf-8"))
56
+ return cfg.get("channels", {}).get("websocket", {}).get("token", "")
57
+ except Exception:
58
+ pass
59
+ return ""
60
+
61
+
62
+ def _log_dir() -> Path:
63
+ """Return logs/ dir at project root, creating it on first call."""
64
+ log_dir = get_project_root() / "logs"
65
+ log_dir.mkdir(parents=True, exist_ok=True)
66
+ return log_dir
67
+
68
+
69
+ def _serve_log_path() -> Path:
70
+ """Path to the rolling serve log file."""
71
+ return _log_dir() / "quantnodes_serve.log"
72
+
73
+
74
+ def _start_frontend(host: str, frontend_port: int, api_port: int,
75
+ gateway_port: int = DEFAULT_GATEWAY_PORT) -> subprocess.Popen:
76
+ """Spawn Vite dev server (npm run dev) with HOST/PORT/API_PORT injected.
77
+
78
+ The frontend subprocess lifecycle is managed by the caller's finally
79
+ block (terminate on shutdown).
80
+ """
81
+ env = os.environ.copy()
82
+ env["HOST"] = host
83
+ env["PORT"] = str(frontend_port)
84
+ env["API_PORT"] = str(api_port)
85
+ env["GATEWAY_PORT"] = str(gateway_port)
86
+ env["VITE_NANOBOT_GATEWAY_URL"] = f"http://{host}:{gateway_port}/"
87
+ return subprocess.Popen(
88
+ ["npm", "run", "dev"],
89
+ cwd=str(get_project_root() / "frontend"),
90
+ env=env,
91
+ )
92
+
93
+
94
+ def _start_mcp_server(host: str, port: int) -> subprocess.Popen:
95
+ """Spawn MCP server as HTTP subprocess for external clients.
96
+
97
+ The MCP server exposes quant tools over MCP protocol (HTTP transport)
98
+ so that Claude Desktop, Cursor, etc. can connect.
99
+ """
100
+ cmd = [
101
+ sys.executable, "-m", "QuantNodes.mcp_server",
102
+ "--transport", "http",
103
+ "--host", host,
104
+ "--port", str(port),
105
+ ]
106
+ return subprocess.Popen(
107
+ cmd, cwd=str(get_project_root()),
108
+ stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
109
+ )
110
+
111
+
112
+ def _print_startup_info(args, pid: int) -> None:
113
+ """Print startup info (used in daemon mode)."""
114
+ api_url = f"http://{args.host}:{args.port}"
115
+ gateway_url = f"http://{args.host}:{args.gateway_port}"
116
+ log_path = _serve_log_path()
117
+ print("=" * 50)
118
+ print("✓ QuantNodes 已后台启动")
119
+ print("=" * 50)
120
+ print(f" API: {api_url}")
121
+ print(f" WebUI: {gateway_url}/")
122
+ _token = _read_gateway_token()
123
+ if _token:
124
+ print(f" Token: {_token}")
125
+ if getattr(args, "mcp", False):
126
+ print(f" MCP: http://{args.host}:{getattr(args, 'mcp_port', DEFAULT_WEBSOCKET_PORT)}/")
127
+ print(f" PID: {pid} 日志: {log_path}")
128
+ print(f" 停止: quantnodes stop")
129
+ print(f" 状态: quantnodes status")
130
+ print()
131
+ print_nanobot_install_hint()
132
+
133
+
134
+ def _kill_procs(*procs: Optional[subprocess.Popen]) -> None:
135
+ """Terminate a list of subprocesses gracefully, with SIGKILL fallback."""
136
+ for proc in procs:
137
+ if proc is None or proc.poll() is not None:
138
+ continue
139
+ proc.terminate()
140
+ try:
141
+ proc.wait(timeout=5)
142
+ except subprocess.TimeoutExpired:
143
+ proc.kill()
144
+
145
+
146
+ def cmd_serve(args) -> int:
147
+ """Start the QuantNodes backend.
148
+
149
+ Foreground by default; --daemon double-forks and writes .quantnodes.pid.
150
+ uvicorn runs in-process (no subprocess) for clean signal handling.
151
+ """
152
+ if not load_env_quietly():
153
+ print("⚠ .env 未找到(继续运行,部分功能可能受限)")
154
+ print(" 建议运行: quantnodes init 生成 .env")
155
+
156
+ # 1. Port conflict detection
157
+ if not is_port_free(args.port):
158
+ print(f"✗ 后端端口 {args.port} 已被占用")
159
+ print(f" 提示: 用 --port 换其他端口 (默认 {DEFAULT_API_PORT})")
160
+ return 1
161
+ if not is_port_free(args.gateway_port):
162
+ print(f"✗ nanobot gateway 端口 {args.gateway_port} 已被占用")
163
+ if args.gateway_port == 18080:
164
+ print(" 提示: 18080 常被 gpustack 等占用,建议换 --gateway-port 18090")
165
+ print(f" 当前默认: {DEFAULT_GATEWAY_PORT}")
166
+ return 1
167
+ if getattr(args, "mcp", False) and not is_port_free(getattr(args, "mcp_port", DEFAULT_WEBSOCKET_PORT)):
168
+ print(f"✗ MCP server 端口 {args.mcp_port} 已被占用")
169
+ return 1
170
+
171
+ # 2. --check-env
172
+ if args.check_env and not os.environ.get("QUANTNODES__LLM__API_KEY"):
173
+ print("✗ .env 中缺少 QUANTNODES__LLM__API_KEY")
174
+ print(" 请运行: quantnodes init 或手动编辑 .env")
175
+ return 1
176
+
177
+ # 3. Set environment variables (for lifespan / nanobot)
178
+ os.environ["NANOBOT_GATEWAY_HOST"] = args.host
179
+ os.environ["NANOBOT_GATEWAY_PORT"] = str(args.gateway_port)
180
+
181
+ # 4. Optional frontend subprocess
182
+ frontend_proc: Optional[subprocess.Popen] = None
183
+ if args.frontend:
184
+ frontend_proc = _start_frontend(args.host, args.frontend_port, args.port,
185
+ gateway_port=args.gateway_port)
186
+
187
+ # 5. Optional MCP server subprocess
188
+ mcp_proc: Optional[subprocess.Popen] = None
189
+ if getattr(args, "mcp", False):
190
+ mcp_proc = _start_mcp_server(args.host, getattr(args, "mcp_port", DEFAULT_WEBSOCKET_PORT))
191
+
192
+ # 6. Daemon mode: double-fork to detach from terminal
193
+ if args.daemon:
194
+ # Fork 1: exit parent, child becomes session leader
195
+ if os.fork() > 0:
196
+ _kill_procs(frontend_proc, mcp_proc)
197
+ sys.exit(0)
198
+ os.setsid()
199
+ # Fork 2: prevent re-acquiring controlling terminal
200
+ if os.fork() > 0:
201
+ sys.exit(0)
202
+ # Redirect stdio to log file
203
+ sys.stdin = open(os.devnull)
204
+ log_path = _serve_log_path()
205
+ log_fd = open(log_path, "a")
206
+ sys.stdout = sys.stderr = log_fd
207
+ write_pidfile(os.getpid())
208
+ _print_startup_info(args, os.getpid())
209
+
210
+ # 7. Run uvicorn in-process (blocking)
211
+ import uvicorn
212
+ config = uvicorn.Config(
213
+ "api.main:app",
214
+ host=args.host,
215
+ port=args.port,
216
+ log_level="info",
217
+ )
218
+ server = uvicorn.Server(config)
219
+
220
+ # Signal: SIGTERM → graceful shutdown
221
+ def _shutdown(sig, frame):
222
+ server.should_exit = True
223
+ signal.signal(signal.SIGTERM, _shutdown)
224
+
225
+ try:
226
+ server.run()
227
+ except KeyboardInterrupt:
228
+ pass
229
+ finally:
230
+ _kill_procs(frontend_proc, mcp_proc)
231
+ if not args.daemon:
232
+ remove_pidfile()
233
+
234
+ return 0
235
+
236
+
237
+ def load_env_quietly() -> bool:
238
+ """Call load_env_file without printing on missing optional dep."""
239
+ try:
240
+ from .._helpers import load_env_file
241
+ return load_env_file()
242
+ except Exception:
243
+ return False
244
+
245
+
246
+ def cmd_stop(args) -> int:
247
+ """Send SIGTERM to the PID stored in .quantnodes.pid."""
248
+ pid = read_pidfile()
249
+ if pid is None:
250
+ print(f"未找到 {PIDFILE_NAME},服务可能未启动或已手动停止")
251
+ return 1
252
+ if not is_pid_alive(pid):
253
+ print(f"PID {pid} 不存在(stale pidfile,已清理)")
254
+ remove_pidfile()
255
+ return 0
256
+ try:
257
+ os.kill(pid, signal.SIGTERM)
258
+ print(f"✓ 已发送 SIGTERM 到 PID {pid}")
259
+ except ProcessLookupError:
260
+ print(f"PID {pid} 已退出")
261
+ except PermissionError:
262
+ print(f"✗ 无权终止 PID {pid}(可能属于其他用户)")
263
+ return 1
264
+ remove_pidfile()
265
+ print(f" pidfile 已清理: {PIDFILE_NAME}")
266
+ return 0
267
+
268
+
269
+ def cmd_status(args) -> int:
270
+ """Print pidfile + health endpoint + /api/agent/status as one JSON summary."""
271
+ api_url = args.api_url.rstrip("/")
272
+ pid = read_pidfile()
273
+ pid_alive = is_pid_alive(pid) if pid else False
274
+
275
+ summary: dict = {
276
+ "pidfile": {
277
+ "path": str(Path.cwd() / PIDFILE_NAME),
278
+ "pid": pid,
279
+ "alive": pid_alive,
280
+ },
281
+ "api_url": api_url,
282
+ }
283
+
284
+ try:
285
+ import httpx
286
+ r = httpx.get(f"{api_url}/api/agent/status", timeout=3.0)
287
+ if r.status_code == 200:
288
+ summary["agent_status"] = r.json()
289
+ summary["reachable"] = True
290
+ else:
291
+ summary["reachable"] = False
292
+ summary["http_status"] = r.status_code
293
+ except Exception as e:
294
+ summary["reachable"] = False
295
+ summary["error"] = str(e)
296
+
297
+ import json
298
+ print(json.dumps(summary, indent=2, ensure_ascii=False))
299
+ return 0 if summary.get("agent_status", {}).get("state") == "running" else 1
300
+
301
+
302
+ def cmd_logs(args) -> int:
303
+ """tail -f logs/quantnodes_serve.log (or cat if --no-follow)."""
304
+ log_path = _serve_log_path()
305
+ if not log_path.is_file():
306
+ print(f"日志文件不存在: {log_path}")
307
+ print("(需要先运行 quantnodes serve)")
308
+ return 1
309
+ if args.follow:
310
+ try:
311
+ subprocess.run(["tail", "-F", "-n", "+1", str(log_path)])
312
+ except KeyboardInterrupt:
313
+ pass
314
+ else:
315
+ try:
316
+ subprocess.run(["tail", "-n", "200", str(log_path)])
317
+ except FileNotFoundError:
318
+ text = log_path.read_text(encoding="utf-8", errors="replace")
319
+ lines = text.splitlines()[-200:]
320
+ print("\n".join(lines))
321
+ return 0
322
+
323
+
324
+ # ============================================================================
325
+ # Command classes (registry pattern)
326
+ # ============================================================================
327
+
328
+ class ServeCommand(Command):
329
+ """``quantnodes serve`` — 启动后端(+ 可选前端/MCP)."""
330
+
331
+ name = "serve"
332
+ description = "启动 QuantNodes 后端(FastAPI + nanobot gateway)"
333
+
334
+ def add_arguments(self, subparsers) -> None:
335
+ p = subparsers.add_parser(self.name, help=self.description)
336
+ p.add_argument("--host", default=DEFAULT_HOST, help=f"绑定主机 (默认 {DEFAULT_HOST})")
337
+ p.add_argument("--port", type=int, default=DEFAULT_API_PORT,
338
+ help=f"后端端口 (默认 {DEFAULT_API_PORT})")
339
+ p.add_argument("--gateway-port", type=int, default=DEFAULT_GATEWAY_PORT,
340
+ help=f"nanobot WebSocket gateway 端口 (默认 {DEFAULT_GATEWAY_PORT})")
341
+ p.add_argument("--frontend", action="store_true",
342
+ help="同时启动 Vite dev server (开发模式)")
343
+ p.add_argument("--frontend-port", type=int, default=DEFAULT_FRONTEND_PORT,
344
+ help=f"前端端口 (默认 {DEFAULT_FRONTEND_PORT})")
345
+ p.add_argument("--mcp", action="store_true",
346
+ help="同时启动 MCP server (供 Claude Desktop / Cursor 等外部客户端)")
347
+ p.add_argument("--mcp-port", type=int, default=DEFAULT_WEBSOCKET_PORT,
348
+ help=f"MCP server HTTP 端口 (默认 {DEFAULT_WEBSOCKET_PORT})")
349
+ p.add_argument("--daemon", action="store_true",
350
+ help="后台运行,写入 .quantnodes.pid")
351
+ p.add_argument("--check-env", action="store_true",
352
+ help="启动前校验 .env 中 QUANTNODES__LLM__API_KEY")
353
+
354
+ def run(self, args) -> int:
355
+ return cmd_serve(args)
356
+
357
+
358
+ class StopCommand(Command):
359
+ """``quantnodes stop`` — 停止 serve(通过 .quantnodes.pid)."""
360
+
361
+ name = "stop"
362
+ description = "通过 pidfile 停止 quantnodes serve"
363
+
364
+ def add_arguments(self, subparsers) -> None:
365
+ subparsers.add_parser(self.name, help=self.description)
366
+
367
+ def run(self, args) -> int:
368
+ return cmd_stop(args)
369
+
370
+
371
+ class StatusCommand(Command):
372
+ """``quantnodes status`` — 综合服务状态(pidfile + /api/agent/status)."""
373
+
374
+ name = "status"
375
+ description = "查服务运行状态(pidfile + /api/agent/status)"
376
+
377
+ def add_arguments(self, subparsers) -> None:
378
+ p = subparsers.add_parser(self.name, help=self.description)
379
+ p.add_argument("--api-url", default=f"http://{DEFAULT_HOST}:{DEFAULT_API_PORT}",
380
+ help=f"FastAPI base URL (默认 http://{DEFAULT_HOST}:{DEFAULT_API_PORT})")
381
+
382
+ def run(self, args) -> int:
383
+ return cmd_status(args)
384
+
385
+
386
+ class LogsCommand(Command):
387
+ """``quantnodes logs`` — 查看 / tail serve 日志."""
388
+
389
+ name = "logs"
390
+ description = "查看 serve 日志 (logs/quantnodes_serve.log)"
391
+
392
+ def add_arguments(self, subparsers) -> None:
393
+ p = subparsers.add_parser(self.name, help=self.description)
394
+ p.add_argument("-f", "--follow", action="store_true",
395
+ help="实时滚动 (默认只打印最后 200 行)")
396
+
397
+ def run(self, args) -> int:
398
+ return cmd_logs(args)
@@ -0,0 +1,120 @@
1
+ # coding=utf-8
2
+ """``quantnodes version`` and ``quantnodes help`` commands.
3
+
4
+ Phase 3.1 (2026-06-22): 改为 Command pattern — VersionCommand + HelpCommand.
5
+ 旧的 cmd_version / cmd_help 函数保留作 backward compat.
6
+ """
7
+
8
+ from QuantNodes import __version__
9
+ from QuantNodes.cli.command import Command
10
+
11
+
12
+ def cmd_version(args) -> int:
13
+ """Show version information."""
14
+ print(f"QuantNodes version {__version__}")
15
+ return 0
16
+
17
+
18
+ def cmd_help(args) -> int:
19
+ """Show help message."""
20
+ print("""
21
+ QuantNodes CLI - 量化研究节点架构命令行工具
22
+
23
+ 用法:
24
+ quantnodes <命令> [选项]
25
+
26
+ 命令:
27
+ init 初始化当前目录
28
+ run 启动服务
29
+ chat 启动 Agent 对话模式
30
+ evolve 多轮演化主入口 (Week 5)
31
+ factor-info 显示 TrajectoryPool 统计 (Week 5)
32
+ factor-best 显示 Top-N 最佳 entry (Week 5)
33
+ factor-visual 生成可视化 HTML 报告 (Week 6)
34
+ factor-rag-show RAG 检索演示 (Week 7)
35
+ factor-rag-eval 批量评估 RAG 质量 (Week 10)
36
+ factor-data-fetch 从 iFinD 拉取数据 + 写 H5 (Week 12)
37
+ factor-dashboard 生成 3 类指标 dashboard (Week 13)
38
+ version 显示版本
39
+ help 显示帮助
40
+
41
+ evolve 选项:
42
+ --config PATH YAML 配置文件路径 (必填)
43
+ --directions LIST 逗号分隔的研究方向
44
+ --initial-json JSON 初始 candidates JSON
45
+ --max-rounds N 覆盖 config.evolution.max_rounds
46
+ --early-stop N 覆盖 config.evolution.early_stop_patience
47
+
48
+ factor-info / factor-best / factor-visual / factor-rag-show 选项:
49
+ --pool-dir PATH TrajectoryPool 目录
50
+ --top N Top-N (默认 5, 仅 factor-best/rag-show)
51
+ --metric NAME 排序指标 (默认 sharpe, 仅 factor-best/visual)
52
+ --output PATH HTML 输出路径 (仅 factor-visual)
53
+ --title TITLE 报告标题 (仅 factor-visual)
54
+ --query TEXT 查询文本 (仅 factor-rag-show)
55
+ --compress 启用谱系压缩 (Week 9, 仅 factor-rag-show)
56
+ --ancestor-depth N 祖先深度 (默认 2, 仅 --compress)
57
+ --descendant-depth N 后裔深度 (默认 2, 仅 --compress)
58
+ --max-tokens N 压缩最大字符数 (默认 200, 仅 --compress)
59
+
60
+ init 选项:
61
+ --force 强制重新初始化 (覆盖现有配置)
62
+
63
+ run 选项:
64
+ --host HOST 绑定主机 (默认: localhost)
65
+ --port PORT 前端端口 (默认: 5173),设置后后端端口自动设为 PORT+1000
66
+ --api-port PORT 后端端口 (默认: 19380),优先级高于 --port 联动
67
+ --daemon 后台运行 (仅 Linux)
68
+ --api-only 仅启动后端
69
+ --frontend-only 仅启动前端
70
+
71
+ 示例:
72
+ quantnodes init
73
+ quantnodes run # 前端:5173, 后端:19380
74
+ quantnodes run --port 18380 # 前端:18380, 后端:19380 (联动)
75
+ quantnodes run --port 18380 --api-port 9000 # 前端:18380, 后端:9000 (指定后端)
76
+ quantnodes run --daemon
77
+ quantnodes run --api-only
78
+ quantnodes evolve --config configs/evolve.yaml \\
79
+ --directions momentum,reversal --max-rounds 3 --workers 4
80
+ quantnodes factor-info --pool-dir output/trajectory
81
+ quantnodes factor-best --pool-dir output/trajectory --top 10 --metric sharpe
82
+ quantnodes factor-visual --pool-dir output/trajectory --output report.html
83
+ quantnodes factor-rag-show --pool-dir output/trajectory \\
84
+ --query "momentum effect" --top 5
85
+ quantnodes factor-rag-eval --pool-dir output/trajectory \\
86
+ --queries "momentum,reversal" --top 5
87
+ quantnodes factor-data-fetch --output-dir /tmp/real_data/ \\
88
+ --date-beg 20260101 --factors momentum_20d,reversal_5d
89
+ quantnodes factor-dashboard --pool-dir output/trajectory --output dashboard.html
90
+ quantnodes version
91
+
92
+ 详细文档: docs/QuickStart.md
93
+ """)
94
+ return 0
95
+
96
+
97
+ class VersionCommand(Command):
98
+ """``quantnodes version`` subcommand."""
99
+
100
+ name = "version"
101
+ description = "显示版本"
102
+
103
+ def add_arguments(self, subparsers) -> None:
104
+ subparsers.add_parser(self.name, help=self.description)
105
+
106
+ def run(self, args) -> int:
107
+ return cmd_version(args)
108
+
109
+
110
+ class HelpCommand(Command):
111
+ """``quantnodes help`` subcommand."""
112
+
113
+ name = "help"
114
+ description = "显示帮助"
115
+
116
+ def add_arguments(self, subparsers) -> None:
117
+ subparsers.add_parser(self.name, help=self.description)
118
+
119
+ def run(self, args) -> int:
120
+ return cmd_help(args)
@@ -0,0 +1,146 @@
1
+ # coding=utf-8
2
+ """
3
+ Enhanced CLI - Rich Agent 交互终端
4
+
5
+ 提供流式输出、Markdown 渲染、命令历史的 Agent 对话界面。
6
+ """
7
+
8
+ import asyncio
9
+
10
+ from rich.console import Console
11
+ from rich.markdown import Markdown
12
+ from rich.panel import Panel
13
+ from rich.text import Text
14
+
15
+
16
+ console = Console()
17
+
18
+
19
+ async def _stream_chat(agent, message: str) -> None:
20
+ """流式输出 Agent 响应"""
21
+ full_response = ""
22
+ try:
23
+ async for chunk in agent.chat(message):
24
+ if chunk:
25
+ full_response += chunk
26
+ console.print(chunk, end="", highlight=False)
27
+ console.print()
28
+ except Exception as e:
29
+ console.print(f"[red]Error: {e}[/red]")
30
+ return
31
+
32
+ if full_response:
33
+ console.print()
34
+ try:
35
+ console.print(Markdown(full_response))
36
+ except Exception:
37
+ pass
38
+
39
+
40
+ def _print_welcome() -> None:
41
+ """打印欢迎信息"""
42
+ welcome = Text()
43
+ welcome.append("QuantNodes Agent", style="bold cyan")
44
+ welcome.append(" - 量化研究智能助手\n", style="dim")
45
+ welcome.append("输入问题开始对话,", style="dim")
46
+ welcome.append("exit", style="bold")
47
+ welcome.append(" 退出\n", style="dim")
48
+ console.print(Panel(welcome, border_style="cyan"))
49
+
50
+
51
+ def _print_help() -> None:
52
+ """打印帮助信息"""
53
+ help_text = """
54
+ **可用命令:**
55
+ - `exit` / `quit` / `q` - 退出
56
+ - `help` - 显示此帮助
57
+ - `clear` - 清屏
58
+ - `history` - 查看对话历史
59
+ - 直接输入文本开始对话
60
+ """
61
+ console.print(Markdown(help_text))
62
+
63
+
64
+ def chat(workspace: str = ".", config: dict = None) -> None:
65
+ """启动 Agent 对话模式
66
+
67
+ Args:
68
+ workspace: 工作目录
69
+ config: Agent 配置
70
+ """
71
+ from QuantNodes.agent import Agent
72
+
73
+ console.print("[bold cyan]正在初始化 Agent...[/bold cyan]")
74
+
75
+ try:
76
+ agent = Agent(workspace=workspace, config=config or {})
77
+ except Exception as e:
78
+ console.print(f"[red]Agent 初始化失败: {e}[/red]")
79
+ return
80
+
81
+ _print_welcome()
82
+
83
+ history: list[str] = []
84
+
85
+ while True:
86
+ try:
87
+ user_input = console.input("[bold green]> [/bold green]").strip()
88
+ except (EOFError, KeyboardInterrupt):
89
+ console.print("\n[dim]再见![/dim]")
90
+ break
91
+
92
+ if not user_input:
93
+ continue
94
+
95
+ cmd = user_input.lower()
96
+ if cmd in ("exit", "quit", "q"):
97
+ console.print("[dim]再见![/dim]")
98
+ break
99
+ elif cmd == "help":
100
+ _print_help()
101
+ continue
102
+ elif cmd == "clear":
103
+ console.clear()
104
+ continue
105
+ elif cmd == "history":
106
+ if history:
107
+ for i, msg in enumerate(history, 1):
108
+ console.print(f"[dim]{i}.[/dim] {msg[:80]}...")
109
+ else:
110
+ console.print("[dim]暂无历史记录[/dim]")
111
+ continue
112
+
113
+ history.append(user_input)
114
+
115
+ try:
116
+ loop = asyncio.new_event_loop()
117
+ loop.run_until_complete(_stream_chat(agent, user_input))
118
+ loop.close()
119
+ except KeyboardInterrupt:
120
+ console.print("\n[yellow]已中断[/yellow]")
121
+ except Exception as e:
122
+ console.print(f"[red]Error: {e}[/red]")
123
+
124
+
125
+ def chat_single(message: str, workspace: str = ".", config: dict = None) -> None:
126
+ """单次问答模式
127
+
128
+ Args:
129
+ message: 用户消息
130
+ workspace: 工作目录
131
+ config: Agent 配置
132
+ """
133
+ from QuantNodes.agent import Agent
134
+
135
+ try:
136
+ agent = Agent(workspace=workspace, config=config or {})
137
+ except Exception as e:
138
+ console.print(f"[red]Agent 初始化失败: {e}[/red]")
139
+ return
140
+
141
+ try:
142
+ loop = asyncio.new_event_loop()
143
+ loop.run_until_complete(_stream_chat(agent, message))
144
+ loop.close()
145
+ except Exception as e:
146
+ console.print(f"[red]Error: {e}[/red]")
@@ -0,0 +1,37 @@
1
+ # coding=utf-8
2
+ """
3
+ Configuration Node Module
4
+
5
+ 提供配置节点体系,用于从各种来源加载配置:
6
+ - IniConfigNode: INI 配置文件
7
+ - YamlConfigNode: YAML 配置文件
8
+ - JSONConfigNode: JSON 配置文件
9
+ - EnvConfigNode: 环境变量
10
+
11
+ Examples:
12
+ >>> # 从 INI 文件读取
13
+ >>> ini = IniConfigNode(file_path="config.ini", section="database")
14
+ >>> settings = ini.execute()
15
+ >>>
16
+ >>> # 从 YAML 文件读取
17
+ >>> yaml_config = YamlConfigNode(file_path="config.yaml", key="app")
18
+ >>> app_config = yaml_config.execute()
19
+ >>>
20
+ >>> # 从环境变量读取
21
+ >>> env = EnvConfigNode(prefix="MYAPP_", types={'PORT': int})
22
+ >>> env_config = env.execute()
23
+ """
24
+
25
+ from QuantNodes.conf_node.base import ConfigNode
26
+ from QuantNodes.conf_node.ini_config import IniConfigNode
27
+ from QuantNodes.conf_node.yaml_config import YamlConfigNode
28
+ from QuantNodes.conf_node.env_config import EnvConfigNode
29
+ from QuantNodes.conf_node.json_config import JSONConfigNode
30
+
31
+ __all__ = [
32
+ 'ConfigNode',
33
+ 'IniConfigNode',
34
+ 'YamlConfigNode',
35
+ 'EnvConfigNode',
36
+ 'JSONConfigNode',
37
+ ]