aria-code 0.52.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 (478) hide show
  1. aria_code/__init__.py +42 -0
  2. aria_code/_version.py +20 -0
  3. aria_code/adk_apps/__init__.py +1 -0
  4. aria_code/adk_apps/aria_code_review/__init__.py +1 -0
  5. aria_code/adk_apps/aria_code_review/agent.py +32 -0
  6. aria_code/adk_apps/aria_research/__init__.py +1 -0
  7. aria_code/adk_apps/aria_research/agent.py +31 -0
  8. aria_code/agents/__init__.py +34 -0
  9. aria_code/agents/base.py +318 -0
  10. aria_code/agents/code_review.py +200 -0
  11. aria_code/agents/deep/__init__.py +37 -0
  12. aria_code/agents/deep/calibration_loop.py +144 -0
  13. aria_code/agents/deep/critic.py +125 -0
  14. aria_code/agents/deep/deepen.py +193 -0
  15. aria_code/agents/deep/models.py +149 -0
  16. aria_code/agents/deep/pipeline.py +164 -0
  17. aria_code/agents/deep/quant_fusion.py +192 -0
  18. aria_code/agents/deep/themes.py +95 -0
  19. aria_code/agents/deep/tiers.py +106 -0
  20. aria_code/agents/engineering/__init__.py +14 -0
  21. aria_code/agents/engineering/coder.py +222 -0
  22. aria_code/agents/engineering/tester.py +145 -0
  23. aria_code/agents/financial/__init__.py +21 -0
  24. aria_code/agents/financial/cashflow_burn.py +119 -0
  25. aria_code/agents/financial/catalyst.py +279 -0
  26. aria_code/agents/financial/corporate_finance.py +175 -0
  27. aria_code/agents/financial/debate.py +224 -0
  28. aria_code/agents/financial/earnings.py +303 -0
  29. aria_code/agents/financial/fundamental.py +191 -0
  30. aria_code/agents/financial/macro.py +99 -0
  31. aria_code/agents/financial/news.py +207 -0
  32. aria_code/agents/financial/risk.py +165 -0
  33. aria_code/agents/financial/sector.py +279 -0
  34. aria_code/agents/financial/strategist.py +121 -0
  35. aria_code/agents/financial/stripe_revenue.py +127 -0
  36. aria_code/agents/financial/synthesis.py +274 -0
  37. aria_code/agents/financial/technical.py +258 -0
  38. aria_code/agents/orchestrator.py +44 -0
  39. aria_code/agents/portfolio_agent.py +363 -0
  40. aria_code/agents/realty/__init__.py +62 -0
  41. aria_code/agents/realty/asset_diagnosis.py +152 -0
  42. aria_code/agents/realty/business_match.py +166 -0
  43. aria_code/agents/realty/cashflow_verify.py +209 -0
  44. aria_code/agents/realty/contract_rules.py +210 -0
  45. aria_code/agents/realty/energy_anomaly.py +189 -0
  46. aria_code/agents/realty/exit_settlement.py +208 -0
  47. aria_code/agents/realty/fulfillment_risk.py +206 -0
  48. aria_code/agents/realty/ops_optimize.py +160 -0
  49. aria_code/agents/realty/revenue_share.py +215 -0
  50. aria_code/agents/registry.py +158 -0
  51. aria_code/agents/signal_scheme.py +111 -0
  52. aria_code/agents/sports/__init__.py +0 -0
  53. aria_code/agents/sports/football_agent.py +197 -0
  54. aria_code/agents/supervisor.py +113 -0
  55. aria_code/agents/team.py +492 -0
  56. aria_code/agents/warehouse/__init__.py +25 -0
  57. aria_code/agents/warehouse/contracts.py +26 -0
  58. aria_code/agents/warehouse/dashboard.py +155 -0
  59. aria_code/agents/warehouse/fulfillment_leadtime.py +95 -0
  60. aria_code/agents/warehouse/inbound_exceptions.py +25 -0
  61. aria_code/agents/warehouse/inventory_health.py +24 -0
  62. aria_code/agents/warehouse/local_run.py +71 -0
  63. aria_code/agents/warehouse/local_snapshot.py +132 -0
  64. aria_code/agents/warehouse/logistics_cost.py +84 -0
  65. aria_code/agents/warehouse/logistics_sync.py +21 -0
  66. aria_code/agents/warehouse/workflow.py +31 -0
  67. aria_code/aliyun_data_client.py +4 -0
  68. aria_code/apps/README.md +12 -0
  69. aria_code/apps/__init__.py +2 -0
  70. aria_code/apps/channels/README.md +15 -0
  71. aria_code/apps/channels/__init__.py +17 -0
  72. aria_code/apps/channels/intake.py +92 -0
  73. aria_code/apps/channels/registry.py +95 -0
  74. aria_code/apps/channels/tradingview.py +94 -0
  75. aria_code/apps/cli/README.md +13 -0
  76. aria_code/apps/cli/__init__.py +2 -0
  77. aria_code/apps/cli/_optional.py +120 -0
  78. aria_code/apps/cli/bootstrap.py +145 -0
  79. aria_code/apps/cli/broker_render.py +206 -0
  80. aria_code/apps/cli/codegen_paths.py +29 -0
  81. aria_code/apps/cli/commands/__init__.py +16 -0
  82. aria_code/apps/cli/commands/_business_render.py +78 -0
  83. aria_code/apps/cli/commands/_ui.py +71 -0
  84. aria_code/apps/cli/commands/analysis_cmds.py +369 -0
  85. aria_code/apps/cli/commands/ashare_prediction_cmds.py +327 -0
  86. aria_code/apps/cli/commands/auth_cmds.py +239 -0
  87. aria_code/apps/cli/commands/backtest_cmds.py +2543 -0
  88. aria_code/apps/cli/commands/broker_cmds.py +1234 -0
  89. aria_code/apps/cli/commands/business_workflow_cmds.py +319 -0
  90. aria_code/apps/cli/commands/canvas_cmds.py +77 -0
  91. aria_code/apps/cli/commands/catalog.py +87 -0
  92. aria_code/apps/cli/commands/core_cmds.py +2520 -0
  93. aria_code/apps/cli/commands/data_cmds.py +457 -0
  94. aria_code/apps/cli/commands/diagnostic_cmds.py +230 -0
  95. aria_code/apps/cli/commands/diagnostic_ops_cmds.py +813 -0
  96. aria_code/apps/cli/commands/file_cmds.py +312 -0
  97. aria_code/apps/cli/commands/finance_service_cmds.py +60 -0
  98. aria_code/apps/cli/commands/fx_commodity_cmds.py +123 -0
  99. aria_code/apps/cli/commands/market.py +434 -0
  100. aria_code/apps/cli/commands/market_cmds.py +1381 -0
  101. aria_code/apps/cli/commands/market_context.py +425 -0
  102. aria_code/apps/cli/commands/market_render.py +7 -0
  103. aria_code/apps/cli/commands/model_cmds.py +2153 -0
  104. aria_code/apps/cli/commands/ops_cmds.py +721 -0
  105. aria_code/apps/cli/commands/orchestrator_cmds.py +179 -0
  106. aria_code/apps/cli/commands/pdf_export_cmds.py +125 -0
  107. aria_code/apps/cli/commands/portfolio_cmds.py +1278 -0
  108. aria_code/apps/cli/commands/report.py +437 -0
  109. aria_code/apps/cli/commands/scaffold_templates.py +617 -0
  110. aria_code/apps/cli/commands/session_cmds.py +236 -0
  111. aria_code/apps/cli/commands/session_ux_cmds.py +359 -0
  112. aria_code/apps/cli/commands/team.py +669 -0
  113. aria_code/apps/cli/commands/team_render.py +8 -0
  114. aria_code/apps/cli/commands/ui_cmds.py +401 -0
  115. aria_code/apps/cli/commands/warehouse_cmds.py +79 -0
  116. aria_code/apps/cli/commands/workflow_cmds.py +480 -0
  117. aria_code/apps/cli/commands/workspace_cmds.py +1494 -0
  118. aria_code/apps/cli/config_paths.py +73 -0
  119. aria_code/apps/cli/config_store.py +78 -0
  120. aria_code/apps/cli/constants.py +88 -0
  121. aria_code/apps/cli/context.py +34 -0
  122. aria_code/apps/cli/deterministic.py +191 -0
  123. aria_code/apps/cli/direct.py +48 -0
  124. aria_code/apps/cli/finance_service_catalog.py +111 -0
  125. aria_code/apps/cli/football_reports.py +231 -0
  126. aria_code/apps/cli/github_app_auth.py +135 -0
  127. aria_code/apps/cli/google_login.py +196 -0
  128. aria_code/apps/cli/handlers/__init__.py +11 -0
  129. aria_code/apps/cli/handlers/broker_handlers.py +122 -0
  130. aria_code/apps/cli/handlers/chart_handlers.py +1309 -0
  131. aria_code/apps/cli/handlers/market_handlers.py +2513 -0
  132. aria_code/apps/cli/handlers/realty_handlers.py +114 -0
  133. aria_code/apps/cli/handlers/sports_handlers.py +22 -0
  134. aria_code/apps/cli/handlers/strategy_advice.py +82 -0
  135. aria_code/apps/cli/helpers.py +302 -0
  136. aria_code/apps/cli/hooks.py +180 -0
  137. aria_code/apps/cli/i18n.py +297 -0
  138. aria_code/apps/cli/intent.py +136 -0
  139. aria_code/apps/cli/intent_router.py +276 -0
  140. aria_code/apps/cli/intent_signals.py +344 -0
  141. aria_code/apps/cli/lifecycle_hooks.py +48 -0
  142. aria_code/apps/cli/local_tool_schemas.py +536 -0
  143. aria_code/apps/cli/main.py +29 -0
  144. aria_code/apps/cli/market_metadata.py +135 -0
  145. aria_code/apps/cli/market_universe.py +487 -0
  146. aria_code/apps/cli/message_processing.py +310 -0
  147. aria_code/apps/cli/model_catalog.py +620 -0
  148. aria_code/apps/cli/pdf_report.py +977 -0
  149. aria_code/apps/cli/plan_mode.py +139 -0
  150. aria_code/apps/cli/plotly_html.py +15 -0
  151. aria_code/apps/cli/prediction_feedback.py +202 -0
  152. aria_code/apps/cli/preflight.py +502 -0
  153. aria_code/apps/cli/project_aria.py +60 -0
  154. aria_code/apps/cli/prompt_assembly.py +59 -0
  155. aria_code/apps/cli/prompts/__init__.py +0 -0
  156. aria_code/apps/cli/prompts/coding.py +53 -0
  157. aria_code/apps/cli/prompts/select.py +142 -0
  158. aria_code/apps/cli/prompts/system_prompts.py +552 -0
  159. aria_code/apps/cli/prompts/ui.py +436 -0
  160. aria_code/apps/cli/provider_endpoints.py +237 -0
  161. aria_code/apps/cli/provider_keys.py +73 -0
  162. aria_code/apps/cli/providers/__init__.py +1 -0
  163. aria_code/apps/cli/providers/base.py +521 -0
  164. aria_code/apps/cli/providers/chat_routing.py +128 -0
  165. aria_code/apps/cli/providers/collaboration.py +98 -0
  166. aria_code/apps/cli/providers/llm/__init__.py +1 -0
  167. aria_code/apps/cli/providers/llm/offline_responses.py +68 -0
  168. aria_code/apps/cli/providers/llm/ollama_stream.py +1594 -0
  169. aria_code/apps/cli/providers/llm/response_cache.py +60 -0
  170. aria_code/apps/cli/providers/llm/sse_stream.py +257 -0
  171. aria_code/apps/cli/providers/runtime_bridge.py +353 -0
  172. aria_code/apps/cli/providers/vertexai_stream.py +316 -0
  173. aria_code/apps/cli/runtime_consumer.py +657 -0
  174. aria_code/apps/cli/sandbox.py +32 -0
  175. aria_code/apps/cli/session_export.py +120 -0
  176. aria_code/apps/cli/session_jsonl.py +208 -0
  177. aria_code/apps/cli/session_store.py +112 -0
  178. aria_code/apps/cli/skills_catalog.py +273 -0
  179. aria_code/apps/cli/todo_tracker.py +190 -0
  180. aria_code/apps/cli/tool_executor.py +823 -0
  181. aria_code/apps/cli/tool_registry.py +34 -0
  182. aria_code/apps/cli/tool_scope.py +106 -0
  183. aria_code/apps/cli/tools/__init__.py +40 -0
  184. aria_code/apps/cli/tools/context.py +46 -0
  185. aria_code/apps/cli/tools/file_tools.py +180 -0
  186. aria_code/apps/cli/tools/market_tools.py +620 -0
  187. aria_code/apps/cli/tools/notebook_tools.py +111 -0
  188. aria_code/apps/cli/tools/system_tools.py +726 -0
  189. aria_code/apps/cli/tools/write_tools.py +845 -0
  190. aria_code/apps/cli/tradingview_bridge.py +529 -0
  191. aria_code/apps/cli/turn_planning.py +137 -0
  192. aria_code/apps/cli/update_check.py +153 -0
  193. aria_code/apps/cli/utils/__init__.py +0 -0
  194. aria_code/apps/cli/utils/market_detect.py +1597 -0
  195. aria_code/apps/daemon/README.md +14 -0
  196. aria_code/apps/vscode/README.md +115 -0
  197. aria_code/apps/vscode/package.json +70 -0
  198. aria_code/aria_cli.py +6743 -0
  199. aria_code/aria_daemon.py +1398 -0
  200. aria_code/aria_feishu_bot.py +1423 -0
  201. aria_code/aria_mcp_server.py +7 -0
  202. aria_code/aria_relay_client.py +4 -0
  203. aria_code/aria_relay_server.py +490 -0
  204. aria_code/aria_telegram_bot.py +202 -0
  205. aria_code/ariarc.py +385 -0
  206. aria_code/artifacts.py +581 -0
  207. aria_code/backtest_engine.py +4 -0
  208. aria_code/backtest_report.py +4 -0
  209. aria_code/brokers/__init__.py +78 -0
  210. aria_code/brokers/automation.py +193 -0
  211. aria_code/brokers/base.py +231 -0
  212. aria_code/brokers/capabilities.py +264 -0
  213. aria_code/brokers/cn/__init__.py +10 -0
  214. aria_code/brokers/cn/easytrader_broker.py +193 -0
  215. aria_code/brokers/cn/futu_broker.py +194 -0
  216. aria_code/brokers/cn/longbridge_broker.py +190 -0
  217. aria_code/brokers/cn/tiger_broker.py +196 -0
  218. aria_code/brokers/cn/xtquant_broker.py +225 -0
  219. aria_code/brokers/config.py +414 -0
  220. aria_code/brokers/intl/__init__.py +5 -0
  221. aria_code/brokers/intl/alpaca_broker.py +183 -0
  222. aria_code/brokers/intl/ibkr_broker.py +215 -0
  223. aria_code/brokers/intl/trading212_broker.py +183 -0
  224. aria_code/brokers/intl/webull_broker.py +156 -0
  225. aria_code/brokers/paper_broker.py +266 -0
  226. aria_code/brokers/planning.py +296 -0
  227. aria_code/brokers/registry.py +213 -0
  228. aria_code/brokers/trading.py +267 -0
  229. aria_code/canva_client.py +4 -0
  230. aria_code/change_store.py +127 -0
  231. aria_code/clients/__init__.py +0 -0
  232. aria_code/clients/aliyun_data_client.py +660 -0
  233. aria_code/clients/aria_relay_client.py +182 -0
  234. aria_code/clients/canva_client.py +284 -0
  235. aria_code/clients/figma_client.py +100 -0
  236. aria_code/clients/football_data_client.py +1671 -0
  237. aria_code/clients/kling_video_client.py +182 -0
  238. aria_code/clients/market_data_client.py +1976 -0
  239. aria_code/clients/openai_image_client.py +242 -0
  240. aria_code/clients/runway_video_client.py +157 -0
  241. aria_code/clients/warehouse_erp_client.py +105 -0
  242. aria_code/cloud_memory.py +181 -0
  243. aria_code/command_safety.py +19 -0
  244. aria_code/computer_use_tools.py +4 -0
  245. aria_code/dashboard_generator.py +579 -0
  246. aria_code/data_analysis_tools.py +4 -0
  247. aria_code/data_cleaner.py +483 -0
  248. aria_code/data_service.py +513 -0
  249. aria_code/datasources/__init__.py +23 -0
  250. aria_code/datasources/base.py +166 -0
  251. aria_code/datasources/router.py +253 -0
  252. aria_code/datasources/sources/__init__.py +15 -0
  253. aria_code/datasources/sources/akshare_source.py +269 -0
  254. aria_code/datasources/sources/alpha_vantage_source.py +203 -0
  255. aria_code/datasources/sources/edgar_source.py +219 -0
  256. aria_code/datasources/sources/finnhub_source.py +198 -0
  257. aria_code/datasources/sources/fred_source.py +223 -0
  258. aria_code/datasources/sources/tushare_source.py +143 -0
  259. aria_code/datasources/sources/web_scraper_source.py +278 -0
  260. aria_code/datasources/sources/world_bank_source.py +206 -0
  261. aria_code/datasources/sources/yfinance_source.py +152 -0
  262. aria_code/demo_player.py +207 -0
  263. aria_code/doctor.py +813 -0
  264. aria_code/domain/__init__.py +0 -0
  265. aria_code/domain/backtest_engine.py +354 -0
  266. aria_code/domain/backtest_report.py +472 -0
  267. aria_code/domain/finance_formulas.py +389 -0
  268. aria_code/domain/portfolio_ledger.py +307 -0
  269. aria_code/domain/strategy_vault.py +421 -0
  270. aria_code/evals/__init__.py +37 -0
  271. aria_code/evals/harness.py +598 -0
  272. aria_code/evals/runner.py +238 -0
  273. aria_code/external_agent_runner.py +115 -0
  274. aria_code/figma_client.py +4 -0
  275. aria_code/file_analysis_tools.py +4 -0
  276. aria_code/finance_formulas.py +4 -0
  277. aria_code/football_data_client.py +4 -0
  278. aria_code/image_gen_tools.py +4 -0
  279. aria_code/intent_classifier.py +386 -0
  280. aria_code/kling_video_client.py +4 -0
  281. aria_code/licensing.py +151 -0
  282. aria_code/local_finance_tools.py +4 -0
  283. aria_code/local_image_provider.py +4 -0
  284. aria_code/local_llm_provider.py +4 -0
  285. aria_code/macro_tools.py +4 -0
  286. aria_code/markdown_pdf.py +289 -0
  287. aria_code/market_data_client.py +4 -0
  288. aria_code/mcp_client.py +639 -0
  289. aria_code/memory_manager.py +246 -0
  290. aria_code/model_capability.py +486 -0
  291. aria_code/notification_tools.py +4 -0
  292. aria_code/openai_image_client.py +4 -0
  293. aria_code/packages/__init__.py +23 -0
  294. aria_code/packages/adk_bridge/__init__.py +11 -0
  295. aria_code/packages/adk_bridge/code_review_tools.py +49 -0
  296. aria_code/packages/adk_bridge/market_tools.py +125 -0
  297. aria_code/packages/aria_agents/__init__.py +5 -0
  298. aria_code/packages/aria_agents/manifest.py +78 -0
  299. aria_code/packages/aria_core/__init__.py +34 -0
  300. aria_code/packages/aria_core/architecture.py +269 -0
  301. aria_code/packages/aria_core/export.py +147 -0
  302. aria_code/packages/aria_core/manifest.py +65 -0
  303. aria_code/packages/aria_core/paths.py +57 -0
  304. aria_code/packages/aria_core/secure_file.py +68 -0
  305. aria_code/packages/aria_infra/__init__.py +15 -0
  306. aria_code/packages/aria_infra/arthera.py +52 -0
  307. aria_code/packages/aria_infra/doctor.py +246 -0
  308. aria_code/packages/aria_infra/product.py +40 -0
  309. aria_code/packages/aria_mcp/__init__.py +25 -0
  310. aria_code/packages/aria_mcp/bridge.py +201 -0
  311. aria_code/packages/aria_mcp/circuit.py +82 -0
  312. aria_code/packages/aria_mcp/config.py +111 -0
  313. aria_code/packages/aria_mcp/installer.py +95 -0
  314. aria_code/packages/aria_mcp/server.py +1550 -0
  315. aria_code/packages/aria_mcp/tools.py +81 -0
  316. aria_code/packages/aria_sdk/__init__.py +19 -0
  317. aria_code/packages/aria_sdk/client.py +396 -0
  318. aria_code/packages/aria_sdk/providers.py +70 -0
  319. aria_code/packages/aria_sdk/streaming.py +79 -0
  320. aria_code/packages/aria_sdk/types.py +86 -0
  321. aria_code/packages/aria_services/__init__.py +92 -0
  322. aria_code/packages/aria_services/cache.py +60 -0
  323. aria_code/packages/aria_services/context.py +356 -0
  324. aria_code/packages/aria_services/context_checkpoints.py +157 -0
  325. aria_code/packages/aria_services/data.py +11 -0
  326. aria_code/packages/aria_services/provider_health.py +268 -0
  327. aria_code/packages/aria_services/references.py +247 -0
  328. aria_code/packages/aria_services/registry.py +249 -0
  329. aria_code/packages/aria_services/research_protocol.py +57 -0
  330. aria_code/packages/aria_services/research_quality.py +186 -0
  331. aria_code/packages/aria_services/settings.py +157 -0
  332. aria_code/packages/aria_services/usage.py +151 -0
  333. aria_code/packages/aria_skills/__init__.py +46 -0
  334. aria_code/packages/aria_skills/catalog.py +149 -0
  335. aria_code/packages/aria_skills/loader.py +455 -0
  336. aria_code/packages/aria_skills/registry.py +84 -0
  337. aria_code/packages/aria_tools/__init__.py +5 -0
  338. aria_code/packages/aria_tools/financial/__init__.py +8 -0
  339. aria_code/packages/aria_tools/financial/_paths.py +130 -0
  340. aria_code/packages/aria_tools/financial/compliance.py +31 -0
  341. aria_code/packages/aria_tools/financial/factors.py +33 -0
  342. aria_code/packages/aria_tools/financial/risk_tools.py +33 -0
  343. aria_code/packages/aria_tools/financial/strategy.py +31 -0
  344. aria_code/packages/aria_tools/registry.py +128 -0
  345. aria_code/packages/quant_engine/__init__.py +34 -0
  346. aria_code/packages/quant_engine/_namespace.py +62 -0
  347. aria_code/packages/quant_engine/backtest/__init__.py +14 -0
  348. aria_code/packages/quant_engine/backtest/core.py +53 -0
  349. aria_code/packages/quant_engine/backtest/engine.py +96 -0
  350. aria_code/packages/quant_engine/portfolio/__init__.py +13 -0
  351. aria_code/packages/quant_engine/portfolio/optimizer.py +85 -0
  352. aria_code/packages/quant_engine/sports/__init__.py +80 -0
  353. aria_code/packages/quant_engine/sports/calibrator.py +354 -0
  354. aria_code/packages/quant_engine/sports/dixon_coles.py +234 -0
  355. aria_code/packages/quant_engine/sports/elo.py +300 -0
  356. aria_code/packages/quant_engine/sports/form.py +188 -0
  357. aria_code/packages/quant_engine/sports/h2h.py +195 -0
  358. aria_code/packages/quant_engine/sports/ml_model.py +377 -0
  359. aria_code/packages/quant_engine/sports/predictor.py +312 -0
  360. aria_code/packages/quant_engine/sports/tracker.py +665 -0
  361. aria_code/packages/quant_engine/stochastic/__init__.py +35 -0
  362. aria_code/packages/quant_engine/stochastic/gbm_enhanced.py +195 -0
  363. aria_code/packages/quant_engine/stochastic/ito_calculus.py +477 -0
  364. aria_code/packages/quant_engine/stochastic/kelly_criterion.py +181 -0
  365. aria_code/packages/quant_engine/stochastic/monte_carlo_advanced.py +95 -0
  366. aria_code/packages/quant_engine/stochastic/options_pricing.py +576 -0
  367. aria_code/packages/quant_engine/stochastic/stochastic_processes.py +90 -0
  368. aria_code/packs/__init__.py +85 -0
  369. aria_code/packs/base.py +168 -0
  370. aria_code/packs/finance/__init__.py +250 -0
  371. aria_code/packs/logistics/__init__.py +169 -0
  372. aria_code/packs/payments/__init__.py +139 -0
  373. aria_code/packs/realty/__init__.py +190 -0
  374. aria_code/packs/registry.py +202 -0
  375. aria_code/packs/rules.py +90 -0
  376. aria_code/plan_utils.py +194 -0
  377. aria_code/plugin_loader.py +328 -0
  378. aria_code/portfolio_ledger.py +4 -0
  379. aria_code/preview_server.py +449 -0
  380. aria_code/privacy/__init__.py +5 -0
  381. aria_code/privacy/feedback.py +123 -0
  382. aria_code/project_review.py +278 -0
  383. aria_code/project_review_api.py +235 -0
  384. aria_code/project_review_server.py +18 -0
  385. aria_code/project_tools.py +4 -0
  386. aria_code/providers/__init__.py +30 -0
  387. aria_code/providers/llm/__init__.py +19 -0
  388. aria_code/providers/llm/anthropic.py +184 -0
  389. aria_code/providers/llm/autoconfig.py +213 -0
  390. aria_code/providers/llm/base.py +139 -0
  391. aria_code/providers/llm/custom.py +158 -0
  392. aria_code/providers/llm/ollama.py +129 -0
  393. aria_code/providers/llm/openai_compat.py +313 -0
  394. aria_code/providers/llm/registry.py +444 -0
  395. aria_code/providers/local_image_provider.py +202 -0
  396. aria_code/providers/local_llm_provider.py +589 -0
  397. aria_code/realty_data_tools.py +4 -0
  398. aria_code/report_exporters.py +150 -0
  399. aria_code/report_generator.py +1764 -0
  400. aria_code/runtime/__init__.py +169 -0
  401. aria_code/runtime/acceptance.py +481 -0
  402. aria_code/runtime/agent_loop.py +1520 -0
  403. aria_code/runtime/approval.py +57 -0
  404. aria_code/runtime/budget.py +232 -0
  405. aria_code/runtime/checkpoints.py +432 -0
  406. aria_code/runtime/crash_report.py +174 -0
  407. aria_code/runtime/events.py +113 -0
  408. aria_code/runtime/gateway.py +150 -0
  409. aria_code/runtime/lsp.py +484 -0
  410. aria_code/runtime/orchestrator.py +55 -0
  411. aria_code/runtime/repo_map.py +700 -0
  412. aria_code/runtime/run_state.py +127 -0
  413. aria_code/runtime/run_store.py +450 -0
  414. aria_code/runtime/self_healing.py +422 -0
  415. aria_code/runtime/subagent.py +547 -0
  416. aria_code/runtime/task_ledger.py +86 -0
  417. aria_code/runtime/task_orchestrator.py +90 -0
  418. aria_code/runtime/tool_executor.py +217 -0
  419. aria_code/runtime/tool_policy.py +107 -0
  420. aria_code/runtime/worktrees.py +215 -0
  421. aria_code/runway_video_client.py +4 -0
  422. aria_code/safety/__init__.py +23 -0
  423. aria_code/safety/permissions.py +306 -0
  424. aria_code/safety/service.py +102 -0
  425. aria_code/setup_wizard.py +673 -0
  426. aria_code/spreadsheet_tools.py +4 -0
  427. aria_code/strategy_vault.py +4 -0
  428. aria_code/tools/__init__.py +0 -0
  429. aria_code/tools/artifact_tools.py +252 -0
  430. aria_code/tools/broker_tools.py +92 -0
  431. aria_code/tools/build_quant_engine.py +97 -0
  432. aria_code/tools/code_audit_tools.py +192 -0
  433. aria_code/tools/computer_use_tools.py +504 -0
  434. aria_code/tools/data_analysis_tools.py +809 -0
  435. aria_code/tools/enterprise_finance_tools.py +156 -0
  436. aria_code/tools/extended_tools.py +240 -0
  437. aria_code/tools/file_analysis_tools.py +885 -0
  438. aria_code/tools/image_gen_tools.py +114 -0
  439. aria_code/tools/local_finance_tools.py +3417 -0
  440. aria_code/tools/logistics_tools.py +135 -0
  441. aria_code/tools/macro_tools.py +369 -0
  442. aria_code/tools/notification_tools.py +249 -0
  443. aria_code/tools/project_tools.py +525 -0
  444. aria_code/tools/realty_data_tools.py +659 -0
  445. aria_code/tools/spreadsheet_tools.py +388 -0
  446. aria_code/tools/stripe_tools.py +115 -0
  447. aria_code/ui/__init__.py +105 -0
  448. aria_code/ui/banner.py +508 -0
  449. aria_code/ui/completer.py +501 -0
  450. aria_code/ui/console.py +281 -0
  451. aria_code/ui/image_render.py +243 -0
  452. aria_code/ui/input_box.py +488 -0
  453. aria_code/ui/picker.py +201 -0
  454. aria_code/ui/render/__init__.py +11 -0
  455. aria_code/ui/render/finance.py +1705 -0
  456. aria_code/ui/render/market.py +225 -0
  457. aria_code/ui/render/output.py +775 -0
  458. aria_code/ui/render/responsive.py +75 -0
  459. aria_code/ui/render/team.py +354 -0
  460. aria_code/ui/robot.py +235 -0
  461. aria_code/ui/startup_dashboard.py +109 -0
  462. aria_code/utils/vscode_uri.py +37 -0
  463. aria_code/video_analysis.py +147 -0
  464. aria_code/video_editor.py +271 -0
  465. aria_code/workspace/__init__.py +6 -0
  466. aria_code/workspace/files.py +193 -0
  467. aria_code/workspace/verify.py +113 -0
  468. aria_code/workspace_changes.py +199 -0
  469. aria_code/workspace_context.py +233 -0
  470. aria_code/workspace_service.py +196 -0
  471. aria_code/workspace_tools.py +150 -0
  472. aria_code-0.52.0.dist-info/METADATA +237 -0
  473. aria_code-0.52.0.dist-info/RECORD +478 -0
  474. aria_code-0.52.0.dist-info/WHEEL +5 -0
  475. aria_code-0.52.0.dist-info/entry_points.txt +3 -0
  476. aria_code-0.52.0.dist-info/licenses/LICENSE +201 -0
  477. aria_code-0.52.0.dist-info/licenses/NOTICE +49 -0
  478. aria_code-0.52.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,457 @@
1
+ """DataCommandsMixin — data, alert, correlation, and comparison commands."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from ._ui import print_error
6
+
7
+
8
+ import json
9
+ import asyncio
10
+ import datetime
11
+ import time
12
+ import shlex
13
+ from typing import Dict, Any, Optional
14
+
15
+ def _render_portfolio_bt(*args, **kwargs):
16
+ from aria_cli import _render_portfolio_bt as fn
17
+ return fn(*args, **kwargs)
18
+ def _render_alerts(*args, **kwargs):
19
+ from aria_cli import _render_alerts as fn
20
+ return fn(*args, **kwargs)
21
+ def _get__HAS_LOCAL_FINANCE():
22
+ from aria_cli import _HAS_LOCAL_FINANCE as val
23
+ return val
24
+ def _get_LOCAL_TOOLS():
25
+ # Owned by apps/cli/tool_registry.py; aria_cli fills it in place.
26
+ from ..tool_registry import LOCAL_TOOLS as val
27
+ return val
28
+ def _render_corr_matrix(*args, **kwargs):
29
+ from aria_cli import _render_corr_matrix as fn
30
+ return fn(*args, **kwargs)
31
+ def _render_peer_comparison(*args, **kwargs):
32
+ from aria_cli import _render_peer_comparison as fn
33
+ return fn(*args, **kwargs)
34
+ def _render_sql_result(*args, **kwargs):
35
+ from aria_cli import _render_sql_result as fn
36
+ return fn(*args, **kwargs)
37
+
38
+ import json
39
+ import asyncio
40
+ import datetime
41
+ import time
42
+ import shlex
43
+ import sys
44
+ import os
45
+ from typing import Dict, Any, Optional
46
+
47
+
48
+ import json
49
+ import asyncio
50
+ import datetime
51
+ import time
52
+ import shlex
53
+ import sys
54
+ import os
55
+ from typing import Dict, Any, Optional
56
+
57
+
58
+ class DataCommandsMixin:
59
+ """Mixin: data analysis and comparison commands."""
60
+
61
+ async def cmd_data(self, args: str):
62
+ """
63
+ /data sql "SELECT ..." — DuckDB SQL 查询
64
+ /data export [filename] — 导出上次结果到 Excel
65
+ /data load <csv_path> — 加载 CSV 到 DuckDB
66
+ /data tables — 列出已加载的表
67
+ """
68
+ import asyncio as _asyncio
69
+ loop = _asyncio.get_event_loop()
70
+ parts = args.strip().split(None, 1) if args.strip() else []
71
+ sub = parts[0].lower() if parts else "help"
72
+ rest = parts[1] if len(parts) > 1 else ""
73
+
74
+ try:
75
+ from data_analysis_tools import (sql_query, sql_list_tables,
76
+ export_to_excel, load_csv_data)
77
+ except ImportError as e:
78
+ if self.context.has_rich:
79
+ self.context.console.print(f"[red]data_analysis_tools 未加载: {e}[/red]")
80
+ return
81
+
82
+ if sub == "sql":
83
+ query = rest.strip().strip('"').strip("'")
84
+ if not query:
85
+ if self.context.has_rich:
86
+ self.context.console.print("[dim]用法: /data sql \"SELECT ...\"|/dim]")
87
+ return
88
+ if self.context.has_rich:
89
+ with self.context.console.status("[dim]执行 SQL...[/dim]", spinner="dots"):
90
+ r = await loop.run_in_executor(None, sql_query, {"query": query})
91
+ else:
92
+ r = sql_query({"query": query})
93
+ _render_sql_result(r)
94
+
95
+ elif sub == "export":
96
+ fname = rest.strip() or None
97
+ watchlist = self.terminal.config.get("watchlist", ["AAPL", "MSFT", "SPY"])
98
+ try:
99
+ import yfinance as _yf
100
+ raw = _yf.download(watchlist[:5], period="1mo", progress=False, auto_adjust=True)
101
+ closes = raw["Close"] if hasattr(raw.columns, "levels") else raw
102
+ export_data = {"价格历史": closes.reset_index().to_dict("records")}
103
+ except Exception:
104
+ export_data = {"示例数据": [{"symbol": s, "note": "需 yfinance"} for s in watchlist]}
105
+ p = {"data": export_data, "filename": fname}
106
+ if self.context.has_rich:
107
+ with self.context.console.status("[dim]生成 Excel...[/dim]", spinner="dots"):
108
+ r = await loop.run_in_executor(None, export_to_excel, p)
109
+ else:
110
+ r = export_to_excel(p)
111
+ if r.get("success"):
112
+ msg = f"✓ 已导出: {r['path']} ({r['total_rows']} 行)"
113
+ if self.context.has_rich:
114
+ self.context.console.print(f"[green]{msg}[/green]")
115
+ else:
116
+ print(msg)
117
+ else:
118
+ if self.context.has_rich:
119
+ self.context.console.print(f"[red]{r.get('error')}[/red]")
120
+
121
+ elif sub == "load":
122
+ csv_path = rest.strip()
123
+ if not csv_path:
124
+ if self.context.has_rich:
125
+ self.context.console.print("[dim]用法: /data load <csv文件路径>[/dim]")
126
+ return
127
+ if self.context.has_rich:
128
+ with self.context.console.status("[dim]加载 CSV...[/dim]", spinner="dots"):
129
+ r = await loop.run_in_executor(None, load_csv_data, {"path": csv_path})
130
+ else:
131
+ r = load_csv_data({"path": csv_path})
132
+ if r.get("success"):
133
+ if self.context.has_rich:
134
+ self.context.console.print(f"[green]✓ 已加载 {r['rows']} 行 → 表 {r['table_name']}[/green]")
135
+ self.context.console.print(f"[dim]列: {', '.join(r['columns'][:10])}[/dim]")
136
+ self.context.console.print(f"[dim]现在可以: /data sql \"SELECT * FROM {r['table_name']} LIMIT 10\"[/dim]")
137
+ else:
138
+ if self.context.has_rich:
139
+ self.context.console.print(f"[red]{r.get('error')}[/red]")
140
+
141
+ elif sub == "tables":
142
+ r = sql_list_tables()
143
+ if r.get("success"):
144
+ tables = r.get("tables", [])
145
+ if self.context.has_rich:
146
+ if tables:
147
+ self.context.console.print(f"[bold]已加载表:[/bold] {', '.join(tables)}")
148
+ else:
149
+ self.context.console.print("[dim]暂无已加载的表。使用 /data load <csv> 加载数据[/dim]")
150
+
151
+ else:
152
+ if self.context.has_rich:
153
+ self.context.console.print("[dim]用法: /data [sql|export|load|tables][/dim]")
154
+ self.context.console.print("[dim] /data sql \"SELECT * FROM my_table LIMIT 10\"[/dim]")
155
+ self.context.console.print("[dim] /data load ~/Desktop/data.csv[/dim]")
156
+ self.context.console.print("[dim] /data export my_report.xlsx[/dim]")
157
+ self.context.console.print("[dim] /data tables[/dim]")
158
+
159
+ async def cmd_alert(self, args: str):
160
+ """
161
+ /alert add AAPL gt 200 — 设置预警(gt/lt/cross_up/cross_down)
162
+ /alert list — 列出所有预警
163
+ /alert delete <id> — 删除预警
164
+ /alert check — 检查所有预警状态
165
+ """
166
+ import asyncio as _asyncio
167
+ loop = _asyncio.get_event_loop()
168
+ parts = args.strip().split() if args.strip() else []
169
+ sub = parts[0].lower() if parts else "list"
170
+
171
+ try:
172
+ from data_analysis_tools import (add_price_alert, list_price_alerts,
173
+ delete_price_alert, check_alerts)
174
+ except ImportError as e:
175
+ if self.context.has_rich:
176
+ self.context.console.print(f"[red]data_analysis_tools 未加载: {e}[/red]")
177
+ return
178
+
179
+ if sub == "add":
180
+ if len(parts) < 4:
181
+ if self.context.has_rich:
182
+ self.context.console.print("[dim]用法: /alert add <symbol> <gt|lt|cross_up|cross_down> <price> [备注][/dim]")
183
+ return
184
+ sym = parts[1].upper()
185
+ cond = parts[2].lower()
186
+ try:
187
+ price = float(parts[3])
188
+ except ValueError:
189
+ if self.context.has_rich:
190
+ self.context.console.print("[red]价格必须是数字[/red]")
191
+ return
192
+ note = " ".join(parts[4:]) if len(parts) > 4 else ""
193
+ r = add_price_alert({"symbol": sym, "condition": cond, "price": price, "note": note})
194
+ if r.get("success"):
195
+ msg = r.get("message", "预警已设置")
196
+ if self.context.has_rich:
197
+ self.context.console.print(f"[green]✓ {msg}[/green]")
198
+ else:
199
+ print(f"✓ {msg}")
200
+ else:
201
+ if self.context.has_rich:
202
+ self.context.console.print(f"[red]{r.get('error')}[/red]")
203
+
204
+ elif sub == "list":
205
+ r = list_price_alerts()
206
+ _render_alerts(r)
207
+
208
+ elif sub in ("delete", "del", "remove"):
209
+ alert_id = parts[1] if len(parts) > 1 else ""
210
+ if not alert_id:
211
+ if self.context.has_rich:
212
+ self.context.console.print("[dim]用法: /alert delete <预警ID>[/dim]")
213
+ return
214
+ r = delete_price_alert({"alert_id": alert_id})
215
+ if r.get("success"):
216
+ if self.context.has_rich:
217
+ self.context.console.print(f"[green]✓ 已删除预警 {r['deleted_id']}[/green]")
218
+ else:
219
+ if self.context.has_rich:
220
+ self.context.console.print(f"[red]{r.get('error')}[/red]")
221
+
222
+ elif sub == "check":
223
+ if self.context.has_rich:
224
+ with self.context.console.status("[dim]检查价格预警...[/dim]", spinner="dots"):
225
+ r = await loop.run_in_executor(None, check_alerts)
226
+ else:
227
+ r = check_alerts()
228
+ triggered = r.get("triggered", [])
229
+ if triggered:
230
+ if self.context.has_rich:
231
+ self.context.console.print(f"[bold yellow]🔔 {len(triggered)} 个预警已触发![/bold yellow]")
232
+ for a in triggered:
233
+ self.context.console.print(f" [yellow]{a['symbol']}[/yellow] {a.get('condition','')} "
234
+ f"{a['price']} → 当前 [bold]{a.get('triggered_price','')}[/bold]")
235
+ else:
236
+ msg = r.get("message", "暂无触发的预警")
237
+ if self.context.has_rich:
238
+ self.context.console.print(f"[dim]{msg}[/dim]")
239
+
240
+ else:
241
+ if self.context.has_rich:
242
+ self.context.console.print("[dim]用法: /alert [add|list|delete|check][/dim]")
243
+
244
+ async def cmd_corr(self, args: str):
245
+ """/corr AAPL MSFT TSLA SPY [1y|2y|6mo] — 计算相关性矩阵"""
246
+ import asyncio as _asyncio
247
+ loop = _asyncio.get_event_loop()
248
+ parts = args.strip().upper().split() if args.strip() else []
249
+
250
+ period = "1y"
251
+ if parts and parts[-1].lower() in ("1y", "2y", "3y", "6mo", "ytd", "5y"):
252
+ period = parts[-1].lower()
253
+ parts = parts[:-1]
254
+
255
+ symbols = parts if parts else ["AAPL", "MSFT", "TSLA", "SPY", "QQQ"]
256
+
257
+ try:
258
+ from data_analysis_tools import calc_correlation_matrix
259
+ except ImportError as e:
260
+ if self.context.has_rich:
261
+ self.context.console.print(f"[red]data_analysis_tools 未加载: {e}[/red]")
262
+ return
263
+
264
+ if self.context.has_rich:
265
+ with self.context.console.status(f"[dim]计算 {', '.join(symbols)} 相关性矩阵...[/dim]", spinner="dots"):
266
+ r = await loop.run_in_executor(None, calc_correlation_matrix,
267
+ {"symbols": symbols, "period": period})
268
+ else:
269
+ r = calc_correlation_matrix({"symbols": symbols, "period": period})
270
+ _render_corr_matrix(r)
271
+
272
+ async def cmd_portfolio_bt(self, args: str):
273
+ """/ptbt AAPL MSFT GOOG [0.4 0.3 0.3] [2y] [monthly] — 多资产组合回测"""
274
+ import asyncio as _asyncio
275
+ loop = _asyncio.get_event_loop()
276
+ parts = args.strip().split() if args.strip() else []
277
+
278
+ try:
279
+ from data_analysis_tools import portfolio_backtest
280
+ except ImportError as e:
281
+ if self.context.has_rich:
282
+ self.context.console.print(f"[red]data_analysis_tools 未加载: {e}[/red]")
283
+ return
284
+
285
+ symbols, weights, period, rebalance = [], [], "2y", "monthly"
286
+ _PERIODS = {"1y", "2y", "3y", "5y", "6mo", "ytd", "max"}
287
+ _REBALANCE = {"monthly", "quarterly", "none"}
288
+ for p in parts:
289
+ pl = p.lower()
290
+ if pl in _PERIODS:
291
+ period = pl
292
+ continue
293
+ if pl in _REBALANCE:
294
+ rebalance = pl
295
+ continue
296
+ try:
297
+ f = float(p)
298
+ if f < 2:
299
+ weights.append(f)
300
+ else:
301
+ symbols.append(p.upper())
302
+ except ValueError:
303
+ symbols.append(p.upper())
304
+
305
+ if not symbols:
306
+ symbols = ["AAPL", "MSFT", "GOOGL", "SPY"]
307
+ if self.context.has_rich:
308
+ self.context.console.print(f"[dim]未指定标的,使用默认: {symbols}[/dim]")
309
+
310
+ p_params = {"symbols": symbols, "period": period, "rebalance": rebalance}
311
+ if weights:
312
+ p_params["weights"] = weights
313
+
314
+ if self.context.has_rich:
315
+ with self.context.console.status(f"[dim]回测 {', '.join(symbols)} ({period})...[/dim]", spinner="dots"):
316
+ r = await loop.run_in_executor(None, portfolio_backtest, p_params)
317
+ else:
318
+ r = portfolio_backtest(p_params)
319
+ _render_portfolio_bt(r)
320
+
321
+ async def cmd_peer(self, args: str):
322
+ """/peer <symbol> [peer1 peer2 ...] — 同行估值对比"""
323
+ parts = args.strip().upper().split() if args.strip() else []
324
+ symbol = parts[0] if parts else "AAPL"
325
+ peers = parts[1:] if len(parts) > 1 else []
326
+
327
+ if not _get__HAS_LOCAL_FINANCE():
328
+ if self.context.has_rich:
329
+ self.context.console.print("[red]local_finance_tools 未加载[/red]")
330
+ return
331
+
332
+ import asyncio as _asyncio
333
+ loop = _asyncio.get_event_loop()
334
+ if self.context.has_rich:
335
+ with self.context.console.status(f"[dim]获取 {symbol} 同行数据...[/dim]", spinner="dots"):
336
+ from local_finance_tools import _peer_comparison
337
+ r = await loop.run_in_executor(None, _peer_comparison,
338
+ {"symbol": symbol, "peers": peers})
339
+ else:
340
+ from local_finance_tools import _peer_comparison
341
+ r = _peer_comparison({"symbol": symbol, "peers": peers})
342
+
343
+ _render_peer_comparison(r)
344
+
345
+ async def cmd_compare(self, args: str):
346
+ """多策略横向对比 → /api/v1/backtest/compare-strategies"""
347
+ parts = args.split() if args else ["SPY"]
348
+ symbol = parts[0].upper() if parts else "SPY"
349
+ start = parts[1] if len(parts) > 1 else "2020-01-01"
350
+ end = parts[2] if len(parts) > 2 else __import__("datetime").date.today().isoformat()
351
+ api_url = self.terminal.config.get("api_url", "http://localhost:8000")
352
+ import aiohttp
353
+
354
+ _STRATS = ["momentum", "mean_reversion", "breakout", "turtle", "ma_crossover"]
355
+
356
+ async def _do():
357
+ payload = {"symbol": symbol, "strategies": _STRATS,
358
+ "start_date": start, "end_date": end, "initial_capital": 100000, "commission_rate": 0.0003}
359
+ async with aiohttp.ClientSession() as sess:
360
+ async with sess.post(f"{api_url}/api/v1/backtest/compare-strategies", json=payload, timeout=aiohttp.ClientTimeout(total=90)) as resp:
361
+ if resp.status != 200:
362
+ raise RuntimeError(f"HTTP {resp.status}")
363
+ body = await resp.json()
364
+ return body.get("data", body)
365
+
366
+ def _do_local():
367
+ """Fallback: run each strategy via the local backtest engine and
368
+ assemble the same shape the backend endpoint returns. Used when the
369
+ backend is down or lacks the compare-strategies endpoint."""
370
+ import asyncio as _aio
371
+ rows = []
372
+ bench_pct = 0.0
373
+ for strat in _STRATS:
374
+ try:
375
+ res = _get_LOCAL_TOOLS()["backtest_strategy"][0](
376
+ {"symbol": symbol, "strategy": strat})
377
+ except Exception:
378
+ continue
379
+ if not res.get("success"):
380
+ continue
381
+ d = res.get("data", res)
382
+ ann = float(d.get("annual_return", 0) or 0)
383
+ mdd = float(d.get("max_drawdown", 0) or 0)
384
+ calmar = (ann / abs(mdd)) if mdd else 0.0
385
+ rows.append({
386
+ "name": strat,
387
+ "annualized_return_pct": ann * 100,
388
+ "sharpe_ratio": float(d.get("sharpe_ratio", 0) or 0),
389
+ "max_drawdown_pct": mdd * 100,
390
+ "calmar_ratio": calmar,
391
+ "sortino_ratio": float(d.get("sortino_ratio", 0) or 0),
392
+ "win_rate_pct": float(d.get("win_rate", 0) or 0) * 100,
393
+ "n_trades": int(d.get("total_trades", 0) or 0),
394
+ })
395
+ br = d.get("benchmark_return")
396
+ if br is not None and br == br: # not NaN
397
+ bench_pct = float(br) * 100
398
+ rows.sort(key=lambda r: r["sharpe_ratio"], reverse=True)
399
+ for i, r in enumerate(rows, 1):
400
+ r["rank_by_sharpe"] = i
401
+ return {"strategies": rows, "benchmark": {"annualized_return_pct": bench_pct},
402
+ "provider": "local"}
403
+
404
+ async def _do_with_fallback():
405
+ try:
406
+ return await _do()
407
+ except Exception:
408
+ # Backend unavailable / missing endpoint → local engine
409
+ if self.context.has_rich:
410
+ self.context.console.print(" [dim]后端不可用,使用本地回测引擎对比…[/dim]")
411
+ return _do_local()
412
+
413
+ if self.context.has_rich:
414
+ with self.context.console.status(f"[dim]Comparing strategies on {symbol}...[/dim]", spinner="dots"):
415
+ try:
416
+ data = await _do_with_fallback()
417
+ except Exception as e:
418
+ print_error(self.context, str(e), "tool")
419
+ return
420
+ else:
421
+ print(f"Comparing strategies on {symbol}...")
422
+ try:
423
+ data = await _do_with_fallback()
424
+ except Exception as e:
425
+ print_error(self.context, str(e), "tool")
426
+ return
427
+ if not data.get("strategies"):
428
+ print_error(self.context, "策略对比无结果", "本地回测引擎未返回数据,检查标的代码是否正确")
429
+ return
430
+
431
+ strategies = data.get("strategies", [])
432
+ bh = data.get("benchmark", {})
433
+ if self.context.has_rich:
434
+ from rich.table import Table
435
+ tbl = Table(title=f"[bold]{symbol} Strategy Comparison[/bold] {start} → {end}", show_header=True, header_style="bold")
436
+ for col in ["Rank", "Strategy", "Ann.Ret%", "Sharpe", "MaxDD%", "Calmar", "Sortino", "Win%", "Trades"]:
437
+ tbl.add_column(col, justify="right")
438
+ for s in strategies:
439
+ tbl.add_row(
440
+ str(s.get("rank_by_sharpe", "")),
441
+ s["name"],
442
+ f"{s.get('annualized_return_pct',0):+.1f}%",
443
+ f"{s.get('sharpe_ratio',0):.3f}",
444
+ f"{s.get('max_drawdown_pct',0):.1f}%",
445
+ f"{s.get('calmar_ratio',0):.2f}",
446
+ f"{s.get('sortino_ratio',0):.2f}",
447
+ f"{s.get('win_rate_pct',0):.0f}%",
448
+ str(s.get("n_trades",0)),
449
+ )
450
+ tbl.add_row("—", "[dim]Buy & Hold[/dim]",
451
+ f"{bh.get('annualized_return_pct',0):+.1f}%",
452
+ f"{bh.get('sharpe_ratio',0):.3f}",
453
+ f"{bh.get('max_drawdown_pct',0):.1f}%", "—", "—", "—", "2")
454
+ self.context.console.print(tbl)
455
+ else:
456
+ for s in strategies:
457
+ print(f"{s['name']}: Ann={s.get('annualized_return_pct',0):+.1f}% Sharpe={s.get('sharpe_ratio',0):.2f} DD={s.get('max_drawdown_pct',0):.1f}%")