aria-code 0.167.0__py3-none-win_amd64.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 (601) hide show
  1. aria_bots/__init__.py +7 -0
  2. aria_bots/channels/README.md +97 -0
  3. aria_bots/channels/__init__.py +1 -0
  4. aria_bots/channels/approvals.py +263 -0
  5. aria_bots/channels/conversation.py +280 -0
  6. aria_bots/channels/digest.py +186 -0
  7. aria_bots/channels/registry.py +95 -0
  8. aria_bots/engine.py +144 -0
  9. aria_bots/feishu_bot.py +1385 -0
  10. aria_bots/logistics/__init__.py +1 -0
  11. aria_bots/logistics/carriers.py +253 -0
  12. aria_bots/logistics/freight.py +154 -0
  13. aria_bots/logistics/inventory.py +242 -0
  14. aria_bots/logistics/mcp_server.py +156 -0
  15. aria_bots/logistics/records.py +119 -0
  16. aria_bots/logistics/tenancy.py +152 -0
  17. aria_bots/market.py +91 -0
  18. aria_bots/relay_client.py +326 -0
  19. aria_bots/telegram_bot.py +299 -0
  20. aria_code/__init__.py +111 -0
  21. aria_code/_bin/aria-native.exe +0 -0
  22. aria_code/_bin/aria-runtime.exe +0 -0
  23. aria_code/_version.py +20 -0
  24. aria_code/account_memory.py +296 -0
  25. aria_code/account_session.py +166 -0
  26. aria_code/adk_apps/__init__.py +1 -0
  27. aria_code/adk_apps/aria_code_review/__init__.py +1 -0
  28. aria_code/adk_apps/aria_code_review/agent.py +32 -0
  29. aria_code/adk_apps/aria_research/__init__.py +1 -0
  30. aria_code/adk_apps/aria_research/agent.py +31 -0
  31. aria_code/agents/__init__.py +49 -0
  32. aria_code/agents/base.py +329 -0
  33. aria_code/agents/code_review.py +200 -0
  34. aria_code/agents/deep/__init__.py +37 -0
  35. aria_code/agents/deep/calibration_loop.py +144 -0
  36. aria_code/agents/deep/critic.py +125 -0
  37. aria_code/agents/deep/deepen.py +193 -0
  38. aria_code/agents/deep/models.py +149 -0
  39. aria_code/agents/deep/pipeline.py +164 -0
  40. aria_code/agents/deep/quant_fusion.py +192 -0
  41. aria_code/agents/deep/themes.py +95 -0
  42. aria_code/agents/deep/tiers.py +106 -0
  43. aria_code/agents/engineering/__init__.py +14 -0
  44. aria_code/agents/engineering/coder.py +222 -0
  45. aria_code/agents/engineering/tester.py +145 -0
  46. aria_code/agents/financial/__init__.py +21 -0
  47. aria_code/agents/financial/cashflow_burn.py +119 -0
  48. aria_code/agents/financial/catalyst.py +279 -0
  49. aria_code/agents/financial/corporate_finance.py +175 -0
  50. aria_code/agents/financial/debate.py +224 -0
  51. aria_code/agents/financial/earnings.py +315 -0
  52. aria_code/agents/financial/fundamental.py +178 -0
  53. aria_code/agents/financial/macro.py +111 -0
  54. aria_code/agents/financial/news.py +231 -0
  55. aria_code/agents/financial/risk.py +146 -0
  56. aria_code/agents/financial/sector.py +279 -0
  57. aria_code/agents/financial/strategist.py +121 -0
  58. aria_code/agents/financial/stripe_revenue.py +127 -0
  59. aria_code/agents/financial/synthesis.py +274 -0
  60. aria_code/agents/financial/technical.py +277 -0
  61. aria_code/agents/orchestrator.py +44 -0
  62. aria_code/agents/portfolio_agent.py +392 -0
  63. aria_code/agents/realty/__init__.py +62 -0
  64. aria_code/agents/realty/asset_diagnosis.py +152 -0
  65. aria_code/agents/realty/business_match.py +166 -0
  66. aria_code/agents/realty/cashflow_verify.py +209 -0
  67. aria_code/agents/realty/contract_rules.py +210 -0
  68. aria_code/agents/realty/energy_anomaly.py +189 -0
  69. aria_code/agents/realty/exit_settlement.py +208 -0
  70. aria_code/agents/realty/fulfillment_risk.py +206 -0
  71. aria_code/agents/realty/ops_optimize.py +160 -0
  72. aria_code/agents/realty/revenue_share.py +215 -0
  73. aria_code/agents/registry.py +168 -0
  74. aria_code/agents/signal_scheme.py +111 -0
  75. aria_code/agents/sports/__init__.py +0 -0
  76. aria_code/agents/sports/football_agent.py +197 -0
  77. aria_code/agents/supervisor.py +113 -0
  78. aria_code/agents/team.py +500 -0
  79. aria_code/agents/video/__init__.py +16 -0
  80. aria_code/agents/video/director.py +376 -0
  81. aria_code/agents/video/qa_agent.py +143 -0
  82. aria_code/agents/video/script_doctor.py +112 -0
  83. aria_code/agents/warehouse/__init__.py +25 -0
  84. aria_code/agents/warehouse/contracts.py +26 -0
  85. aria_code/agents/warehouse/dashboard.py +155 -0
  86. aria_code/agents/warehouse/fulfillment_leadtime.py +95 -0
  87. aria_code/agents/warehouse/inbound_exceptions.py +25 -0
  88. aria_code/agents/warehouse/inventory_health.py +24 -0
  89. aria_code/agents/warehouse/local_run.py +71 -0
  90. aria_code/agents/warehouse/local_snapshot.py +132 -0
  91. aria_code/agents/warehouse/logistics_cost.py +84 -0
  92. aria_code/agents/warehouse/logistics_sync.py +21 -0
  93. aria_code/agents/warehouse/navigation.schema.json +110 -0
  94. aria_code/agents/warehouse/task_agent.py +172 -0
  95. aria_code/agents/warehouse/workflow.py +31 -0
  96. aria_code/aliyun_data_client.py +4 -0
  97. aria_code/apps/README.md +12 -0
  98. aria_code/apps/__init__.py +2 -0
  99. aria_code/apps/channels/README.md +9 -0
  100. aria_code/apps/channels/__init__.py +17 -0
  101. aria_code/apps/channels/approvals.py +11 -0
  102. aria_code/apps/channels/conversation.py +11 -0
  103. aria_code/apps/channels/digest.py +11 -0
  104. aria_code/apps/channels/intake.py +92 -0
  105. aria_code/apps/channels/registry.py +11 -0
  106. aria_code/apps/channels/tradingview.py +94 -0
  107. aria_code/apps/cli/README.md +13 -0
  108. aria_code/apps/cli/__init__.py +2 -0
  109. aria_code/apps/cli/_optional.py +120 -0
  110. aria_code/apps/cli/app_server.py +656 -0
  111. aria_code/apps/cli/auto_update.py +125 -0
  112. aria_code/apps/cli/bootstrap.py +206 -0
  113. aria_code/apps/cli/broker_render.py +206 -0
  114. aria_code/apps/cli/chat_turn.py +1327 -0
  115. aria_code/apps/cli/cloud_models.py +231 -0
  116. aria_code/apps/cli/codegen_paths.py +29 -0
  117. aria_code/apps/cli/commands/__init__.py +34 -0
  118. aria_code/apps/cli/commands/_business_render.py +78 -0
  119. aria_code/apps/cli/commands/_ui.py +71 -0
  120. aria_code/apps/cli/commands/analysis_cmds.py +378 -0
  121. aria_code/apps/cli/commands/ashare_prediction_cmds.py +327 -0
  122. aria_code/apps/cli/commands/auth_cmds.py +215 -0
  123. aria_code/apps/cli/commands/backtest_cmds.py +2518 -0
  124. aria_code/apps/cli/commands/broker_cmds.py +1236 -0
  125. aria_code/apps/cli/commands/business_workflow_cmds.py +379 -0
  126. aria_code/apps/cli/commands/canvas_cmds.py +77 -0
  127. aria_code/apps/cli/commands/catalog.py +189 -0
  128. aria_code/apps/cli/commands/core_cmds.py +2748 -0
  129. aria_code/apps/cli/commands/data_cmds.py +521 -0
  130. aria_code/apps/cli/commands/diagnostic_cmds.py +285 -0
  131. aria_code/apps/cli/commands/diagnostic_ops_cmds.py +813 -0
  132. aria_code/apps/cli/commands/engineering_cmds.py +399 -0
  133. aria_code/apps/cli/commands/file_cmds.py +312 -0
  134. aria_code/apps/cli/commands/finance_service_cmds.py +60 -0
  135. aria_code/apps/cli/commands/fx_commodity_cmds.py +123 -0
  136. aria_code/apps/cli/commands/market.py +544 -0
  137. aria_code/apps/cli/commands/market_cmds.py +1419 -0
  138. aria_code/apps/cli/commands/market_context.py +432 -0
  139. aria_code/apps/cli/commands/market_render.py +7 -0
  140. aria_code/apps/cli/commands/model_cmds.py +2374 -0
  141. aria_code/apps/cli/commands/ops_cmds.py +721 -0
  142. aria_code/apps/cli/commands/orchestrator_cmds.py +181 -0
  143. aria_code/apps/cli/commands/pdf_export_cmds.py +125 -0
  144. aria_code/apps/cli/commands/portfolio_cmds.py +1316 -0
  145. aria_code/apps/cli/commands/report.py +476 -0
  146. aria_code/apps/cli/commands/scaffold_templates.py +617 -0
  147. aria_code/apps/cli/commands/session_cmds.py +236 -0
  148. aria_code/apps/cli/commands/session_ux_cmds.py +359 -0
  149. aria_code/apps/cli/commands/team.py +723 -0
  150. aria_code/apps/cli/commands/team_render.py +8 -0
  151. aria_code/apps/cli/commands/ui_cmds.py +401 -0
  152. aria_code/apps/cli/commands/warehouse_cmds.py +297 -0
  153. aria_code/apps/cli/commands/workflow_cmds.py +629 -0
  154. aria_code/apps/cli/commands/workspace_cmds.py +1543 -0
  155. aria_code/apps/cli/config_paths.py +73 -0
  156. aria_code/apps/cli/config_store.py +158 -0
  157. aria_code/apps/cli/constants.py +88 -0
  158. aria_code/apps/cli/context.py +34 -0
  159. aria_code/apps/cli/conversation_policy.py +53 -0
  160. aria_code/apps/cli/deterministic.py +200 -0
  161. aria_code/apps/cli/direct.py +48 -0
  162. aria_code/apps/cli/earnings_view.py +172 -0
  163. aria_code/apps/cli/endpoint_migration.py +64 -0
  164. aria_code/apps/cli/exec_events.py +255 -0
  165. aria_code/apps/cli/file_references.py +155 -0
  166. aria_code/apps/cli/finance_service_catalog.py +111 -0
  167. aria_code/apps/cli/football_reports.py +231 -0
  168. aria_code/apps/cli/github_app_auth.py +135 -0
  169. aria_code/apps/cli/google_login.py +239 -0
  170. aria_code/apps/cli/handlers/__init__.py +11 -0
  171. aria_code/apps/cli/handlers/broker_handlers.py +122 -0
  172. aria_code/apps/cli/handlers/chart_handlers.py +1314 -0
  173. aria_code/apps/cli/handlers/market_handlers.py +2570 -0
  174. aria_code/apps/cli/handlers/realty_handlers.py +114 -0
  175. aria_code/apps/cli/handlers/sports_handlers.py +22 -0
  176. aria_code/apps/cli/handlers/strategy_advice.py +82 -0
  177. aria_code/apps/cli/headless.py +352 -0
  178. aria_code/apps/cli/helpers.py +326 -0
  179. aria_code/apps/cli/hooks.py +180 -0
  180. aria_code/apps/cli/i18n.py +310 -0
  181. aria_code/apps/cli/intent.py +136 -0
  182. aria_code/apps/cli/intent_router.py +305 -0
  183. aria_code/apps/cli/intent_shadow.py +72 -0
  184. aria_code/apps/cli/intent_signals.py +347 -0
  185. aria_code/apps/cli/lifecycle_hooks.py +48 -0
  186. aria_code/apps/cli/local_tool_schemas.py +550 -0
  187. aria_code/apps/cli/main.py +39 -0
  188. aria_code/apps/cli/market_hours.py +100 -0
  189. aria_code/apps/cli/market_metadata.py +135 -0
  190. aria_code/apps/cli/market_universe.py +487 -0
  191. aria_code/apps/cli/message_processing.py +310 -0
  192. aria_code/apps/cli/mixin_binding.py +32 -0
  193. aria_code/apps/cli/model_catalog.py +652 -0
  194. aria_code/apps/cli/model_probe.py +169 -0
  195. aria_code/apps/cli/model_retirement.py +65 -0
  196. aria_code/apps/cli/native_branding.py +12 -0
  197. aria_code/apps/cli/native_bridge.py +118 -0
  198. aria_code/apps/cli/native_entry.py +58 -0
  199. aria_code/apps/cli/pdf_report.py +977 -0
  200. aria_code/apps/cli/plan_mode.py +139 -0
  201. aria_code/apps/cli/plotly_html.py +15 -0
  202. aria_code/apps/cli/prediction_feedback.py +202 -0
  203. aria_code/apps/cli/preflight.py +502 -0
  204. aria_code/apps/cli/project_aria.py +60 -0
  205. aria_code/apps/cli/prompt_assembly.py +78 -0
  206. aria_code/apps/cli/prompts/__init__.py +0 -0
  207. aria_code/apps/cli/prompts/coding.py +71 -0
  208. aria_code/apps/cli/prompts/select.py +193 -0
  209. aria_code/apps/cli/prompts/system_prompts.py +562 -0
  210. aria_code/apps/cli/prompts/ui.py +436 -0
  211. aria_code/apps/cli/provider_endpoints.py +237 -0
  212. aria_code/apps/cli/provider_keys.py +73 -0
  213. aria_code/apps/cli/providers/__init__.py +1 -0
  214. aria_code/apps/cli/providers/base.py +775 -0
  215. aria_code/apps/cli/providers/chat_routing.py +139 -0
  216. aria_code/apps/cli/providers/collaboration.py +98 -0
  217. aria_code/apps/cli/providers/llm/__init__.py +1 -0
  218. aria_code/apps/cli/providers/llm/offline_responses.py +68 -0
  219. aria_code/apps/cli/providers/llm/ollama_stream.py +1574 -0
  220. aria_code/apps/cli/providers/llm/response_cache.py +60 -0
  221. aria_code/apps/cli/providers/llm/sse_stream.py +298 -0
  222. aria_code/apps/cli/providers/runtime_bridge.py +586 -0
  223. aria_code/apps/cli/providers/vertexai_stream.py +592 -0
  224. aria_code/apps/cli/release_download.py +159 -0
  225. aria_code/apps/cli/review_runner.py +111 -0
  226. aria_code/apps/cli/runtime_consumer.py +769 -0
  227. aria_code/apps/cli/sandbox.py +32 -0
  228. aria_code/apps/cli/session_export.py +120 -0
  229. aria_code/apps/cli/session_jsonl.py +208 -0
  230. aria_code/apps/cli/session_refresh.py +123 -0
  231. aria_code/apps/cli/session_store.py +125 -0
  232. aria_code/apps/cli/skills_catalog.py +273 -0
  233. aria_code/apps/cli/task_isolation.py +211 -0
  234. aria_code/apps/cli/terminal_chrome.py +412 -0
  235. aria_code/apps/cli/todo_tracker.py +190 -0
  236. aria_code/apps/cli/tool_executor.py +932 -0
  237. aria_code/apps/cli/tool_registry.py +34 -0
  238. aria_code/apps/cli/tool_scope.py +113 -0
  239. aria_code/apps/cli/tools/__init__.py +40 -0
  240. aria_code/apps/cli/tools/context.py +46 -0
  241. aria_code/apps/cli/tools/file_tools.py +181 -0
  242. aria_code/apps/cli/tools/market_tools.py +626 -0
  243. aria_code/apps/cli/tools/notebook_tools.py +111 -0
  244. aria_code/apps/cli/tools/system_tools.py +656 -0
  245. aria_code/apps/cli/tools/write_tools.py +961 -0
  246. aria_code/apps/cli/tradingview_bridge.py +529 -0
  247. aria_code/apps/cli/transactions.py +269 -0
  248. aria_code/apps/cli/turn_planning.py +137 -0
  249. aria_code/apps/cli/update_check.py +257 -0
  250. aria_code/apps/cli/updater.py +373 -0
  251. aria_code/apps/cli/utils/__init__.py +0 -0
  252. aria_code/apps/cli/utils/market_detect.py +1663 -0
  253. aria_code/apps/cli/web_login.py +136 -0
  254. aria_code/apps/cli/workflow_runner.py +127 -0
  255. aria_code/apps/cli/workspace_route.py +121 -0
  256. aria_code/apps/daemon/README.md +14 -0
  257. aria_code/apps/vscode/README.md +115 -0
  258. aria_code/apps/vscode/package.json +70 -0
  259. aria_code/aria_cli.py +5244 -0
  260. aria_code/aria_daemon.py +1372 -0
  261. aria_code/aria_feishu_bot.py +16 -0
  262. aria_code/aria_mcp_server.py +61 -0
  263. aria_code/aria_relay_client.py +4 -0
  264. aria_code/aria_telegram_bot.py +11 -0
  265. aria_code/ariarc.py +385 -0
  266. aria_code/artifacts.py +581 -0
  267. aria_code/backtest_engine.py +4 -0
  268. aria_code/backtest_report.py +4 -0
  269. aria_code/brokers/__init__.py +78 -0
  270. aria_code/brokers/automation.py +193 -0
  271. aria_code/brokers/base.py +231 -0
  272. aria_code/brokers/capabilities.py +264 -0
  273. aria_code/brokers/cn/__init__.py +10 -0
  274. aria_code/brokers/cn/easytrader_broker.py +193 -0
  275. aria_code/brokers/cn/futu_broker.py +194 -0
  276. aria_code/brokers/cn/longbridge_broker.py +190 -0
  277. aria_code/brokers/cn/tiger_broker.py +196 -0
  278. aria_code/brokers/cn/xtquant_broker.py +225 -0
  279. aria_code/brokers/config.py +414 -0
  280. aria_code/brokers/intl/__init__.py +5 -0
  281. aria_code/brokers/intl/alpaca_broker.py +183 -0
  282. aria_code/brokers/intl/ibkr_broker.py +215 -0
  283. aria_code/brokers/intl/trading212_broker.py +183 -0
  284. aria_code/brokers/intl/webull_broker.py +156 -0
  285. aria_code/brokers/paper_broker.py +266 -0
  286. aria_code/brokers/planning.py +296 -0
  287. aria_code/brokers/registry.py +213 -0
  288. aria_code/brokers/trading.py +267 -0
  289. aria_code/canva_client.py +4 -0
  290. aria_code/change_store.py +127 -0
  291. aria_code/clients/__init__.py +0 -0
  292. aria_code/clients/aliyun_data_client.py +660 -0
  293. aria_code/clients/aria_relay_client.py +16 -0
  294. aria_code/clients/canva_client.py +284 -0
  295. aria_code/clients/figma_client.py +100 -0
  296. aria_code/clients/football_data_client.py +1671 -0
  297. aria_code/clients/kling_video_client.py +182 -0
  298. aria_code/clients/market_data_client.py +1985 -0
  299. aria_code/clients/openai_image_client.py +242 -0
  300. aria_code/clients/runway_video_client.py +157 -0
  301. aria_code/clients/warehouse_erp_client.py +105 -0
  302. aria_code/cloud_memory.py +190 -0
  303. aria_code/command_safety.py +19 -0
  304. aria_code/computer_use_server.py +276 -0
  305. aria_code/computer_use_tools.py +4 -0
  306. aria_code/dashboard_generator.py +579 -0
  307. aria_code/data_analysis_tools.py +4 -0
  308. aria_code/data_cleaner.py +483 -0
  309. aria_code/data_service.py +513 -0
  310. aria_code/datasources/__init__.py +23 -0
  311. aria_code/datasources/base.py +166 -0
  312. aria_code/datasources/router.py +253 -0
  313. aria_code/datasources/sec_statements.py +217 -0
  314. aria_code/datasources/sources/__init__.py +15 -0
  315. aria_code/datasources/sources/akshare_source.py +269 -0
  316. aria_code/datasources/sources/alpha_vantage_source.py +203 -0
  317. aria_code/datasources/sources/edgar_source.py +219 -0
  318. aria_code/datasources/sources/finnhub_source.py +198 -0
  319. aria_code/datasources/sources/fred_source.py +223 -0
  320. aria_code/datasources/sources/tushare_source.py +143 -0
  321. aria_code/datasources/sources/web_scraper_source.py +278 -0
  322. aria_code/datasources/sources/world_bank_source.py +206 -0
  323. aria_code/datasources/sources/yfinance_source.py +152 -0
  324. aria_code/doctor.py +860 -0
  325. aria_code/domain/__init__.py +0 -0
  326. aria_code/domain/_finance_core/__init__.py +5 -0
  327. aria_code/domain/_finance_core/backtest_engine.py +325 -0
  328. aria_code/domain/_finance_core/performance_stats.py +101 -0
  329. aria_code/domain/backtest_engine.py +75 -0
  330. aria_code/domain/backtest_report.py +488 -0
  331. aria_code/domain/finance_formulas.py +389 -0
  332. aria_code/domain/performance_stats.py +6 -0
  333. aria_code/domain/portfolio_ledger.py +307 -0
  334. aria_code/domain/strategy_vault.py +421 -0
  335. aria_code/evals/__init__.py +37 -0
  336. aria_code/evals/behavior.py +113 -0
  337. aria_code/evals/gap.py +93 -0
  338. aria_code/evals/harness.py +949 -0
  339. aria_code/evals/review_probe.py +132 -0
  340. aria_code/evals/runner.py +425 -0
  341. aria_code/evals/scorecard.py +322 -0
  342. aria_code/evals/summary.py +125 -0
  343. aria_code/external_agent_runner.py +115 -0
  344. aria_code/figma_client.py +4 -0
  345. aria_code/file_analysis_tools.py +4 -0
  346. aria_code/finance_formulas.py +4 -0
  347. aria_code/football_data_client.py +4 -0
  348. aria_code/image_gen_tools.py +4 -0
  349. aria_code/intent_classifier.py +459 -0
  350. aria_code/kling_video_client.py +4 -0
  351. aria_code/licensing.py +151 -0
  352. aria_code/local_finance_tools.py +4 -0
  353. aria_code/local_image_provider.py +4 -0
  354. aria_code/local_llm_provider.py +4 -0
  355. aria_code/macro_tools.py +4 -0
  356. aria_code/markdown_pdf.py +289 -0
  357. aria_code/market_data_client.py +4 -0
  358. aria_code/mcp_client.py +744 -0
  359. aria_code/memory_manager.py +273 -0
  360. aria_code/model_capability.py +512 -0
  361. aria_code/notification_tools.py +4 -0
  362. aria_code/openai_image_client.py +4 -0
  363. aria_code/packages/__init__.py +26 -0
  364. aria_code/packages/adk_bridge/__init__.py +11 -0
  365. aria_code/packages/adk_bridge/code_review_tools.py +49 -0
  366. aria_code/packages/adk_bridge/market_tools.py +125 -0
  367. aria_code/packages/aria_agents/__init__.py +5 -0
  368. aria_code/packages/aria_agents/manifest.py +78 -0
  369. aria_code/packages/aria_core/__init__.py +34 -0
  370. aria_code/packages/aria_core/architecture.py +269 -0
  371. aria_code/packages/aria_core/export.py +147 -0
  372. aria_code/packages/aria_core/manifest.py +65 -0
  373. aria_code/packages/aria_core/paths.py +57 -0
  374. aria_code/packages/aria_core/secure_file.py +68 -0
  375. aria_code/packages/aria_infra/__init__.py +15 -0
  376. aria_code/packages/aria_infra/arthera.py +58 -0
  377. aria_code/packages/aria_infra/doctor.py +246 -0
  378. aria_code/packages/aria_infra/product.py +40 -0
  379. aria_code/packages/aria_mcp/__init__.py +25 -0
  380. aria_code/packages/aria_mcp/bridge.py +232 -0
  381. aria_code/packages/aria_mcp/circuit.py +82 -0
  382. aria_code/packages/aria_mcp/config.py +162 -0
  383. aria_code/packages/aria_mcp/installer.py +95 -0
  384. aria_code/packages/aria_mcp/server.py +1705 -0
  385. aria_code/packages/aria_mcp/tools.py +81 -0
  386. aria_code/packages/aria_sdk/__init__.py +19 -0
  387. aria_code/packages/aria_sdk/client.py +393 -0
  388. aria_code/packages/aria_sdk/providers.py +70 -0
  389. aria_code/packages/aria_sdk/streaming.py +75 -0
  390. aria_code/packages/aria_sdk/types.py +86 -0
  391. aria_code/packages/aria_services/__init__.py +92 -0
  392. aria_code/packages/aria_services/cache.py +60 -0
  393. aria_code/packages/aria_services/context.py +356 -0
  394. aria_code/packages/aria_services/context_checkpoints.py +157 -0
  395. aria_code/packages/aria_services/data.py +11 -0
  396. aria_code/packages/aria_services/provider_health.py +304 -0
  397. aria_code/packages/aria_services/references.py +247 -0
  398. aria_code/packages/aria_services/registry.py +249 -0
  399. aria_code/packages/aria_services/research_protocol.py +137 -0
  400. aria_code/packages/aria_services/research_quality.py +186 -0
  401. aria_code/packages/aria_services/settings.py +160 -0
  402. aria_code/packages/aria_services/usage.py +151 -0
  403. aria_code/packages/aria_skills/__init__.py +46 -0
  404. aria_code/packages/aria_skills/catalog.py +149 -0
  405. aria_code/packages/aria_skills/loader.py +455 -0
  406. aria_code/packages/aria_skills/registry.py +84 -0
  407. aria_code/packages/aria_tools/__init__.py +5 -0
  408. aria_code/packages/aria_tools/financial/__init__.py +5 -0
  409. aria_code/packages/aria_tools/financial/_paths.py +92 -0
  410. aria_code/packages/aria_tools/registry.py +129 -0
  411. aria_code/packages/quant_engine/__init__.py +33 -0
  412. aria_code/packages/quant_engine/_namespace.py +24 -0
  413. aria_code/packages/quant_engine/backtest/__init__.py +10 -0
  414. aria_code/packages/quant_engine/backtest/core.py +53 -0
  415. aria_code/packages/quant_engine/backtest/engine.py +102 -0
  416. aria_code/packages/quant_engine/portfolio/__init__.py +9 -0
  417. aria_code/packages/quant_engine/portfolio/optimizer.py +85 -0
  418. aria_code/packages/quant_engine/sports/__init__.py +76 -0
  419. aria_code/packages/quant_engine/sports/calibrator.py +354 -0
  420. aria_code/packages/quant_engine/sports/dixon_coles.py +234 -0
  421. aria_code/packages/quant_engine/sports/elo.py +300 -0
  422. aria_code/packages/quant_engine/sports/form.py +188 -0
  423. aria_code/packages/quant_engine/sports/h2h.py +195 -0
  424. aria_code/packages/quant_engine/sports/predictor.py +312 -0
  425. aria_code/packages/quant_engine/sports/tracker.py +665 -0
  426. aria_code/packages/quant_engine/stochastic/__init__.py +31 -0
  427. aria_code/packages/quant_engine/stochastic/gbm_enhanced.py +195 -0
  428. aria_code/packages/quant_engine/stochastic/ito_calculus.py +477 -0
  429. aria_code/packages/quant_engine/stochastic/kelly_criterion.py +181 -0
  430. aria_code/packages/quant_engine/stochastic/monte_carlo_advanced.py +95 -0
  431. aria_code/packages/quant_engine/stochastic/options_pricing.py +576 -0
  432. aria_code/packages/quant_engine/stochastic/stochastic_processes.py +90 -0
  433. aria_code/packs/__init__.py +85 -0
  434. aria_code/packs/base.py +168 -0
  435. aria_code/packs/finance/__init__.py +250 -0
  436. aria_code/packs/healthcare/__init__.py +40 -0
  437. aria_code/packs/logistics/__init__.py +171 -0
  438. aria_code/packs/payments/__init__.py +139 -0
  439. aria_code/packs/realty/__init__.py +190 -0
  440. aria_code/packs/registry.py +202 -0
  441. aria_code/packs/rules.py +90 -0
  442. aria_code/plan_utils.py +194 -0
  443. aria_code/plugin_loader.py +328 -0
  444. aria_code/portfolio_ledger.py +4 -0
  445. aria_code/preview_server.py +449 -0
  446. aria_code/privacy/__init__.py +5 -0
  447. aria_code/privacy/feedback.py +123 -0
  448. aria_code/project_review.py +278 -0
  449. aria_code/project_review_api.py +235 -0
  450. aria_code/project_review_server.py +18 -0
  451. aria_code/project_tools.py +4 -0
  452. aria_code/providers/__init__.py +30 -0
  453. aria_code/providers/google_video_provider.py +256 -0
  454. aria_code/providers/llm/__init__.py +19 -0
  455. aria_code/providers/llm/anthropic.py +184 -0
  456. aria_code/providers/llm/arthera_gateway.py +90 -0
  457. aria_code/providers/llm/autoconfig.py +213 -0
  458. aria_code/providers/llm/base.py +139 -0
  459. aria_code/providers/llm/custom.py +158 -0
  460. aria_code/providers/llm/ollama.py +137 -0
  461. aria_code/providers/llm/openai_compat.py +350 -0
  462. aria_code/providers/llm/registry.py +457 -0
  463. aria_code/providers/local_image_provider.py +202 -0
  464. aria_code/providers/local_llm_provider.py +549 -0
  465. aria_code/providers/ollama_models.py +79 -0
  466. aria_code/providers/openai_params.py +32 -0
  467. aria_code/providers/tool_messages.py +100 -0
  468. aria_code/realty_data_tools.py +4 -0
  469. aria_code/report_exporters.py +150 -0
  470. aria_code/report_generator.py +1764 -0
  471. aria_code/review_service.py +497 -0
  472. aria_code/runtime/__init__.py +176 -0
  473. aria_code/runtime/acceptance.py +632 -0
  474. aria_code/runtime/agent_loop.py +1851 -0
  475. aria_code/runtime/agent_profiles.py +75 -0
  476. aria_code/runtime/approval.py +71 -0
  477. aria_code/runtime/baseline.py +219 -0
  478. aria_code/runtime/budget.py +232 -0
  479. aria_code/runtime/checkpoints.py +481 -0
  480. aria_code/runtime/consult.py +65 -0
  481. aria_code/runtime/contract.py +282 -0
  482. aria_code/runtime/delivery.py +432 -0
  483. aria_code/runtime/events.py +113 -0
  484. aria_code/runtime/gateway.py +167 -0
  485. aria_code/runtime/lsp.py +484 -0
  486. aria_code/runtime/native_index.py +153 -0
  487. aria_code/runtime/orchestrator.py +55 -0
  488. aria_code/runtime/processes.py +343 -0
  489. aria_code/runtime/project_graph.py +614 -0
  490. aria_code/runtime/repo_map.py +712 -0
  491. aria_code/runtime/research_bundle.py +105 -0
  492. aria_code/runtime/review.py +269 -0
  493. aria_code/runtime/run_state.py +127 -0
  494. aria_code/runtime/run_store.py +522 -0
  495. aria_code/runtime/scoped_runs.py +113 -0
  496. aria_code/runtime/self_healing.py +422 -0
  497. aria_code/runtime/semantic_diff.py +171 -0
  498. aria_code/runtime/subagent.py +721 -0
  499. aria_code/runtime/symbol_edit.py +117 -0
  500. aria_code/runtime/task_brief.py +46 -0
  501. aria_code/runtime/task_context.py +145 -0
  502. aria_code/runtime/task_ledger.py +108 -0
  503. aria_code/runtime/task_orchestrator.py +90 -0
  504. aria_code/runtime/task_outcome.py +33 -0
  505. aria_code/runtime/task_verification.py +266 -0
  506. aria_code/runtime/task_worktree.py +448 -0
  507. aria_code/runtime/tool_executor.py +329 -0
  508. aria_code/runtime/tool_policy.py +107 -0
  509. aria_code/runtime/transactions.py +216 -0
  510. aria_code/runtime/windows_job.py +115 -0
  511. aria_code/runtime/workflows.py +222 -0
  512. aria_code/runtime/worktrees.py +215 -0
  513. aria_code/runway_video_client.py +4 -0
  514. aria_code/safety/__init__.py +27 -0
  515. aria_code/safety/client_isolation.py +178 -0
  516. aria_code/safety/permissions.py +339 -0
  517. aria_code/safety/risk.py +699 -0
  518. aria_code/safety/sandbox.py +148 -0
  519. aria_code/safety/service.py +102 -0
  520. aria_code/service_endpoints.py +14 -0
  521. aria_code/setup_wizard.py +684 -0
  522. aria_code/spreadsheet_tools.py +4 -0
  523. aria_code/strategy_vault.py +4 -0
  524. aria_code/tools/__init__.py +0 -0
  525. aria_code/tools/artifact_tools.py +252 -0
  526. aria_code/tools/broker_tools.py +92 -0
  527. aria_code/tools/build_quant_engine.py +97 -0
  528. aria_code/tools/code_audit_tools.py +192 -0
  529. aria_code/tools/computer_use_tools.py +509 -0
  530. aria_code/tools/data_analysis_tools.py +831 -0
  531. aria_code/tools/enterprise_finance_tools.py +202 -0
  532. aria_code/tools/extended_tools.py +240 -0
  533. aria_code/tools/file_analysis_tools.py +880 -0
  534. aria_code/tools/image_gen_tools.py +114 -0
  535. aria_code/tools/local_finance_tools.py +3488 -0
  536. aria_code/tools/logistics_carriers.py +11 -0
  537. aria_code/tools/logistics_inventory.py +11 -0
  538. aria_code/tools/logistics_io.py +11 -0
  539. aria_code/tools/logistics_tenancy.py +11 -0
  540. aria_code/tools/logistics_tools.py +11 -0
  541. aria_code/tools/macro_tools.py +412 -0
  542. aria_code/tools/notification_tools.py +249 -0
  543. aria_code/tools/project_tools.py +525 -0
  544. aria_code/tools/realty_data_tools.py +662 -0
  545. aria_code/tools/spreadsheet_tools.py +399 -0
  546. aria_code/tools/stripe_tools.py +115 -0
  547. aria_code/tools/video_tools.py +500 -0
  548. aria_code/training/__init__.py +1 -0
  549. aria_code/training/compare.py +117 -0
  550. aria_code/training/prelude_commands.py +111 -0
  551. aria_code/training/prelude_eval.py +390 -0
  552. aria_code/training/prelude_real.py +183 -0
  553. aria_code/training/prelude_train.py +248 -0
  554. aria_code/training/sft_dataset.py +230 -0
  555. aria_code/training/trajectory_dataset.py +263 -0
  556. aria_code/ui/__init__.py +105 -0
  557. aria_code/ui/banner.py +404 -0
  558. aria_code/ui/completer.py +571 -0
  559. aria_code/ui/console.py +285 -0
  560. aria_code/ui/input_box.py +505 -0
  561. aria_code/ui/mentions.py +206 -0
  562. aria_code/ui/picker.py +248 -0
  563. aria_code/ui/render/__init__.py +11 -0
  564. aria_code/ui/render/actions.py +297 -0
  565. aria_code/ui/render/finance.py +1732 -0
  566. aria_code/ui/render/market.py +253 -0
  567. aria_code/ui/render/output.py +954 -0
  568. aria_code/ui/render/responsive.py +75 -0
  569. aria_code/ui/render/team.py +367 -0
  570. aria_code/ui/robot.py +239 -0
  571. aria_code/ui/startup_dashboard.py +110 -0
  572. aria_code/video_analysis.py +147 -0
  573. aria_code/video_editor.py +518 -0
  574. aria_code/video_workflow/__init__.py +8 -0
  575. aria_code/video_workflow/__main__.py +61 -0
  576. aria_code/video_workflow/engines/__init__.py +18 -0
  577. aria_code/video_workflow/engines/base.py +69 -0
  578. aria_code/video_workflow/engines/custom_model.py +204 -0
  579. aria_code/video_workflow/engines/google_veo.py +94 -0
  580. aria_code/video_workflow/engines/local_engine.py +71 -0
  581. aria_code/video_workflow/engines/registry.py +98 -0
  582. aria_code/video_workflow/google_models.py +278 -0
  583. aria_code/video_workflow/music/__init__.py +5 -0
  584. aria_code/video_workflow/music/foley_service.py +132 -0
  585. aria_code/video_workflow/music/service.py +212 -0
  586. aria_code/video_workflow/pipeline.py +620 -0
  587. aria_code/video_workflow/plan.py +202 -0
  588. aria_code/video_workflow/session.py +297 -0
  589. aria_code/workspace/__init__.py +6 -0
  590. aria_code/workspace/files.py +219 -0
  591. aria_code/workspace/verify.py +167 -0
  592. aria_code/workspace_changes.py +199 -0
  593. aria_code/workspace_service.py +196 -0
  594. aria_code/workspace_tools.py +150 -0
  595. aria_code-0.167.0.dist-info/METADATA +330 -0
  596. aria_code-0.167.0.dist-info/RECORD +601 -0
  597. aria_code-0.167.0.dist-info/WHEEL +5 -0
  598. aria_code-0.167.0.dist-info/entry_points.txt +5 -0
  599. aria_code-0.167.0.dist-info/licenses/LICENSE +201 -0
  600. aria_code-0.167.0.dist-info/licenses/NOTICE +49 -0
  601. aria_code-0.167.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,521 @@
1
+ """DataCommandsMixin — data, alert, correlation, and comparison commands."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from aria_code.apps.cli.i18n import ui_text
6
+
7
+ from ._ui import print_error
8
+
9
+
10
+ import json
11
+ import asyncio
12
+ import datetime
13
+ import time
14
+ import shlex
15
+ from typing import Dict, Any, Optional
16
+
17
+ def _render_portfolio_bt(*args, **kwargs):
18
+ from aria_cli import _render_portfolio_bt as fn
19
+ return fn(*args, **kwargs)
20
+ def _render_alerts(*args, **kwargs):
21
+ from aria_cli import _render_alerts as fn
22
+ return fn(*args, **kwargs)
23
+ def _get__HAS_LOCAL_FINANCE():
24
+ from aria_cli import _HAS_LOCAL_FINANCE as val
25
+ return val
26
+ def _get_LOCAL_TOOLS():
27
+ # Owned by apps/cli/tool_registry.py; aria_cli fills it in place.
28
+ from ..tool_registry import LOCAL_TOOLS as val
29
+ return val
30
+ def _render_corr_matrix(*args, **kwargs):
31
+ from aria_cli import _render_corr_matrix as fn
32
+ return fn(*args, **kwargs)
33
+ def _render_peer_comparison(*args, **kwargs):
34
+ from aria_cli import _render_peer_comparison as fn
35
+ return fn(*args, **kwargs)
36
+ def _render_sql_result(*args, **kwargs):
37
+ from aria_cli import _render_sql_result as fn
38
+ return fn(*args, **kwargs)
39
+
40
+ import json
41
+ import asyncio
42
+ import datetime
43
+ import time
44
+ import shlex
45
+ import sys
46
+ import os
47
+ from typing import Dict, Any, Optional
48
+
49
+
50
+ import json
51
+ import asyncio
52
+ import datetime
53
+ import time
54
+ import shlex
55
+ import sys
56
+ import os
57
+ from typing import Dict, Any, Optional
58
+
59
+
60
+ class DataCommandsMixin:
61
+ """Mixin: data analysis and comparison commands."""
62
+
63
+ async def cmd_data(self, args: str):
64
+ """
65
+ /data sql "SELECT ..." — DuckDB SQL 查询
66
+ /data export [filename] — 导出上次结果到 Excel
67
+ /data load <csv_path> — 加载 CSV 到 DuckDB
68
+ /data tables — 列出已加载的表
69
+ """
70
+ import asyncio as _asyncio
71
+ loop = _asyncio.get_event_loop()
72
+ parts = args.strip().split(None, 1) if args.strip() else []
73
+ sub = parts[0].lower() if parts else "help"
74
+ rest = parts[1] if len(parts) > 1 else ""
75
+
76
+ try:
77
+ from data_analysis_tools import (sql_query, sql_list_tables,
78
+ export_to_excel, load_csv_data)
79
+ except ImportError as e:
80
+ if self.context.has_rich:
81
+ self.context.console.print(f"[red]data_analysis_tools 未加载: {e}[/red]")
82
+ return
83
+
84
+ if sub == "sql":
85
+ query = rest.strip().strip('"').strip("'")
86
+ if not query:
87
+ if self.context.has_rich:
88
+ self.context.console.print("[dim]用法: /data sql \"SELECT ...\"|/dim]")
89
+ return
90
+ if self.context.has_rich:
91
+ with self.context.console.status(f"[dim]{ui_text(self, '执行 SQL', 'Running SQL')}...[/dim]", spinner="dots"):
92
+ r = await loop.run_in_executor(None, sql_query, {"query": query})
93
+ else:
94
+ r = sql_query({"query": query})
95
+ _render_sql_result(r)
96
+
97
+ elif sub == "export":
98
+ fname = rest.strip() or None
99
+ watchlist = self.terminal.config.get("watchlist", ["AAPL", "MSFT", "SPY"])
100
+ try:
101
+ import yfinance as _yf
102
+ raw = _yf.download(watchlist[:5], period="1mo", progress=False, auto_adjust=True)
103
+ closes = raw["Close"] if hasattr(raw.columns, "levels") else raw
104
+ export_data = {"价格历史": closes.reset_index().to_dict("records")}
105
+ except Exception:
106
+ export_data = {"示例数据": [{"symbol": s, "note": "需 yfinance"} for s in watchlist]}
107
+ p = {"data": export_data, "filename": fname}
108
+ if self.context.has_rich:
109
+ with self.context.console.status(f"[dim]{ui_text(self, '生成 Excel', 'Building Excel')}...[/dim]", spinner="dots"):
110
+ r = await loop.run_in_executor(None, export_to_excel, p)
111
+ else:
112
+ r = export_to_excel(p)
113
+ if r.get("success"):
114
+ msg = f"✓ 已导出: {r['path']} ({r['total_rows']} 行)"
115
+ if self.context.has_rich:
116
+ self.context.console.print(f"[green]{msg}[/green]")
117
+ else:
118
+ print(msg)
119
+ else:
120
+ if self.context.has_rich:
121
+ self.context.console.print(f"[red]{r.get('error')}[/red]")
122
+
123
+ elif sub == "load":
124
+ csv_path = rest.strip()
125
+ if not csv_path:
126
+ if self.context.has_rich:
127
+ self.context.console.print("[dim]用法: /data load <csv文件路径>[/dim]")
128
+ return
129
+ if self.context.has_rich:
130
+ with self.context.console.status(f"[dim]{ui_text(self, '加载 CSV', 'Loading CSV')}...[/dim]", spinner="dots"):
131
+ r = await loop.run_in_executor(None, load_csv_data, {"path": csv_path})
132
+ else:
133
+ r = load_csv_data({"path": csv_path})
134
+ if r.get("success"):
135
+ if self.context.has_rich:
136
+ self.context.console.print(f"[green]✓ 已加载 {r['rows']} 行 → 表 {r['table_name']}[/green]")
137
+ self.context.console.print(f"[dim]列: {', '.join(r['columns'][:10])}[/dim]")
138
+ self.context.console.print(f"[dim]现在可以: /data sql \"SELECT * FROM {r['table_name']} LIMIT 10\"[/dim]")
139
+ else:
140
+ if self.context.has_rich:
141
+ self.context.console.print(f"[red]{r.get('error')}[/red]")
142
+
143
+ elif sub == "tables":
144
+ r = sql_list_tables()
145
+ if r.get("success"):
146
+ tables = r.get("tables", [])
147
+ if self.context.has_rich:
148
+ if tables:
149
+ self.context.console.print(f"[bold]已加载表:[/bold] {', '.join(tables)}")
150
+ else:
151
+ self.context.console.print("[dim]暂无已加载的表。使用 /data load <csv> 加载数据[/dim]")
152
+
153
+ else:
154
+ if self.context.has_rich:
155
+ self.context.console.print("[dim]用法: /data [sql|export|load|tables][/dim]")
156
+ self.context.console.print("[dim] /data sql \"SELECT * FROM my_table LIMIT 10\"[/dim]")
157
+ self.context.console.print("[dim] /data load ~/Desktop/data.csv[/dim]")
158
+ self.context.console.print("[dim] /data export my_report.xlsx[/dim]")
159
+ self.context.console.print("[dim] /data tables[/dim]")
160
+
161
+ async def cmd_alert(self, args: str):
162
+ """
163
+ /alert add AAPL gt 200 — 设置预警(gt/lt/cross_up/cross_down)
164
+ /alert list — 列出所有预警
165
+ /alert delete <id> — 删除预警
166
+ /alert check — 检查所有预警状态
167
+ """
168
+ import asyncio as _asyncio
169
+ loop = _asyncio.get_event_loop()
170
+ parts = args.strip().split() if args.strip() else []
171
+ sub = parts[0].lower() if parts else "list"
172
+
173
+ try:
174
+ from data_analysis_tools import (add_price_alert, list_price_alerts,
175
+ delete_price_alert, check_alerts)
176
+ except ImportError as e:
177
+ if self.context.has_rich:
178
+ self.context.console.print(f"[red]data_analysis_tools 未加载: {e}[/red]")
179
+ return
180
+
181
+ if sub == "add":
182
+ if len(parts) < 4:
183
+ if self.context.has_rich:
184
+ self.context.console.print("[dim]用法: /alert add <symbol> <gt|lt|cross_up|cross_down> <price> [备注][/dim]")
185
+ return
186
+ sym = parts[1].upper()
187
+ cond = parts[2].lower()
188
+ try:
189
+ price = float(parts[3])
190
+ except ValueError:
191
+ if self.context.has_rich:
192
+ self.context.console.print("[red]价格必须是数字[/red]")
193
+ return
194
+ note = " ".join(parts[4:]) if len(parts) > 4 else ""
195
+ r = add_price_alert({"symbol": sym, "condition": cond, "price": price, "note": note})
196
+ if r.get("success"):
197
+ msg = r.get("message", "预警已设置")
198
+ if self.context.has_rich:
199
+ self.context.console.print(f"[green]✓ {msg}[/green]")
200
+ else:
201
+ print(f"✓ {msg}")
202
+ else:
203
+ if self.context.has_rich:
204
+ self.context.console.print(f"[red]{r.get('error')}[/red]")
205
+
206
+ elif sub == "list":
207
+ r = list_price_alerts()
208
+ _render_alerts(r)
209
+
210
+ elif sub in ("delete", "del", "remove"):
211
+ alert_id = parts[1] if len(parts) > 1 else ""
212
+ if not alert_id:
213
+ if self.context.has_rich:
214
+ self.context.console.print("[dim]用法: /alert delete <预警ID>[/dim]")
215
+ return
216
+ r = delete_price_alert({"alert_id": alert_id})
217
+ if r.get("success"):
218
+ if self.context.has_rich:
219
+ self.context.console.print(f"[green]✓ 已删除预警 {r['deleted_id']}[/green]")
220
+ else:
221
+ if self.context.has_rich:
222
+ self.context.console.print(f"[red]{r.get('error')}[/red]")
223
+
224
+ elif sub == "check":
225
+ if self.context.has_rich:
226
+ with self.context.console.status(f"[dim]{ui_text(self, '检查价格预警', 'Checking price alerts')}...[/dim]", spinner="dots"):
227
+ r = await loop.run_in_executor(None, check_alerts)
228
+ else:
229
+ r = check_alerts()
230
+ triggered = r.get("triggered", [])
231
+ if triggered:
232
+ if self.context.has_rich:
233
+ self.context.console.print(f"[bold yellow]🔔 {len(triggered)} 个预警已触发![/bold yellow]")
234
+ for a in triggered:
235
+ self.context.console.print(f" [yellow]{a['symbol']}[/yellow] {a.get('condition','')} "
236
+ f"{a['price']} → 当前 [bold]{a.get('triggered_price','')}[/bold]")
237
+ else:
238
+ msg = r.get("message", "暂无触发的预警")
239
+ if self.context.has_rich:
240
+ self.context.console.print(f"[dim]{msg}[/dim]")
241
+
242
+ else:
243
+ if self.context.has_rich:
244
+ self.context.console.print("[dim]用法: /alert [add|list|delete|check][/dim]")
245
+
246
+ async def cmd_corr(self, args: str):
247
+ """/corr AAPL MSFT TSLA SPY [1y|2y|6mo] — 计算相关性矩阵"""
248
+ import asyncio as _asyncio
249
+ loop = _asyncio.get_event_loop()
250
+ parts = args.strip().upper().split() if args.strip() else []
251
+
252
+ period = "1y"
253
+ if parts and parts[-1].lower() in ("1y", "2y", "3y", "6mo", "ytd", "5y"):
254
+ period = parts[-1].lower()
255
+ parts = parts[:-1]
256
+
257
+ symbols = parts if parts else ["AAPL", "MSFT", "TSLA", "SPY", "QQQ"]
258
+
259
+ try:
260
+ from data_analysis_tools import calc_correlation_matrix
261
+ except ImportError as e:
262
+ if self.context.has_rich:
263
+ self.context.console.print(f"[red]data_analysis_tools 未加载: {e}[/red]")
264
+ return
265
+
266
+ if self.context.has_rich:
267
+ _names = ', '.join(symbols)
268
+ with self.context.console.status(f"[dim]{ui_text(self, f'计算 {_names} 相关性矩阵', f'Computing the {_names} correlation matrix')}...[/dim]", spinner="dots"):
269
+ r = await loop.run_in_executor(None, calc_correlation_matrix,
270
+ {"symbols": symbols, "period": period})
271
+ else:
272
+ r = calc_correlation_matrix({"symbols": symbols, "period": period})
273
+ _render_corr_matrix(r)
274
+
275
+ async def cmd_portfolio_bt(self, args: str):
276
+ """/ptbt AAPL MSFT GOOG [0.4 0.3 0.3] [2y] [monthly] — 多资产组合回测"""
277
+ import asyncio as _asyncio
278
+ loop = _asyncio.get_event_loop()
279
+ parts = args.strip().split() if args.strip() else []
280
+
281
+ try:
282
+ from data_analysis_tools import portfolio_backtest
283
+ except ImportError as e:
284
+ if self.context.has_rich:
285
+ self.context.console.print(f"[red]data_analysis_tools 未加载: {e}[/red]")
286
+ return
287
+
288
+ symbols, weights, period, rebalance = [], [], "2y", "monthly"
289
+ _PERIODS = {"1y", "2y", "3y", "5y", "6mo", "ytd", "max"}
290
+ _REBALANCE = {"monthly", "quarterly", "none"}
291
+ for p in parts:
292
+ pl = p.lower()
293
+ if pl in _PERIODS:
294
+ period = pl
295
+ continue
296
+ if pl in _REBALANCE:
297
+ rebalance = pl
298
+ continue
299
+ try:
300
+ f = float(p)
301
+ if f < 2:
302
+ weights.append(f)
303
+ else:
304
+ symbols.append(p.upper())
305
+ except ValueError:
306
+ symbols.append(p.upper())
307
+
308
+ if not symbols:
309
+ symbols = ["AAPL", "MSFT", "GOOGL", "SPY"]
310
+ if self.context.has_rich:
311
+ self.context.console.print(f"[dim]未指定标的,使用默认: {symbols}[/dim]")
312
+
313
+ p_params = {"symbols": symbols, "period": period, "rebalance": rebalance}
314
+ if weights:
315
+ p_params["weights"] = weights
316
+
317
+ if self.context.has_rich:
318
+ _names = ', '.join(symbols)
319
+ with self.context.console.status(f"[dim]{ui_text(self, f'回测 {_names} ({period})', f'Backtesting {_names} ({period})')}...[/dim]", spinner="dots"):
320
+ r = await loop.run_in_executor(None, portfolio_backtest, p_params)
321
+ else:
322
+ r = portfolio_backtest(p_params)
323
+ _render_portfolio_bt(r)
324
+
325
+ async def cmd_peer(self, args: str):
326
+ """/peer <symbol> [peer1 peer2 ...] — 同行估值对比"""
327
+ parts = args.strip().upper().split() if args.strip() else []
328
+ symbol = parts[0] if parts else "AAPL"
329
+ peers = parts[1:] if len(parts) > 1 else []
330
+
331
+ if not _get__HAS_LOCAL_FINANCE():
332
+ if self.context.has_rich:
333
+ self.context.console.print("[red]local_finance_tools 未加载[/red]")
334
+ return
335
+
336
+ import asyncio as _asyncio
337
+ loop = _asyncio.get_event_loop()
338
+ if self.context.has_rich:
339
+ with self.context.console.status(f"[dim]{ui_text(self, f'获取 {symbol} 同行数据', f'Fetching {symbol} peer data')}...[/dim]", spinner="dots"):
340
+ from local_finance_tools import _peer_comparison
341
+ r = await loop.run_in_executor(None, _peer_comparison,
342
+ {"symbol": symbol, "peers": peers, "lang": ui_text(self, "zh", "en")})
343
+ else:
344
+ from local_finance_tools import _peer_comparison
345
+ r = _peer_comparison({"symbol": symbol, "peers": peers, "lang": ui_text(self, "zh", "en")})
346
+
347
+ _render_peer_comparison(r)
348
+
349
+ async def cmd_compare(self, args: str):
350
+ """/compare SYMBOL [start] [end] — several strategies on one symbol, against buy-and-hold.
351
+
352
+ /compare AAPL MSFT read MSFT as the start date, and the local fallback
353
+ ran four of its five strategies as buy-and-hold (the local engine had
354
+ no such names and fell through to it), so the table showed four
355
+ identical rows. Its "start → end" title was the dates asked for, not
356
+ the ones used, and the Buy & Hold row was a total return in the
357
+ annual-return column with a made-up trade count.
358
+ """
359
+ import re as _re
360
+
361
+ parts = args.split() if args and args.strip() else ["SPY"]
362
+ symbol = parts[0].upper()
363
+ rest = parts[1:]
364
+ def is_date(token: str) -> bool:
365
+ # A real date: 2024-13-01 has the shape and reached yfinance, whose
366
+ # failure was then explained as rate limiting.
367
+ try:
368
+ __import__("datetime").date.fromisoformat(token)
369
+ return len(token) == 10
370
+ except ValueError:
371
+ return False
372
+ if rest and not is_date(rest[0]):
373
+ # A symbol has a letter (AAPL, 0700.HK) or is a six-digit A-share code.
374
+ if all(_re.fullmatch(r"(?=.*[A-Za-z])[A-Za-z0-9.^=-]{1,12}|\d{6}", t) for t in rest):
375
+ # Two or more symbols: the user is comparing stocks, which is /peer.
376
+ peers = " ".join(t.upper() for t in rest)
377
+ note = f"→ /peer {symbol} {peers}"
378
+ self.context.console.print(f" [dim]{note}[/dim]") if self.context.has_rich else print(f" {note}")
379
+ await self.cmd_peer(f"{symbol} {peers}")
380
+ return
381
+ print_error(self.context, ui_text(self, f"无法识别的日期:{rest[0]}", f"Not a date: {rest[0]}"),
382
+ "Usage: /compare SYMBOL [YYYY-MM-DD] [YYYY-MM-DD]")
383
+ return
384
+ if len(rest) > 1 and not is_date(rest[1]):
385
+ print_error(self.context, ui_text(self, f"无法识别的日期:{rest[1]}", f"Not a date: {rest[1]}"),
386
+ "Usage: /compare SYMBOL [YYYY-MM-DD] [YYYY-MM-DD]")
387
+ return
388
+ start = rest[0] if rest else "2020-01-01"
389
+ end = rest[1] if len(rest) > 1 else __import__("datetime").date.today().isoformat()
390
+ api_url = self.terminal.config.get("api_url", "http://localhost:8000")
391
+ import aiohttp
392
+
393
+ _STRATS = ["momentum", "mean_reversion", "breakout", "turtle", "ma_crossover"]
394
+ # What the local engine can run, under the names /compare shows.
395
+ _LOCAL = {"momentum": "momentum", "mean_reversion": "rsi_mean_revert", "ma_crossover": "sma_cross"}
396
+
397
+ async def _do():
398
+ payload = {"symbol": symbol, "strategies": _STRATS,
399
+ "start_date": start, "end_date": end, "initial_capital": 100000, "commission_rate": 0.0003}
400
+ async with aiohttp.ClientSession(trust_env=True) as sess:
401
+ async with sess.post(f"{api_url}/api/v1/backtest/compare-strategies", json=payload, timeout=aiohttp.ClientTimeout(total=90)) as resp:
402
+ if resp.status != 200:
403
+ raise RuntimeError(f"HTTP {resp.status}")
404
+ body = await resp.json()
405
+ return body.get("data", body)
406
+
407
+ def _row(name: str, d: dict) -> dict:
408
+ ann = float(d.get("annual_return", 0) or 0)
409
+ mdd = float(d.get("max_drawdown", 0) or 0)
410
+ return {
411
+ "name": name,
412
+ "annualized_return_pct": ann * 100,
413
+ "sharpe_ratio": float(d.get("sharpe_ratio", 0) or 0),
414
+ "max_drawdown_pct": mdd * 100,
415
+ "calmar_ratio": (ann / abs(mdd)) if mdd else 0.0,
416
+ "sortino_ratio": float(d.get("sortino_ratio", 0) or 0),
417
+ "win_rate_pct": float(d.get("win_rate", 0) or 0) * 100,
418
+ "n_trades": int(d.get("total_trades", 0) or 0),
419
+ }
420
+
421
+ def _do_local():
422
+ """The strategies the local engine has, over the same dates, and
423
+ buy-and-hold run through the same engine as the benchmark."""
424
+ run = _get_LOCAL_TOOLS()["backtest_strategy"][0]
425
+ rows, period, errors = [], None, []
426
+ for shown, local in _LOCAL.items():
427
+ try:
428
+ res = run({"symbol": symbol, "strategy": local, "start": start, "end": end})
429
+ except Exception as exc:
430
+ errors.append(f"{shown}: {exc}")
431
+ continue
432
+ if not res.get("success"):
433
+ errors.append(f"{shown}: {res.get('error', 'failed')}")
434
+ continue
435
+ d = res.get("data", res)
436
+ period = period or (d.get("start"), d.get("end"))
437
+ rows.append(_row(shown, d))
438
+ rows.sort(key=lambda r: r["sharpe_ratio"], reverse=True)
439
+ for i, r in enumerate(rows, 1):
440
+ r["rank_by_sharpe"] = i
441
+ bench = {}
442
+ try:
443
+ b = run({"symbol": symbol, "strategy": "buy_hold", "start": start, "end": end})
444
+ if b.get("success"):
445
+ bench = _row("buy_hold", b.get("data", b))
446
+ except Exception:
447
+ pass
448
+ return {"strategies": rows, "benchmark": bench, "provider": "local", "period": period,
449
+ "skipped": [s for s in _STRATS if s not in _LOCAL], "errors": errors}
450
+
451
+ async def _do_with_fallback():
452
+ try:
453
+ return await _do()
454
+ except Exception:
455
+ # Backend unavailable / missing endpoint → local engine
456
+ note = ui_text(self, "后端不可用,使用本地回测引擎对比…",
457
+ "Backend unavailable; comparing with the local backtest engine…")
458
+ if self.context.has_rich:
459
+ self.context.console.print(f" [dim]{note}[/dim]")
460
+ import asyncio as _aio
461
+ return await _aio.get_event_loop().run_in_executor(None, _do_local)
462
+
463
+ status = ui_text(self, f"正在对比 {symbol} 的策略", f"Comparing strategies on {symbol}")
464
+ if self.context.has_rich:
465
+ with self.context.console.status(f"[dim]{status}...[/dim]", spinner="dots"):
466
+ try:
467
+ data = await _do_with_fallback()
468
+ except Exception as e:
469
+ print_error(self.context, str(e), "tool")
470
+ return
471
+ else:
472
+ print(f"{status}...")
473
+ try:
474
+ data = await _do_with_fallback()
475
+ except Exception as e:
476
+ print_error(self.context, str(e), "tool")
477
+ return
478
+ if not data.get("strategies"):
479
+ detail = "; ".join(data.get("errors") or []) or ui_text(
480
+ self, "检查标的代码和日期是否正确", "check the symbol and the dates")
481
+ print_error(self.context, ui_text(self, "策略对比无结果", "No strategy results"), detail)
482
+ return
483
+
484
+ strategies = data.get("strategies", [])
485
+ bh = data.get("benchmark", {}) or {}
486
+ period = data.get("period") or (start, end)
487
+ if self.context.has_rich:
488
+ from rich.table import Table
489
+ tbl = Table(title=f"[bold]{symbol} Strategy Comparison[/bold] {period[0]} → {period[1]}",
490
+ show_header=True, header_style="bold")
491
+ for col in ["Rank", "Strategy", "Ann.Ret%", "Sharpe", "MaxDD%", "Calmar", "Sortino", "Win%", "Trades"]:
492
+ tbl.add_column(col, justify="right")
493
+ for s in strategies:
494
+ tbl.add_row(
495
+ str(s.get("rank_by_sharpe", "")),
496
+ s["name"],
497
+ f"{s.get('annualized_return_pct',0):+.1f}%",
498
+ f"{s.get('sharpe_ratio',0):.3f}",
499
+ f"{s.get('max_drawdown_pct',0):.1f}%",
500
+ f"{s.get('calmar_ratio',0):.2f}",
501
+ f"{s.get('sortino_ratio',0):.2f}",
502
+ f"{s.get('win_rate_pct',0):.0f}%",
503
+ str(s.get("n_trades",0)),
504
+ )
505
+ if bh:
506
+ tbl.add_row("—", "[dim]Buy & Hold[/dim]",
507
+ f"{bh.get('annualized_return_pct',0):+.1f}%",
508
+ f"{bh.get('sharpe_ratio',0):.3f}",
509
+ f"{bh.get('max_drawdown_pct',0):.1f}%",
510
+ f"{bh['calmar_ratio']:.2f}" if "calmar_ratio" in bh else "—",
511
+ f"{bh['sortino_ratio']:.2f}" if "sortino_ratio" in bh else "—",
512
+ "—", str(bh["n_trades"]) if "n_trades" in bh else "—")
513
+ self.context.console.print(tbl)
514
+ if data.get("skipped"):
515
+ self.context.console.print(" [dim]" + ui_text(
516
+ self, f"本地引擎没有 {', '.join(data['skipped'])},需后端才能对比。",
517
+ f"{', '.join(data['skipped'])} need the backend; the local engine does not have them.")
518
+ + "[/dim]")
519
+ else:
520
+ for s in strategies:
521
+ 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}%")