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,98 @@
1
+ # coding=utf-8
2
+ """监控查询Agent工具"""
3
+
4
+ from __future__ import annotations
5
+
6
+ from typing import Any, Dict
7
+
8
+ from QuantNodes.agent.tools.base import Tool
9
+ from ..storage.repository import DatabaseManager
10
+ from ..monitor.dashboard import MonitorDashboard
11
+
12
+
13
+ class MonitorTool(Tool):
14
+ """策略监控查询工具"""
15
+
16
+ def __init__(self, db_path: str = "~/.quantnodes/monitor.db"):
17
+ self._db_path = db_path
18
+ self._dashboard = None
19
+
20
+ def _get_dashboard(self) -> MonitorDashboard:
21
+ if self._dashboard is None:
22
+ db = DatabaseManager(self._db_path)
23
+ db.connect()
24
+ from ..storage.repository import (
25
+ StrategyRunRepository, PerformanceRepository, DriftAlertRepository,
26
+ )
27
+ self._dashboard = MonitorDashboard(
28
+ StrategyRunRepository(db),
29
+ PerformanceRepository(db),
30
+ DriftAlertRepository(db),
31
+ )
32
+ return self._dashboard
33
+
34
+ @property
35
+ def name(self) -> str:
36
+ return "strategy_monitor"
37
+
38
+ @property
39
+ def description(self) -> str:
40
+ return "查询策略监控状态,包括绩效指标、漂移告警、历史记录等"
41
+
42
+ @property
43
+ def parameters(self) -> Dict[str, Any]:
44
+ return {
45
+ "type": "object",
46
+ "properties": {
47
+ "action": {
48
+ "type": "string",
49
+ "enum": ["status", "history", "alerts", "compare"],
50
+ "description": "操作类型",
51
+ },
52
+ "strategy_name": {
53
+ "type": "string",
54
+ "description": "策略名称",
55
+ },
56
+ "days": {
57
+ "type": "integer",
58
+ "description": "查询天数 (默认30)",
59
+ "default": 30,
60
+ },
61
+ "strategy_names": {
62
+ "type": "array",
63
+ "items": {"type": "string"},
64
+ "description": "对比的策略名称列表 (仅compare操作)",
65
+ },
66
+ },
67
+ "required": ["action"],
68
+ }
69
+
70
+ @property
71
+ def read_only(self) -> bool:
72
+ return True
73
+
74
+ async def execute(self, action: str, strategy_name: str = None,
75
+ days: int = 30, strategy_names: list = None, **kwargs) -> Any:
76
+ dashboard = self._get_dashboard()
77
+
78
+ if action == "status":
79
+ if not strategy_name:
80
+ return {"error": "strategy_name required for status"}
81
+ return dashboard.get_strategy_summary(strategy_name)
82
+
83
+ elif action == "history":
84
+ if not strategy_name:
85
+ return {"error": "strategy_name required for history"}
86
+ return dashboard.get_performance_history(strategy_name, days)
87
+
88
+ elif action == "alerts":
89
+ if not strategy_name:
90
+ return {"error": "strategy_name required for alerts"}
91
+ return dashboard.get_alert_history(strategy_name, days)
92
+
93
+ elif action == "compare":
94
+ if not strategy_names:
95
+ return {"error": "strategy_names required for compare"}
96
+ return dashboard.get_comparison(strategy_names)
97
+
98
+ return {"error": f"Unknown action: {action}"}
@@ -0,0 +1,98 @@
1
+ # coding=utf-8
2
+ """调度管理Agent工具"""
3
+
4
+ from __future__ import annotations
5
+
6
+ from typing import Any, Dict
7
+
8
+ from QuantNodes.agent.tools.base import Tool
9
+ from ..scheduler.scheduler import StrategyScheduler
10
+
11
+
12
+ class ScheduleTool(Tool):
13
+ """策略调度管理工具"""
14
+
15
+ def __init__(self, db_path: str = "~/.quantnodes/monitor.db"):
16
+ self._db_path = db_path
17
+ self._scheduler = None
18
+
19
+ def _get_scheduler(self) -> StrategyScheduler:
20
+ if self._scheduler is None:
21
+ self._scheduler = StrategyScheduler(self._db_path)
22
+ self._scheduler.start()
23
+ return self._scheduler
24
+
25
+ @property
26
+ def name(self) -> str:
27
+ return "strategy_schedule"
28
+
29
+ @property
30
+ def description(self) -> str:
31
+ return "管理策略调度任务,支持添加、移除、暂停、恢复定时执行"
32
+
33
+ @property
34
+ def parameters(self) -> Dict[str, Any]:
35
+ return {
36
+ "type": "object",
37
+ "properties": {
38
+ "action": {
39
+ "type": "string",
40
+ "enum": ["add", "remove", "list", "pause", "resume"],
41
+ "description": "操作类型",
42
+ },
43
+ "strategy_name": {
44
+ "type": "string",
45
+ "description": "策略名称",
46
+ },
47
+ "cron": {
48
+ "type": "string",
49
+ "description": "cron表达式 (如 '0 18 * * 1-5')",
50
+ },
51
+ "interval_minutes": {
52
+ "type": "integer",
53
+ "description": "间隔分钟数",
54
+ },
55
+ "config_path": {
56
+ "type": "string",
57
+ "description": "YAML配置文件路径",
58
+ },
59
+ },
60
+ "required": ["action", "strategy_name"],
61
+ }
62
+
63
+ @property
64
+ def read_only(self) -> bool:
65
+ return False
66
+
67
+ async def execute(self, action: str, strategy_name: str,
68
+ cron: str = None, interval_minutes: int = None,
69
+ config_path: str = None, **kwargs) -> Any:
70
+ scheduler = self._get_scheduler()
71
+
72
+ if action == "add":
73
+ if not config_path:
74
+ return {"error": "config_path required for add"}
75
+ if cron:
76
+ job_id = scheduler.add_cron_job(strategy_name, cron, config_path)
77
+ elif interval_minutes:
78
+ job_id = scheduler.add_interval_job(strategy_name, interval_minutes, config_path)
79
+ else:
80
+ return {"error": "cron or interval_minutes required"}
81
+ return {"status": "added", "job_id": job_id}
82
+
83
+ elif action == "remove":
84
+ success = scheduler.remove_job(strategy_name)
85
+ return {"status": "removed" if success else "not_found"}
86
+
87
+ elif action == "list":
88
+ return {"jobs": scheduler.get_jobs()}
89
+
90
+ elif action == "pause":
91
+ success = scheduler.pause_job(strategy_name)
92
+ return {"status": "paused" if success else "not_found"}
93
+
94
+ elif action == "resume":
95
+ success = scheduler.resume_job(strategy_name)
96
+ return {"status": "resumed" if success else "not_found"}
97
+
98
+ return {"error": f"Unknown action: {action}"}
@@ -0,0 +1,133 @@
1
+ # coding=utf-8
2
+ """版本管理Agent工具"""
3
+
4
+ from __future__ import annotations
5
+
6
+ from typing import Any, Dict
7
+
8
+ from QuantNodes.agent.tools.base import Tool
9
+ from ..storage.repository import DatabaseManager, VersionRepository
10
+ from ..version.version_manager import VersionManager
11
+
12
+
13
+ class VersionTool(Tool):
14
+ """策略版本管理工具"""
15
+
16
+ def __init__(self, db_path: str = "~/.quantnodes/monitor.db"):
17
+ self._db_path = db_path
18
+ self._version_manager = None
19
+
20
+ def _get_version_manager(self) -> VersionManager:
21
+ if self._version_manager is None:
22
+ db = DatabaseManager(self._db_path)
23
+ db.connect()
24
+ self._version_manager = VersionManager(VersionRepository(db))
25
+ return self._version_manager
26
+
27
+ @property
28
+ def name(self) -> str:
29
+ return "strategy_version"
30
+
31
+ @property
32
+ def description(self) -> str:
33
+ return "管理策略版本,支持保存、查看历史、对比差异、回滚"
34
+
35
+ @property
36
+ def parameters(self) -> Dict[str, Any]:
37
+ return {
38
+ "type": "object",
39
+ "properties": {
40
+ "action": {
41
+ "type": "string",
42
+ "enum": ["save", "list", "diff", "rollback", "current"],
43
+ "description": "操作类型",
44
+ },
45
+ "strategy_name": {
46
+ "type": "string",
47
+ "description": "策略名称",
48
+ },
49
+ "version": {
50
+ "type": "string",
51
+ "description": "版本号 (如 'v1', 'v2')",
52
+ },
53
+ "config_path": {
54
+ "type": "string",
55
+ "description": "YAML配置文件路径 (save操作)",
56
+ },
57
+ "description": {
58
+ "type": "string",
59
+ "description": "版本描述 (save操作)",
60
+ },
61
+ },
62
+ "required": ["action", "strategy_name"],
63
+ }
64
+
65
+ @property
66
+ def read_only(self) -> bool:
67
+ return False
68
+
69
+ async def execute(self, action: str, strategy_name: str,
70
+ version: str = None, config_path: str = None,
71
+ description: str = "", **kwargs) -> Any:
72
+ vm = self._get_version_manager()
73
+
74
+ if action == "save":
75
+ if not config_path:
76
+ return {"error": "config_path required for save"}
77
+ sv = vm.save_version(strategy_name, config_path, description)
78
+ return {
79
+ "status": "saved",
80
+ "version": sv.version,
81
+ "commit_hash": sv.commit_hash,
82
+ }
83
+
84
+ elif action == "list":
85
+ versions = vm.list_versions(strategy_name)
86
+ return {
87
+ "versions": [
88
+ {
89
+ "version": v.version,
90
+ "commit_hash": v.commit_hash,
91
+ "description": v.description,
92
+ "created_at": str(v.created_at) if v.created_at else None,
93
+ }
94
+ for v in versions
95
+ ]
96
+ }
97
+
98
+ elif action == "diff":
99
+ if not version:
100
+ return {"error": "version required for diff (compare with previous)"}
101
+ versions = vm.list_versions(strategy_name)
102
+ if len(versions) < 2:
103
+ return {"error": "need at least 2 versions to diff"}
104
+ # 找到目标版本的前一个版本
105
+ target_idx = next(
106
+ (i for i, v in enumerate(versions) if v.version == version), None
107
+ )
108
+ if target_idx is None:
109
+ return {"error": f"version {version} not found"}
110
+ if target_idx >= len(versions) - 1:
111
+ prev_version = versions[target_idx + 1].version
112
+ else:
113
+ prev_version = versions[0].version
114
+ diff_text = vm.diff_versions(strategy_name, version, prev_version)
115
+ return {"diff": diff_text}
116
+
117
+ elif action == "rollback":
118
+ if not version:
119
+ return {"error": "version required for rollback"}
120
+ sv = vm.rollback(strategy_name, version)
121
+ if sv:
122
+ return {
123
+ "status": "rolled_back",
124
+ "new_version": sv.version,
125
+ "commit_hash": sv.commit_hash,
126
+ }
127
+ return {"error": f"version {version} not found"}
128
+
129
+ elif action == "current":
130
+ ver = vm.get_current_version(strategy_name)
131
+ return {"current_version": ver}
132
+
133
+ return {"error": f"Unknown action: {action}"}
@@ -0,0 +1,6 @@
1
+ from .collector import MetricsCollector
2
+ from .drift import DriftDetector
3
+ from .alerter import Alerter
4
+ from .dashboard import MonitorDashboard
5
+
6
+ __all__ = ["MetricsCollector", "DriftDetector", "Alerter", "MonitorDashboard"]
@@ -0,0 +1,60 @@
1
+ # coding=utf-8
2
+ """告警生成器"""
3
+
4
+ from __future__ import annotations
5
+
6
+ from typing import List
7
+
8
+ from ..storage.models import DriftAlert
9
+ from ..storage.repository import DriftAlertRepository
10
+
11
+
12
+ class Alerter:
13
+ """告警生成器 - 创建、查询、确认告警"""
14
+
15
+ def __init__(self, alert_repo: DriftAlertRepository):
16
+ self.repo = alert_repo
17
+
18
+ def create_alert(self, alert: DriftAlert) -> int:
19
+ """创建告警记录"""
20
+ return self.repo.create_alert(alert)
21
+
22
+ def get_pending_alerts(self, strategy_name: str = None) -> List[DriftAlert]:
23
+ """获取未确认的告警"""
24
+ return self.repo.get_pending(strategy_name)
25
+
26
+ def acknowledge_alert(self, alert_id: int) -> None:
27
+ """确认告警"""
28
+ self.repo.acknowledge(alert_id)
29
+
30
+ def get_alert_history(
31
+ self, strategy_name: str, days: int = 30
32
+ ) -> List[DriftAlert]:
33
+ """获取告警历史"""
34
+ return self.repo.get_history(strategy_name, days)
35
+
36
+ def format_alert_message(self, alert: DriftAlert) -> str:
37
+ """格式化告警消息"""
38
+ severity_icon = "🔴" if alert.severity == "critical" else "🟡"
39
+ return (
40
+ f"{severity_icon} [{alert.severity.upper()}] {alert.strategy_name}\n"
41
+ f" 类型: {alert.alert_type}\n"
42
+ f" 指标: {alert.metric_name}\n"
43
+ f" 当前值: {alert.current_value}\n"
44
+ f" 基线值: {alert.baseline_value}\n"
45
+ f" 消息: {alert.message}"
46
+ )
47
+
48
+ def get_pending_summary(self, strategy_name: str = None) -> dict:
49
+ """获取未确认告警摘要"""
50
+ pending = self.get_pending_alerts(strategy_name)
51
+ return {
52
+ "total": len(pending),
53
+ "critical": sum(1 for a in pending if a.severity == "critical"),
54
+ "warning": sum(1 for a in pending if a.severity == "warning"),
55
+ "by_type": {
56
+ "ks_test": sum(1 for a in pending if a.alert_type == "ks_test"),
57
+ "sharpe_drop": sum(1 for a in pending if a.alert_type == "sharpe_drop"),
58
+ "drawdown_breach": sum(1 for a in pending if a.alert_type == "drawdown_breach"),
59
+ },
60
+ }
@@ -0,0 +1,164 @@
1
+ # coding=utf-8
2
+ """绩效指标采集器"""
3
+
4
+ from __future__ import annotations
5
+
6
+ import json
7
+ from datetime import date
8
+ from typing import Optional, Dict, Any, List
9
+
10
+ import polars as pl
11
+
12
+ from ..storage.models import PerformanceSnapshot
13
+ from ..storage.repository import PerformanceRepository
14
+
15
+
16
+ class MetricsCollector:
17
+ """绩效指标采集器 - 从回测结果或实盘数据采集绩效指标"""
18
+
19
+ def __init__(self, performance_repo: PerformanceRepository):
20
+ self.repo = performance_repo
21
+
22
+ def collect_from_backtest(
23
+ self,
24
+ strategy_name: str,
25
+ statistics: Dict[str, Any],
26
+ daily_returns: Optional[List[float]] = None,
27
+ ) -> PerformanceSnapshot:
28
+ """从回测统计结果采集绩效指标
29
+
30
+ Args:
31
+ strategy_name: 策略名称
32
+ statistics: ConfigBacktestRunner._compute_statistics() 的输出
33
+ daily_returns: 日收益率序列 (可选)
34
+
35
+ Returns:
36
+ PerformanceSnapshot 对象
37
+ """
38
+ returns_json = json.dumps(daily_returns) if daily_returns else None
39
+
40
+ snapshot = PerformanceSnapshot(
41
+ strategy_name=strategy_name,
42
+ snapshot_date=date.today(),
43
+ sharpe_ratio=statistics.get("sharpe_ratio"),
44
+ sortino_ratio=statistics.get("sortino_ratio"),
45
+ max_drawdown=statistics.get("max_drawdown"),
46
+ annualized_return=statistics.get("annualized_return"),
47
+ annualized_volatility=statistics.get("annualized_volatility"),
48
+ win_rate=statistics.get("win_rate"),
49
+ profit_factor=statistics.get("profit_factor"),
50
+ total_trades=statistics.get("total_trades"),
51
+ daily_returns=returns_json,
52
+ )
53
+
54
+ self.repo.save_snapshot(snapshot)
55
+ return snapshot
56
+
57
+ def collect_from_lazyframe(
58
+ self,
59
+ strategy_name: str,
60
+ equity_curve: pl.LazyFrame,
61
+ ) -> PerformanceSnapshot:
62
+ """从权益曲线LazyFrame采集绩效指标
63
+
64
+ Args:
65
+ strategy_name: 策略名称
66
+ equity_curve: 包含 date, equity 列的 LazyFrame
67
+
68
+ Returns:
69
+ PerformanceSnapshot 对象
70
+ """
71
+ df = equity_curve.collect()
72
+
73
+ if "equity" not in df.columns or len(df) < 2:
74
+ snapshot = PerformanceSnapshot(
75
+ strategy_name=strategy_name,
76
+ snapshot_date=date.today(),
77
+ )
78
+ self.repo.save_snapshot(snapshot)
79
+ return snapshot
80
+
81
+ equity = df["equity"].to_list()
82
+ daily_returns = self._compute_daily_returns(equity)
83
+ stats = self._compute_statistics(daily_returns)
84
+
85
+ snapshot = PerformanceSnapshot(
86
+ strategy_name=strategy_name,
87
+ snapshot_date=date.today(),
88
+ sharpe_ratio=stats.get("sharpe_ratio"),
89
+ sortino_ratio=stats.get("sortino_ratio"),
90
+ max_drawdown=stats.get("max_drawdown"),
91
+ annualized_return=stats.get("annualized_return"),
92
+ annualized_volatility=stats.get("annualized_volatility"),
93
+ daily_returns=json.dumps(daily_returns),
94
+ )
95
+
96
+ self.repo.save_snapshot(snapshot)
97
+ return snapshot
98
+
99
+ def get_baseline_metrics(
100
+ self, strategy_name: str, baseline_days: int = 252
101
+ ) -> Optional[PerformanceSnapshot]:
102
+ """获取基线指标 (用于漂移检测对比)"""
103
+ return self.repo.get_baseline(strategy_name, baseline_days)
104
+
105
+ @staticmethod
106
+ def _compute_daily_returns(equity: List[float]) -> List[float]:
107
+ """计算日收益率"""
108
+ returns = []
109
+ for i in range(1, len(equity)):
110
+ if equity[i - 1] != 0:
111
+ returns.append(equity[i] / equity[i - 1] - 1)
112
+ else:
113
+ returns.append(0.0)
114
+ return returns
115
+
116
+ @staticmethod
117
+ def _compute_statistics(daily_returns: List[float]) -> Dict[str, Any]:
118
+ """从日收益率计算统计指标"""
119
+ import math
120
+
121
+ if not daily_returns:
122
+ return {}
123
+
124
+ n = len(daily_returns)
125
+ mean_r = sum(daily_returns) / n
126
+ var_r = sum((r - mean_r) ** 2 for r in daily_returns) / max(n - 1, 1)
127
+ std_r = math.sqrt(var_r)
128
+
129
+ # 夏普比率 (rf=3%)
130
+ rf_daily = 0.03 / 252
131
+ sharpe = (mean_r - rf_daily) / std_r * math.sqrt(252) if std_r > 0 else 0.0
132
+
133
+ # 索提诺比率
134
+ downside = [r for r in daily_returns if r < rf_daily]
135
+ downside_var = sum((r - rf_daily) ** 2 for r in downside) / max(len(downside), 1)
136
+ downside_std = math.sqrt(downside_var)
137
+ sortino = (mean_r - rf_daily) / downside_std * math.sqrt(252) if downside_std > 0 else 0.0
138
+
139
+ # 最大回撤
140
+ max_dd = 0.0
141
+ cum = 1.0
142
+ peak = 1.0
143
+ for r in daily_returns:
144
+ cum *= (1 + r)
145
+ if cum > peak:
146
+ peak = cum
147
+ dd = (cum - peak) / peak
148
+ if dd < max_dd:
149
+ max_dd = dd
150
+
151
+ # 年化收益
152
+ total_return = 1.0
153
+ for r in daily_returns:
154
+ total_return *= (1 + r)
155
+ n_years = n / 252
156
+ ann_return = total_return ** (1 / max(n_years, 0.01)) - 1 if total_return > 0 else -1.0
157
+
158
+ return {
159
+ "sharpe_ratio": round(sharpe, 4),
160
+ "sortino_ratio": round(sortino, 4),
161
+ "max_drawdown": round(max_dd, 4),
162
+ "annualized_return": round(ann_return, 4),
163
+ "annualized_volatility": round(std_r * math.sqrt(252), 4),
164
+ }
@@ -0,0 +1,115 @@
1
+ # coding=utf-8
2
+ """监控数据查询接口"""
3
+
4
+ from __future__ import annotations
5
+
6
+ from typing import List, Dict, Any
7
+
8
+ from ..storage.repository import (
9
+ StrategyRunRepository,
10
+ PerformanceRepository,
11
+ DriftAlertRepository,
12
+ )
13
+
14
+
15
+ class MonitorDashboard:
16
+ """监控数据查询接口"""
17
+
18
+ def __init__(
19
+ self,
20
+ run_repo: StrategyRunRepository,
21
+ perf_repo: PerformanceRepository,
22
+ alert_repo: DriftAlertRepository,
23
+ ):
24
+ self.run_repo = run_repo
25
+ self.perf_repo = perf_repo
26
+ self.alert_repo = alert_repo
27
+
28
+ def get_strategy_summary(self, strategy_name: str) -> Dict[str, Any]:
29
+ """获取策略概览"""
30
+ latest_run = None
31
+ runs = self.run_repo.get_by_strategy(strategy_name, limit=1)
32
+ if runs:
33
+ latest_run = {
34
+ "status": runs[0].status,
35
+ "start_time": str(runs[0].start_time) if runs[0].start_time else None,
36
+ "end_time": str(runs[0].end_time) if runs[0].end_time else None,
37
+ }
38
+
39
+ perf = self.perf_repo.get_latest(strategy_name)
40
+ perf_dict = None
41
+ if perf:
42
+ perf_dict = {
43
+ "sharpe_ratio": perf.sharpe_ratio,
44
+ "sortino_ratio": perf.sortino_ratio,
45
+ "max_drawdown": perf.max_drawdown,
46
+ "annualized_return": perf.annualized_return,
47
+ "win_rate": perf.win_rate,
48
+ "snapshot_date": str(perf.snapshot_date) if perf.snapshot_date else None,
49
+ }
50
+
51
+ pending_alerts = self.alert_repo.get_pending(strategy_name)
52
+
53
+ return {
54
+ "strategy_name": strategy_name,
55
+ "latest_run": latest_run,
56
+ "performance": perf_dict,
57
+ "pending_alerts": len(pending_alerts),
58
+ }
59
+
60
+ def get_performance_history(
61
+ self, strategy_name: str, days: int = 30
62
+ ) -> List[Dict[str, Any]]:
63
+ """获取绩效历史"""
64
+ snapshots = self.perf_repo.get_history(strategy_name, days)
65
+ return [
66
+ {
67
+ "date": str(s.snapshot_date),
68
+ "sharpe_ratio": s.sharpe_ratio,
69
+ "max_drawdown": s.max_drawdown,
70
+ "annualized_return": s.annualized_return,
71
+ "win_rate": s.win_rate,
72
+ }
73
+ for s in snapshots
74
+ ]
75
+
76
+ def get_alert_history(
77
+ self, strategy_name: str, days: int = 30
78
+ ) -> List[Dict[str, Any]]:
79
+ """获取告警历史"""
80
+ alerts = self.alert_repo.get_history(strategy_name, days)
81
+ return [
82
+ {
83
+ "id": a.id,
84
+ "type": a.alert_type,
85
+ "severity": a.severity,
86
+ "metric": a.metric_name,
87
+ "message": a.message,
88
+ "acknowledged": a.acknowledged,
89
+ "created_at": str(a.created_at) if a.created_at else None,
90
+ }
91
+ for a in alerts
92
+ ]
93
+
94
+ def get_comparison(self, strategy_names: List[str]) -> Dict[str, Any]:
95
+ """多策略对比"""
96
+ result = {}
97
+ for name in strategy_names:
98
+ perf = self.perf_repo.get_latest(name)
99
+ if perf:
100
+ result[name] = {
101
+ "sharpe_ratio": perf.sharpe_ratio,
102
+ "max_drawdown": perf.max_drawdown,
103
+ "annualized_return": perf.annualized_return,
104
+ "win_rate": perf.win_rate,
105
+ }
106
+ else:
107
+ result[name] = None
108
+ return result
109
+
110
+ def get_all_strategies(self) -> List[str]:
111
+ """获取所有策略名称"""
112
+ rows = self.run_repo.db.conn.execute(
113
+ "SELECT DISTINCT strategy_name FROM strategy_runs"
114
+ ).fetchall()
115
+ return [r["strategy_name"] for r in rows]