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,569 @@
1
+ # coding=utf-8
2
+ """``quantnodes factor-*`` commands.
3
+
4
+ Week 5~13 entry points for trajectory pool inspection / RAG evaluation /
5
+ visual reporting / iFinD data fetching / live monitoring dashboards.
6
+ """
7
+
8
+ from pathlib import Path
9
+
10
+ from QuantNodes.cli._helpers import cli_safe_run
11
+ from QuantNodes.cli.command import Command
12
+
13
+
14
+ @cli_safe_run
15
+ def cmd_factor_info(args) -> int:
16
+ """显示 TrajectoryPool 统计信息。
17
+
18
+ 用法:
19
+ quantnodes factor-info --pool-dir output/trajectory/
20
+ """
21
+ from QuantNodes.core.trajectory import TrajectoryPool
22
+
23
+ pool_dir = args.pool_dir
24
+ if not Path(pool_dir).exists():
25
+ print(f"错误: pool 目录不存在: {pool_dir}")
26
+ return 1
27
+
28
+ pool = TrajectoryPool(pool_dir)
29
+ print("=" * 60)
30
+ print(f"TrajectoryPool: {pool_dir}")
31
+ print(f" size: {pool.size}")
32
+ by_round: dict = {}
33
+ for e in pool.all():
34
+ by_round.setdefault(e.round_idx, 0)
35
+ by_round[e.round_idx] += 1
36
+ print(f" by_round: {by_round}")
37
+ by_op: dict = {}
38
+ for e in pool.all():
39
+ by_op.setdefault(e.operation, 0)
40
+ by_op[e.operation] += 1
41
+ print(f" by_operation: {by_op}")
42
+ n_passed = sum(1 for e in pool.all() if e.feedback and e.feedback.decision)
43
+ print(f" passed: {n_passed} / {pool.size}")
44
+ print("=" * 60)
45
+ return 0
46
+
47
+
48
+ @cli_safe_run
49
+ def cmd_factor_best(args) -> int:
50
+ """显示 Top-N 最佳 entry (按 metric 排序)。
51
+
52
+ 用法:
53
+ quantnodes factor-best --pool-dir output/trajectory/ --top 5 --metric sharpe
54
+ """
55
+ from QuantNodes.core.trajectory import TrajectoryPool
56
+
57
+ pool_dir = args.pool_dir
58
+ if not Path(pool_dir).exists():
59
+ print(f"错误: pool 目录不存在: {pool_dir}")
60
+ return 1
61
+
62
+ pool = TrajectoryPool(pool_dir)
63
+ top = pool.best(top_n=args.top, metric=args.metric)
64
+ print("=" * 60)
65
+ print(f"Top {len(top)} entries by {args.metric}:")
66
+ for i, e in enumerate(top, 1):
67
+ metric_val = e.metrics.get(args.metric, 0)
68
+ name = e.feedback.factor_name if e.feedback else e.entry_id[:8]
69
+ print(f" {i}. {name} [{e.operation} r{e.round_idx}] "
70
+ f"{args.metric}={metric_val:.4f}")
71
+ print("=" * 60)
72
+ return 0
73
+
74
+
75
+ @cli_safe_run
76
+ def cmd_factor_visual(args) -> int:
77
+ """生成可视化 HTML 报告 (谱系 DAG + 指标分布 + 拦截率 + 趋势)。
78
+
79
+ 用法:
80
+ quantnodes factor-visual --pool-dir output/trajectory/ \\
81
+ --output report.html --metric sharpe
82
+ """
83
+ from QuantNodes.core.trajectory import TrajectoryPool
84
+ from QuantNodes.core.visualization import generate_html
85
+
86
+ pool_dir = args.pool_dir
87
+ if not Path(pool_dir).exists():
88
+ print(f"错误: pool 目录不存在: {pool_dir}")
89
+ return 1
90
+
91
+ pool = TrajectoryPool(pool_dir)
92
+ if pool.size == 0:
93
+ print("错误: pool 为空, 无 entry 可视化")
94
+ return 1
95
+
96
+ output = args.output or str(Path(pool_dir).parent / f"{Path(pool_dir).name}_report.html")
97
+ title = args.title or f"QuantNodes 演化报告: {pool_dir}"
98
+ generate_html(pool, metric=args.metric, title=title, output_path=output)
99
+ print(f"✓ HTML 报告已生成: {output}")
100
+ print(f" size: {pool.size}, metric: {args.metric}")
101
+ return 0
102
+
103
+
104
+ @cli_safe_run
105
+ def cmd_factor_dashboard(args) -> int:
106
+ """生成 3 类指标 dashboard (Week 13)。
107
+
108
+ 从 TrajectoryPool 提取 RAG + Evolution + Quality Gate 指标,
109
+ 生成 Plotly 6 图 + 概览表 HTML 报告。
110
+
111
+ 用法:
112
+ quantnodes factor-dashboard --pool-dir output/trajectory/ \\
113
+ --output dashboard.html
114
+ """
115
+ from QuantNodes.core.monitoring import (
116
+ MetricCollector,
117
+ generate_dashboard_html,
118
+ )
119
+ from QuantNodes.core.trajectory import TrajectoryPool
120
+
121
+ pool_dir = args.pool_dir
122
+ if not Path(pool_dir).exists():
123
+ print(f"错误: pool 目录不存在: {pool_dir}")
124
+ return 1
125
+
126
+ pool = TrajectoryPool(pool_dir)
127
+ if pool.size == 0:
128
+ print("错误: pool 为空, 无指标可显示")
129
+ return 1
130
+
131
+ output = args.output or str(Path(pool_dir).parent / f"{Path(pool_dir).name}_dashboard.html")
132
+ title = args.title or f"QuantNodes 演化 Dashboard: {Path(pool_dir).name}"
133
+
134
+ # 收集 3 类指标
135
+ collector = MetricCollector()
136
+
137
+ # RAG: 从 TrajectoryEntry.feedback 元数据中提取 (兼容 rag_metrics_history 缺失)
138
+ rounds = sorted({e.round_idx for e in pool.all()})
139
+ for r in rounds:
140
+ round_entries = [e for e in pool.all() if e.round_idx == r]
141
+ n_total = len(round_entries)
142
+ n_passed = sum(1 for e in round_entries if e.feedback and e.feedback.decision)
143
+ # RAG 指标的简单代理: pass rate 作为 HR@5
144
+ if n_total > 0:
145
+ from QuantNodes.core.monitoring import RagMetrics
146
+ collector.add_rag(RagMetrics(
147
+ round=r, n_queries=n_total,
148
+ hit_at_5=n_passed / n_total, hit_at_10=n_passed / n_total,
149
+ ndcg_at_5=n_passed / n_total, ndcg_at_10=n_passed / n_total,
150
+ mrr=n_passed / n_total,
151
+ lineage_coverage=0.0,
152
+ diversity=1.0,
153
+ ))
154
+
155
+ # Evolution: 累积统计
156
+ from QuantNodes.core.monitoring import EvolutionMetrics
157
+ for r in rounds:
158
+ round_entries = [e for e in pool.all() if e.round_idx <= r]
159
+ n_passed = sum(1 for e in round_entries if e.feedback and e.feedback.decision)
160
+ n_total = len(round_entries)
161
+ n_rejected = n_total - n_passed
162
+ best_metric = 0.0
163
+ best_name = ""
164
+ for e in round_entries:
165
+ sharpe = (e.metrics or {}).get("sharpe", 0)
166
+ if sharpe > best_metric:
167
+ best_metric = sharpe
168
+ if e.feedback:
169
+ best_name = e.feedback.factor_name
170
+ collector.add_evolution(EvolutionMetrics(
171
+ round=r, pool_size=n_total,
172
+ total_count=n_passed, rejected_count=n_rejected,
173
+ best_metric=best_metric, best_factor_name=best_name,
174
+ ))
175
+
176
+ # Quality: 每 round 通道统计
177
+ for r in rounds:
178
+ collector.update_quality_from_pool(pool, round_idx=r)
179
+
180
+ print("=" * 60)
181
+ print(f"Dashboard 收集 ({len(collector)} metrics):")
182
+ print(f" RAG: {len(collector.rag_history)} rounds")
183
+ print(f" Evo: {len(collector.evolution_history)} rounds")
184
+ print(f" Quality: {len(collector.quality_history)} rounds")
185
+ print("=" * 60)
186
+
187
+ try:
188
+ streaming = getattr(args, "streaming", False) or getattr(args, "watch", False)
189
+ refresh_sec = getattr(args, "refresh", 10)
190
+ generate_dashboard_html(
191
+ collector, title=title, output_path=output,
192
+ streaming=streaming, refresh_interval_sec=refresh_sec,
193
+ )
194
+ except Exception as e:
195
+ # 嵌套: 这里包了 generate_dashboard_html 的内部异常。
196
+ # 整体 cmd_factor_dashboard 由 @cli_safe_run 包了顶层异常,
197
+ # 这里只针对 generate_dashboard_html 单独报错以便区分。
198
+ print(f"错误: 生成 dashboard 失败: {e}")
199
+ return 1
200
+
201
+ # 同时保存 JSON (供后续分析)
202
+ metrics_json = output.replace(".html", "_metrics.json")
203
+ collector.save(metrics_json)
204
+ print(f"✓ Dashboard: {output}")
205
+ print(f"✓ Metrics JSON: {metrics_json}")
206
+
207
+ # Watch 模式: 后台定时刷新
208
+ if getattr(args, "watch", False):
209
+ import time as _time
210
+ refresh_sec = getattr(args, "refresh", 10)
211
+ print(f"\n[Watch] 每 {refresh_sec}s 刷新 dashboard (Ctrl+C 退出)...")
212
+ try:
213
+ while True:
214
+ _time.sleep(refresh_sec)
215
+ # 重载 pool + 重新生成
216
+ try:
217
+ pool = TrajectoryPool(pool_dir)
218
+ collector = MetricCollector()
219
+ for r in rounds:
220
+ round_entries = [e for e in pool.all() if e.round_idx == r]
221
+ if not round_entries:
222
+ continue
223
+ collector.update_quality_from_pool(pool, round_idx=r)
224
+ generate_dashboard_html(
225
+ collector, title=title, output_path=output,
226
+ streaming=True, refresh_interval_sec=refresh_sec,
227
+ )
228
+ except Exception:
229
+ pass # pool 可能被其他进程写入, 忽略暂时错误
230
+ except KeyboardInterrupt:
231
+ print("\n[Watch] 停止监控")
232
+ return 0
233
+
234
+
235
+ @cli_safe_run
236
+ def cmd_factor_data_fetch(args) -> int:
237
+ """从 iFinD 拉取数据 + 写为 HDF5 格式 (Week 12)。
238
+
239
+ 用法:
240
+ quantnodes factor-data-fetch --output-dir /tmp/real_data/ \\
241
+ --universe all \\
242
+ --date-beg 20260101 --date-end 20260630 \\
243
+ --factors momentum_20d,reversal_5d
244
+ """
245
+ try:
246
+ from QuantNodes.research.factor_test.ifind_db import IFinDDatabase
247
+ except (ImportError, FileNotFoundError) as e:
248
+ print(f"错误: 无法导入 IFinDDatabase: {e}")
249
+ return 1
250
+
251
+ output_dir = Path(args.output_dir)
252
+ try:
253
+ db = IFinDDatabase(
254
+ date_beg=args.date_beg,
255
+ date_end=args.date_end,
256
+ universe=args.universe,
257
+ )
258
+ except FileNotFoundError as e:
259
+ print(f"错误: iFinD 配置缺失: {e}")
260
+ return 1
261
+ except ValueError as e:
262
+ print(f"错误: iFinD auth_token 无效: {e}")
263
+ return 1
264
+
265
+ factor_names = [f.strip() for f in (args.factors or "").split(",") if f.strip()]
266
+
267
+ print("=" * 60)
268
+ print("iFinD 数据拉取")
269
+ print(f" universe: {args.universe}")
270
+ print(f" date range: {args.date_beg} ~ {args.date_end}")
271
+ print(f" output_dir: {output_dir}")
272
+ print(f" factors: {factor_names or '(none)'}")
273
+ print("=" * 60)
274
+
275
+ stats = db.fetch_to_h5(output_dir, factor_names=factor_names)
276
+
277
+ print()
278
+ print("=" * 60)
279
+ print("✓ 完成, 统计:")
280
+ for fname, file_stats in stats.items():
281
+ if isinstance(file_stats, dict):
282
+ keys_info = ", ".join(
283
+ f"{k}={v}" for k, v in file_stats.items() if v
284
+ )
285
+ print(f" {fname}: {keys_info or '(empty)'}")
286
+ print("=" * 60)
287
+ return 0
288
+
289
+
290
+ @cli_safe_run
291
+ def cmd_factor_rag_eval(args) -> int:
292
+ """批量评估 RAG 检索质量 (Week 10)。
293
+
294
+ 用法:
295
+ quantnodes factor-rag-eval --pool-dir output/trajectory/ \\
296
+ --queries "momentum,reversal,volatility" \\
297
+ --top 5 \\
298
+ --output eval.json
299
+ """
300
+ from QuantNodes.core.knowledge import (
301
+ IdentityRetriever,
302
+ KnowledgeBase,
303
+ RAGEvaluator,
304
+ expand_lineage,
305
+ )
306
+ from QuantNodes.core.trajectory import TrajectoryPool
307
+
308
+ pool_dir = args.pool_dir
309
+ if not Path(pool_dir).exists():
310
+ print(f"错误: pool 目录不存在: {pool_dir}")
311
+ return 1
312
+
313
+ pool = TrajectoryPool(pool_dir)
314
+ if pool.size == 0:
315
+ print("错误: pool 为空, 无可评估内容")
316
+ return 1
317
+
318
+ queries = [q.strip() for q in (args.queries or "").split(",") if q.strip()]
319
+ if not queries:
320
+ print("错误: --queries 至少需要 1 个 query")
321
+ return 1
322
+
323
+ kb = KnowledgeBase(IdentityRetriever(), pool=pool)
324
+ n = kb.sync_from_pool()
325
+
326
+ # 构造评估输入
327
+ all_ids = {e.entry_id for e in pool.all()}
328
+ retrieved: list[list[str]] = []
329
+ relevant: list[list[str]] = []
330
+ relevance_scores: list[dict[str, float]] = []
331
+ lineage_ids: list[list[str]] = []
332
+ token_lists: list[list[list[str]]] = []
333
+
334
+ for q in queries:
335
+ results = kb.query(q, top_k=args.top)
336
+ ids = [e.entry_id for e, _ in results]
337
+ retrieved.append(ids)
338
+ relevant.append(list(all_ids))
339
+ relevance_scores.append({eid: 1.0 for eid in ids})
340
+ lin_set: set[str] = set()
341
+ tokens_per_entry: list[list[str]] = []
342
+ for e, _ in results:
343
+ expanded = expand_lineage(
344
+ pool, e.entry_id,
345
+ max_ancestor_depth=args.ancestor_depth,
346
+ max_descendant_depth=args.descendant_depth,
347
+ )
348
+ for _, ee in expanded["ancestors"] + expanded["descendants"]:
349
+ lin_set.add(ee.entry_id)
350
+ cfg = (e.config_snapshot or {}).get("factor", {}) if e else {}
351
+ toks = []
352
+ if cfg.get("name"):
353
+ toks += cfg["name"].lower().split("_")
354
+ if cfg.get("hypothesis"):
355
+ toks += cfg["hypothesis"].lower().split()
356
+ tokens_per_entry.append(toks)
357
+ lineage_ids.append(list(lin_set))
358
+ token_lists.append(tokens_per_entry)
359
+
360
+ ev = RAGEvaluator()
361
+ report = ev.evaluate(
362
+ queries=queries,
363
+ retrieved=retrieved,
364
+ relevant=relevant,
365
+ relevance_scores=relevance_scores,
366
+ lineage_ids=lineage_ids,
367
+ token_lists=token_lists,
368
+ )
369
+
370
+ if args.output:
371
+ ev.save(report, args.output)
372
+ print(f"✓ EvalReport 已保存: {args.output}")
373
+
374
+ print("=" * 60)
375
+ print(f"RAG 评估报告 ({report.n_queries} queries, indexed {n} entries)")
376
+ print(f" HitRate@5: {report.hit_at_5:.3f}")
377
+ print(f" HitRate@10: {report.hit_at_10:.3f}")
378
+ print(f" NDCG@5: {report.ndcg_at_5:.3f}")
379
+ print(f" NDCG@10: {report.ndcg_at_10:.3f}")
380
+ print(f" MRR: {report.mrr:.3f}")
381
+ print(f" LineageCov: {report.lineage_coverage:.3f}")
382
+ print(f" Diversity: {report.diversity:.3f}")
383
+ print("=" * 60)
384
+ return 0
385
+
386
+
387
+ @cli_safe_run
388
+ def cmd_factor_rag_show(args) -> int:
389
+ """从 TrajectoryPool 检索相似因子 (RAG demo)。
390
+
391
+ 用法:
392
+ quantnodes factor-rag-show --pool-dir output/trajectory/ \\
393
+ --query "momentum effect" --top 5
394
+ """
395
+ from QuantNodes.core.knowledge import (
396
+ Compressor,
397
+ IdentityRetriever,
398
+ KnowledgeBase,
399
+ expand_lineage,
400
+ )
401
+ from QuantNodes.core.trajectory import TrajectoryPool
402
+
403
+ pool_dir = args.pool_dir
404
+ if not Path(pool_dir).exists():
405
+ print(f"错误: pool 目录不存在: {pool_dir}")
406
+ return 1
407
+
408
+ pool = TrajectoryPool(pool_dir)
409
+ if pool.size == 0:
410
+ print("错误: pool 为空, 无可检索内容")
411
+ return 1
412
+
413
+ kb = KnowledgeBase(IdentityRetriever(), pool=pool)
414
+ n = kb.sync_from_pool()
415
+ print(f"索引了 {n} 个 entry")
416
+
417
+ results = kb.query(args.query, top_k=args.top)
418
+ if not results:
419
+ print(f"无匹配结果 (query: {args.query!r})")
420
+ return 0
421
+
422
+ use_compress = getattr(args, "compress", False)
423
+ compressor = Compressor(model="mock", max_tokens=args.max_tokens) if use_compress else None
424
+
425
+ print("=" * 60)
426
+ print(f"Top {len(results)} 检索结果 (query: {args.query!r}):")
427
+ for i, (entry, score) in enumerate(results, 1):
428
+ cfg = entry.config_snapshot or {}
429
+ factor_cfg = cfg.get("factor", {}) if isinstance(cfg, dict) else {}
430
+ name = factor_cfg.get("name", entry.entry_id[:8])
431
+ expr = factor_cfg.get("expression", "")[:50]
432
+ sharpe = (entry.metrics or {}).get("sharpe", 0)
433
+ print(f" {i}. {name} score={score:.3f} sharpe={sharpe:.2f}")
434
+ print(f" expression: {expr}")
435
+ if use_compress and compressor is not None:
436
+ expanded = expand_lineage(
437
+ pool, entry.entry_id,
438
+ max_ancestor_depth=args.ancestor_depth,
439
+ max_descendant_depth=args.descendant_depth,
440
+ )
441
+ c_anc = compressor.compress(expanded["ancestors"], relation="ancestors")
442
+ c_desc = compressor.compress(expanded["descendants"], relation="descendants")
443
+ print(f" ↑ ancestors ({c_anc.original_count}): {c_anc.summary[:80]}")
444
+ print(f" ↓ descendants ({c_desc.original_count}): {c_desc.summary[:80]}")
445
+ print("=" * 60)
446
+ return 0
447
+
448
+
449
+ class FactorInfoCommand(Command):
450
+ name = "factor-info"
451
+ description = "显示 TrajectoryPool 统计"
452
+
453
+ def add_arguments(self, subparsers) -> None:
454
+ from .._helpers import add_pool_dir_arg
455
+ p = subparsers.add_parser(self.name, help=self.description)
456
+ add_pool_dir_arg(p)
457
+
458
+ def run(self, args) -> int:
459
+ return cmd_factor_info(args)
460
+
461
+
462
+ class FactorBestCommand(Command):
463
+ name = "factor-best"
464
+ description = "显示 Top-N 最佳 entry"
465
+
466
+ def add_arguments(self, subparsers) -> None:
467
+ from .._helpers import add_pool_dir_arg, add_top_arg, add_metric_arg
468
+ p = subparsers.add_parser(self.name, help=self.description)
469
+ add_pool_dir_arg(p)
470
+ add_top_arg(p)
471
+ add_metric_arg(p)
472
+
473
+ def run(self, args) -> int:
474
+ return cmd_factor_best(args)
475
+
476
+
477
+ class FactorVisualCommand(Command):
478
+ name = "factor-visual"
479
+ description = "生成可视化 HTML 报告 (Week 6)"
480
+
481
+ def add_arguments(self, subparsers) -> None:
482
+ from .._helpers import (
483
+ add_pool_dir_arg, add_output_arg, add_metric_arg, add_title_arg,
484
+ )
485
+ p = subparsers.add_parser(self.name, help=self.description)
486
+ add_pool_dir_arg(p)
487
+ add_output_arg(p)
488
+ add_metric_arg(p)
489
+ add_title_arg(p)
490
+
491
+ def run(self, args) -> int:
492
+ return cmd_factor_visual(args)
493
+
494
+
495
+ class FactorDashboardCommand(Command):
496
+ name = "factor-dashboard"
497
+ description = "生成 3 类指标 dashboard (Week 13/16)"
498
+
499
+ def add_arguments(self, subparsers) -> None:
500
+ from .._helpers import add_pool_dir_arg, add_output_arg, add_title_arg
501
+ p = subparsers.add_parser(self.name, help=self.description)
502
+ add_pool_dir_arg(p)
503
+ add_output_arg(p)
504
+ add_title_arg(p)
505
+ p.add_argument(
506
+ "--streaming", action="store_true", help="启用 streaming 模式 (自动刷新 10s)"
507
+ )
508
+ p.add_argument("--refresh", type=int, default=10, help="streaming 刷新间隔秒数 (默认 10)")
509
+ p.add_argument("--watch", action="store_true", help="后台模式: 每 10s 刷新 dashboard")
510
+
511
+ def run(self, args) -> int:
512
+ return cmd_factor_dashboard(args)
513
+
514
+
515
+ class FactorDataFetchCommand(Command):
516
+ name = "factor-data-fetch"
517
+ description = "从 iFinD 拉取数据 + 写 H5 (Week 12)"
518
+
519
+ def add_arguments(self, subparsers) -> None:
520
+ from .._helpers import add_cli_overrides
521
+ p = subparsers.add_parser(self.name, help=self.description)
522
+ p.add_argument("--output-dir", required=True, help="HDF5 输出目录")
523
+ p.add_argument("--date-beg", required=True, help="起始日期 (YYYYMMDD)")
524
+ p.add_argument("--date-end", default="", help="截止日期 (空=今天)")
525
+ p.add_argument("--universe", default="all", help="股票池 (默认 all, 与 iFinD API 兼容)")
526
+ p.add_argument("--factors", default="", help="逗号分隔的因子列表")
527
+ add_cli_overrides(p)
528
+
529
+ def run(self, args) -> int:
530
+ return cmd_factor_data_fetch(args)
531
+
532
+
533
+ class FactorRagEvalCommand(Command):
534
+ name = "factor-rag-eval"
535
+ description = "批量评估 RAG 检索质量 (Week 10)"
536
+
537
+ def add_arguments(self, subparsers) -> None:
538
+ from .._helpers import (
539
+ add_pool_dir_arg, add_top_arg, add_lineage_depth_args, add_output_arg,
540
+ )
541
+ p = subparsers.add_parser(self.name, help=self.description)
542
+ add_pool_dir_arg(p)
543
+ p.add_argument("--queries", required=True, help="逗号分隔的 query 列表")
544
+ add_top_arg(p)
545
+ add_lineage_depth_args(p)
546
+ add_output_arg(p)
547
+
548
+ def run(self, args) -> int:
549
+ return cmd_factor_rag_eval(args)
550
+
551
+
552
+ class FactorRagShowCommand(Command):
553
+ name = "factor-rag-show"
554
+ description = "RAG 检索演示 (Week 7)"
555
+
556
+ def add_arguments(self, subparsers) -> None:
557
+ from .._helpers import (
558
+ add_pool_dir_arg, add_top_arg, add_lineage_depth_args,
559
+ )
560
+ p = subparsers.add_parser(self.name, help=self.description)
561
+ add_pool_dir_arg(p)
562
+ p.add_argument("--query", required=True, help="查询文本")
563
+ add_top_arg(p)
564
+ p.add_argument("--compress", action="store_true", help="启用谱系压缩 (Week 9)")
565
+ add_lineage_depth_args(p)
566
+ p.add_argument("--max-tokens", type=int, default=200, help="压缩最大字符数 (默认 200)")
567
+
568
+ def run(self, args) -> int:
569
+ return cmd_factor_rag_show(args)