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,31 @@
1
+ import os
2
+ import sys
3
+ import asyncio
4
+
5
+ from ._paths import find_skill_script, missing_script_message
6
+
7
+ try:
8
+ from arthera_sdk.mcp import mcp_tool
9
+ except ImportError:
10
+ def mcp_tool(*args, **kwargs):
11
+ def wrapper(f): return f
12
+ return wrapper
13
+
14
+ @mcp_tool(description="运行合规审计拦截网关。验证投资组合是否违反合规风控限制(如流动性、黑名单、集中度)。")
15
+ async def run_compliance_audit(strategy_name: str, assets: list[str]) -> str:
16
+ resolved = find_skill_script("compliance-audit-trail", "governance_manifest_gate.py")
17
+ if resolved is None:
18
+ return missing_script_message("compliance-audit-trail", "governance_manifest_gate.py")
19
+ script_path = str(resolved)
20
+ try:
21
+ proc = await asyncio.create_subprocess_exec(
22
+ "python3", script_path, "--demo", "--strategy", strategy_name, "--assets", ",".join(assets),
23
+ stdout=asyncio.subprocess.PIPE,
24
+ stderr=asyncio.subprocess.PIPE
25
+ )
26
+ stdout, stderr = await proc.communicate()
27
+ if proc.returncode == 0:
28
+ return stdout.decode()
29
+ return f"合规验证拦截:\n{stderr.decode()}"
30
+ except Exception as e:
31
+ return f"执行出错: {e}"
@@ -0,0 +1,33 @@
1
+ import os
2
+ import sys
3
+ import asyncio
4
+
5
+ from ._paths import ensure_arthera_sdk, find_skill_script, missing_script_message
6
+
7
+ ensure_arthera_sdk()
8
+
9
+ try:
10
+ from arthera_sdk.mcp import mcp_tool
11
+ except ImportError:
12
+ def mcp_tool(*args, **kwargs):
13
+ def wrapper(f): return f
14
+ return wrapper
15
+
16
+ @mcp_tool(description="运行核心财务因子的量化验证和研究分析。调用 factor_evaluate.py 进行验证。")
17
+ async def run_factor_research(symbol: str, factors: list[str]) -> str:
18
+ resolved = find_skill_script("factor-research", "factor_evaluate.py")
19
+ if resolved is None:
20
+ return missing_script_message("factor-research", "factor_evaluate.py")
21
+ script_path = str(resolved)
22
+ try:
23
+ proc = await asyncio.create_subprocess_exec(
24
+ "python3", script_path, "--symbol", symbol, "--factors", ",".join(factors),
25
+ stdout=asyncio.subprocess.PIPE,
26
+ stderr=asyncio.subprocess.PIPE
27
+ )
28
+ stdout, stderr = await proc.communicate()
29
+ if proc.returncode == 0:
30
+ return stdout.decode()
31
+ return f"脚本执行失败:\n{stderr.decode()}"
32
+ except Exception as e:
33
+ return f"执行出错: {e}"
@@ -0,0 +1,33 @@
1
+ import os
2
+ import sys
3
+ import asyncio
4
+
5
+ from ._paths import ensure_arthera_sdk, find_skill_script, missing_script_message
6
+
7
+ ensure_arthera_sdk()
8
+
9
+ try:
10
+ from arthera_sdk.mcp import mcp_tool
11
+ except ImportError:
12
+ def mcp_tool(*args, **kwargs):
13
+ def wrapper(f): return f
14
+ return wrapper
15
+
16
+ @mcp_tool(description="运行黑天鹅风险、相关性与下行压力测试。调用 risk_profile.py 进行验证。")
17
+ async def run_risk_profile(symbol: str) -> str:
18
+ resolved = find_skill_script("risk-assessment", "risk_profile.py")
19
+ if resolved is None:
20
+ return missing_script_message("risk-assessment", "risk_profile.py")
21
+ script_path = str(resolved)
22
+ try:
23
+ proc = await asyncio.create_subprocess_exec(
24
+ "python3", script_path, "--demo",
25
+ stdout=asyncio.subprocess.PIPE,
26
+ stderr=asyncio.subprocess.PIPE
27
+ )
28
+ stdout, stderr = await proc.communicate()
29
+ if proc.returncode == 0:
30
+ return stdout.decode()
31
+ return f"脚本执行失败:\n{stderr.decode()}"
32
+ except Exception as e:
33
+ return f"执行出错: {e}"
@@ -0,0 +1,31 @@
1
+ import os
2
+ import sys
3
+ import asyncio
4
+
5
+ from ._paths import find_skill_script, missing_script_message
6
+
7
+ try:
8
+ from arthera_sdk.mcp import mcp_tool
9
+ except ImportError:
10
+ def mcp_tool(*args, **kwargs):
11
+ def wrapper(f): return f
12
+ return wrapper
13
+
14
+ @mcp_tool(description="自动校验量化策略代码的逻辑规范与极端边界条件,生成策略鲁棒性诊断报告。")
15
+ async def validate_strategy_spec(strategy_name: str) -> str:
16
+ resolved = find_skill_script("strategy-generation", "validate_strategy_spec.py")
17
+ if resolved is None:
18
+ return missing_script_message("strategy-generation", "validate_strategy_spec.py")
19
+ script_path = str(resolved)
20
+ try:
21
+ proc = await asyncio.create_subprocess_exec(
22
+ "python3", script_path, "--demo",
23
+ stdout=asyncio.subprocess.PIPE,
24
+ stderr=asyncio.subprocess.PIPE
25
+ )
26
+ stdout, stderr = await proc.communicate()
27
+ if proc.returncode == 0:
28
+ return stdout.decode()
29
+ return f"策略校验失败:\n{stderr.decode()}"
30
+ except Exception as e:
31
+ return f"执行出错: {e}"
@@ -0,0 +1,128 @@
1
+ """Tool registry facade over Aria Code's legacy LOCAL_TOOLS shape."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, field
6
+ from typing import Any, Callable, Dict, Iterable, List, Mapping, Optional
7
+
8
+ from aria_code.packages.aria_core import CapabilityManifest, PermissionLevel, ServiceKind
9
+
10
+
11
+ Handler = Callable[[dict], dict]
12
+
13
+
14
+ _PERMISSION_BY_TOOL = {
15
+ "read_file": [PermissionLevel.READ_ONLY],
16
+ "list_files": [PermissionLevel.READ_ONLY],
17
+ "search_code": [PermissionLevel.READ_ONLY],
18
+ "glob": [PermissionLevel.READ_ONLY],
19
+ "write_file": [PermissionLevel.WORKSPACE_WRITE],
20
+ "edit_file": [PermissionLevel.WORKSPACE_WRITE],
21
+ "notebook_edit": [PermissionLevel.WORKSPACE_WRITE],
22
+ "run_command": [PermissionLevel.WORKSPACE_WRITE],
23
+ "web_fetch": [PermissionLevel.NETWORK],
24
+ "github": [PermissionLevel.NETWORK],
25
+ "get_market_data": [PermissionLevel.NETWORK],
26
+ "broker_query": [PermissionLevel.BROKER_READ],
27
+ "broker_order": [PermissionLevel.BROKER_TRADE],
28
+ }
29
+
30
+
31
+ @dataclass(frozen=True)
32
+ class ToolSpec:
33
+ name: str
34
+ handler: Optional[Handler]
35
+ description: str
36
+ schema: Dict[str, Any] = field(default_factory=dict)
37
+ permissions: List[PermissionLevel] = field(default_factory=list)
38
+ capabilities: List[str] = field(default_factory=list)
39
+
40
+ def manifest(self) -> CapabilityManifest:
41
+ return CapabilityManifest(
42
+ name=self.name,
43
+ kind=ServiceKind.TOOL,
44
+ description=self.description,
45
+ capabilities=self.capabilities,
46
+ permissions=self.permissions,
47
+ input_schema=self.schema,
48
+ tags=["tool"],
49
+ )
50
+
51
+
52
+ class ToolRegistry:
53
+ """Small typed registry that can wrap existing dict-based tools."""
54
+
55
+ def __init__(self) -> None:
56
+ self._tools: Dict[str, ToolSpec] = {}
57
+
58
+ def register(self, spec: ToolSpec, *, overwrite: bool = False) -> None:
59
+ if spec.name in self._tools and not overwrite:
60
+ raise ValueError(f"tool already registered: {spec.name}")
61
+ self._tools[spec.name] = spec
62
+
63
+ def get(self, name: str) -> Optional[ToolSpec]:
64
+ return self._tools.get(name)
65
+
66
+ def list(self) -> List[ToolSpec]:
67
+ return [self._tools[name] for name in sorted(self._tools)]
68
+
69
+ def manifests(self) -> List[CapabilityManifest]:
70
+ return [tool.manifest() for tool in self.list()]
71
+
72
+ def legacy_tools(self) -> Dict[str, tuple]:
73
+ return {
74
+ name: (spec.handler, spec.description)
75
+ for name, spec in self._tools.items()
76
+ if spec.handler is not None
77
+ }
78
+
79
+
80
+ def _schema_by_name(schemas: Iterable[dict]) -> Dict[str, dict]:
81
+ out: Dict[str, dict] = {}
82
+ for schema in schemas or []:
83
+ fn = schema.get("function") or {}
84
+ name = fn.get("name")
85
+ if name:
86
+ out[name] = fn.get("parameters") or {}
87
+ return out
88
+
89
+
90
+ def _capabilities_for_tool(name: str) -> List[str]:
91
+ if name.startswith("broker_"):
92
+ return ["broker"]
93
+ if name in ("get_market_data",) or "market" in name or "quote" in name:
94
+ return ["market.data"]
95
+ if name in ("read_file", "list_files", "search_code", "glob"):
96
+ return ["workspace.read"]
97
+ if name in ("write_file", "edit_file", "notebook_edit"):
98
+ return ["workspace.write"]
99
+ if name == "run_command":
100
+ return ["shell"]
101
+ if name in ("web_fetch", "github"):
102
+ return ["network"]
103
+ return ["tool"]
104
+
105
+
106
+ def build_registry_from_legacy(
107
+ tools: Mapping[str, tuple],
108
+ schemas: Iterable[dict] = (),
109
+ ) -> ToolRegistry:
110
+ """Create a typed registry from ``LOCAL_TOOLS`` and tool schemas."""
111
+
112
+ registry = ToolRegistry()
113
+ schema_map = _schema_by_name(schemas)
114
+ for name, value in tools.items():
115
+ handler = value[0] if value else None
116
+ description = value[1] if len(value) > 1 else ""
117
+ registry.register(
118
+ ToolSpec(
119
+ name=name,
120
+ handler=handler,
121
+ description=description,
122
+ schema=schema_map.get(name, {}),
123
+ permissions=_PERMISSION_BY_TOOL.get(name, [PermissionLevel.READ_ONLY]),
124
+ capabilities=_capabilities_for_tool(name),
125
+ ),
126
+ overwrite=True,
127
+ )
128
+ return registry
@@ -0,0 +1,34 @@
1
+ """quant_engine — vendored commodity quant modules (sports + stochastic).
2
+
3
+ Elo/Dixon-Coles football prediction and Black-Scholes/Monte-Carlo/Kelly
4
+ options+derivatives math. Proprietary factor/ML/strategy engines stay in the
5
+ private Arthera platform.
6
+
7
+ Open-core boundary: callers MUST go through ``is_available()`` and degrade
8
+ gracefully when it returns False. Today the source is bundled, so it is always
9
+ available — but routing every use through this boundary means the day the engine
10
+ is split into a separate compiled (.so) wheel, the free shell keeps working with
11
+ no caller changes (see tools/build_quant_engine.py, CLOSING_SOURCE.md).
12
+ """
13
+
14
+ from importlib.util import find_spec
15
+ from pathlib import Path
16
+
17
+ # ``packages`` is a namespace facade into the private Arthera platform, but
18
+ # this public shell also bundles a small ``quant_engine`` package. Python stops
19
+ # namespace lookup once it finds this regular subpackage, so extend *this*
20
+ # package path as well; otherwise ``packages.quant_engine.services`` (the
21
+ # audited A-share prediction engine) is silently unreachable from the CLI.
22
+ _private_quant_engine = Path(__file__).resolve().parents[3] / "Arthera" / "packages" / "quant_engine"
23
+ if _private_quant_engine.is_dir() and str(_private_quant_engine) not in __path__:
24
+ __path__.append(str(_private_quant_engine))
25
+
26
+ __version__ = "1.0.0"
27
+
28
+
29
+ def is_available() -> bool:
30
+ """True if the quant engine (bundled source or compiled wheel) can be imported."""
31
+ try:
32
+ return find_spec("packages.quant_engine.stochastic") is not None
33
+ except Exception:
34
+ return False
@@ -0,0 +1,62 @@
1
+ """让 quant_engine 的子包也能穿透到私有 Arthera 仓。
2
+
3
+ 背景:packages/__init__.py 与 packages/quant_engine/__init__.py 都做了
4
+ ``__path__.append(<Arthera 对应目录>)``,于是 ``packages.quant_engine.services``
5
+ 这类"只有 Arthera 才有"的模块可以透明解析。但拼接**只做了这两层**。
6
+
7
+ Python 的包解析在找到一个常规子包(带 __init__.py 的目录)后就停止查找,
8
+ 不会继续看父包 __path__ 里的其它条目。所以一旦 aria-code 自己有
9
+ ``stochastic/`` 这个目录,``packages.quant_engine.stochastic.<任何模块>``
10
+ 就只会在 aria-code 里找——哪怕 Arthera 有同名子包、有额外的模块。
11
+
12
+ 后果是同一个包的不同子模块,解析规则不一致:
13
+
14
+ packages.quant_engine.services.* → 穿透到 Arthera ✅(aria-code 没这个目录)
15
+ packages.quant_engine.stochastic.* → 只看 aria-code ❌(aria-code 有这个目录)
16
+
17
+ 实测确认过:删掉 aria-code 的 stochastic/ito_calculus.py 之后,
18
+ ``import packages.quant_engine.stochastic.ito_calculus`` 直接
19
+ ModuleNotFoundError,而不是回落到 Arthera 那份同名文件;只有把整个
20
+ stochastic/ 目录删掉才会穿透。
21
+
22
+ 这个不一致本身就是 bug 来源:Arthera 里 3202 行的 backtest/engine.py(内部有
23
+ 18 个文件依赖它)在 aria-code 侧被 93 行的同名文件完全遮蔽,而
24
+ ``sports/tracker.py`` 又是反过来的(aria-code 665 行、Arthera 454 行),
25
+ 说明两边都被单独改过、已经分叉。改了哪份生效取决于从哪个目录启动进程,
26
+ 这类 bug 极难发现。
27
+
28
+ extend() 把规则统一成一句话:**aria-code 自带的实现优先,Arthera 补齐缺口。**
29
+ append(而非 insert(0))保证公开仓的版本仍然赢——这维持了既有行为,本次改动
30
+ 只是让"Arthera 独有的模块"在所有层级都能被找到,不改变任何已能解析的模块
31
+ 指向谁。
32
+ """
33
+
34
+ from __future__ import annotations
35
+
36
+ from pathlib import Path
37
+ from typing import List
38
+
39
+ __all__ = ["extend"]
40
+
41
+ # packages/quant_engine/_namespace.py → 上溯 3 层到 aria-code/,再取同级 Arthera
42
+ _PRIVATE_ROOT = Path(__file__).resolve().parents[3] / "Arthera" / "packages" / "quant_engine"
43
+
44
+
45
+ def extend(package_path: List[str], subpackage: str) -> None:
46
+ """把 Arthera 侧的同名子包目录追加进 ``__path__``。
47
+
48
+ 子包 ``__init__.py`` 里调用::
49
+
50
+ from .._namespace import extend
51
+ extend(__path__, "stochastic")
52
+
53
+ Arthera checkout 不存在时静默跳过——公开仓的用户本来就没有它,
54
+ 那不是错误状态。
55
+ """
56
+ candidate = _PRIVATE_ROOT / subpackage
57
+ try:
58
+ if candidate.is_dir() and str(candidate) not in package_path:
59
+ package_path.append(str(candidate))
60
+ except OSError:
61
+ # 路径不可访问(权限、断开的符号链接)不该让 import 失败
62
+ pass
@@ -0,0 +1,14 @@
1
+ # 让本子包也能穿透到私有 Arthera 仓的同名子包。
2
+ # 父层 (packages / quant_engine) 已经做了 __path__ 拼接,但 Python 找到
3
+ # 常规子包后就停止查找,不会继续看父包 __path__ 的其它条目——所以每一层
4
+ # 都得自己声明。规则:aria-code 自带的实现优先,Arthera 补齐缺口。
5
+ # 详见 packages/quant_engine/_namespace.py 的模块文档。
6
+ from .._namespace import extend as _extend_namespace
7
+ _extend_namespace(__path__, "backtest")
8
+
9
+ """Backtest engine for evaluating AI trading signals."""
10
+
11
+ from .core import Order, Position, Portfolio
12
+ from .engine import BacktestEngine
13
+
14
+ __all__ = ["Order", "Position", "Portfolio", "BacktestEngine"]
@@ -0,0 +1,53 @@
1
+ from dataclasses import dataclass, field
2
+ from typing import Dict, List, Optional
3
+ from datetime import datetime
4
+
5
+ @dataclass
6
+ class Order:
7
+ symbol: str
8
+ quantity: float
9
+ price: float
10
+ order_type: str = "MARKET"
11
+ direction: str = "BUY" # BUY or SELL
12
+ status: str = "PENDING"
13
+ timestamp: Optional[datetime] = None
14
+
15
+ @dataclass
16
+ class Position:
17
+ symbol: str
18
+ quantity: float = 0.0
19
+ avg_price: float = 0.0
20
+
21
+ @property
22
+ def market_value(self, current_price: float) -> float:
23
+ return self.quantity * current_price
24
+
25
+ def update(self, quantity: float, price: float, is_buy: bool):
26
+ if is_buy:
27
+ total_cost = (self.quantity * self.avg_price) + (quantity * price)
28
+ self.quantity += quantity
29
+ self.avg_price = total_cost / self.quantity if self.quantity > 0 else 0
30
+ else:
31
+ self.quantity -= quantity
32
+ if self.quantity <= 0:
33
+ self.avg_price = 0.0
34
+ self.quantity = 0.0
35
+
36
+ class Portfolio:
37
+ def __init__(self, initial_cash: float = 100000.0):
38
+ self.initial_cash = initial_cash
39
+ self.cash = initial_cash
40
+ self.positions: Dict[str, Position] = {}
41
+ self.history: List[Dict] = []
42
+
43
+ def get_position(self, symbol: str) -> Position:
44
+ if symbol not in self.positions:
45
+ self.positions[symbol] = Position(symbol=symbol)
46
+ return self.positions[symbol]
47
+
48
+ def total_value(self, current_prices: Dict[str, float]) -> float:
49
+ pos_value = sum(
50
+ pos.quantity * current_prices.get(sym, pos.avg_price)
51
+ for sym, pos in self.positions.items()
52
+ )
53
+ return self.cash + pos_value
@@ -0,0 +1,96 @@
1
+ from typing import List, Dict, Any
2
+ import pandas as pd
3
+ from .core import Portfolio, Order
4
+
5
+ class BacktestEngine:
6
+ """Minimal Event-Driven Backtest Engine for Agent Signals"""
7
+
8
+ def __init__(self, initial_cash: float = 100000.0):
9
+ self.portfolio = Portfolio(initial_cash=initial_cash)
10
+ self.orders: List[Order] = []
11
+
12
+ def run_signals(self, price_data: pd.DataFrame, signals: List[Dict[str, Any]]):
13
+ """
14
+ Run backtest based on daily prices and agent signals.
15
+ price_data expects index to be datetime, with 'close' column.
16
+ signals expects format: [{'date': 'YYYY-MM-DD', 'signal': 'BUY', 'confidence': 0.8, 'symbol': 'AAPL'}]
17
+ """
18
+ # Convert signals to a dictionary indexed by date for O(1) lookup
19
+ signal_dict = {}
20
+ for s in signals:
21
+ try:
22
+ date_str = pd.to_datetime(s['date']).strftime('%Y-%m-%d')
23
+ signal_dict[date_str] = s
24
+ except (ValueError, TypeError, KeyError):
25
+ # 裸 except 会连 KeyboardInterrupt / SystemExit 一起吞掉——
26
+ # 循环里跑着时用户按 Ctrl+C 会被静默忽略。这里真正要容忍的
27
+ # 只是"某条信号的日期字段解析不了",收窄到具体异常。
28
+ pass
29
+
30
+ equity_curve = []
31
+
32
+ for date, row in price_data.iterrows():
33
+ current_price = float(row['close'])
34
+ date_str = date.strftime('%Y-%m-%d')
35
+ symbol = "UNKNOWN" # Simplification for single-asset backtest for now
36
+
37
+ # Check for signals on this date
38
+ if date_str in signal_dict:
39
+ sig = signal_dict[date_str]
40
+ symbol = sig.get('symbol', 'UNKNOWN')
41
+ action = sig.get('signal', 'HOLD').upper()
42
+ confidence = float(sig.get('confidence', 0.5))
43
+
44
+ if action == 'BUY':
45
+ # Allocate portion of cash based on confidence
46
+ target_investment = self.portfolio.cash * confidence
47
+ qty = int(target_investment / current_price)
48
+ if qty > 0:
49
+ cost = qty * current_price
50
+ self.portfolio.cash -= cost
51
+ pos = self.portfolio.get_position(symbol)
52
+ pos.update(qty, current_price, True)
53
+ self.orders.append(Order(symbol, qty, current_price, direction="BUY", status="FILLED", timestamp=date))
54
+
55
+ elif action in ['SELL', 'REDUCE']:
56
+ pos = self.portfolio.get_position(symbol)
57
+ if pos.quantity > 0:
58
+ # Sell portion based on confidence
59
+ sell_qty = int(pos.quantity * confidence)
60
+ if sell_qty > 0:
61
+ proceeds = sell_qty * current_price
62
+ self.portfolio.cash += proceeds
63
+ pos.update(sell_qty, current_price, False)
64
+ self.orders.append(Order(symbol, sell_qty, current_price, direction="SELL", status="FILLED", timestamp=date))
65
+
66
+ # Record daily equity
67
+ total_val = self.portfolio.total_value({symbol: current_price})
68
+ equity_curve.append({
69
+ 'date': date,
70
+ 'total_value': total_val,
71
+ 'cash': self.portfolio.cash
72
+ })
73
+
74
+ return pd.DataFrame(equity_curve).set_index('date')
75
+
76
+ def calculate_metrics(self, equity_df: pd.DataFrame) -> Dict[str, float]:
77
+ if equity_df.empty:
78
+ return {}
79
+
80
+ returns = equity_df['total_value'].pct_change().dropna()
81
+ total_return = (equity_df['total_value'].iloc[-1] / self.portfolio.initial_cash) - 1.0
82
+
83
+ ann_vol = returns.std() * (252 ** 0.5) if not returns.empty else 0.0
84
+ sharpe = (returns.mean() * 252) / ann_vol if ann_vol > 0 else 0.0
85
+
86
+ cum_ret = (1 + returns).cumprod()
87
+ peak = cum_ret.cummax()
88
+ drawdown = (cum_ret - peak) / peak
89
+ max_dd = drawdown.min()
90
+
91
+ return {
92
+ "total_return_pct": round(total_return * 100, 2),
93
+ "annualized_volatility_pct": round(ann_vol * 100, 2),
94
+ "sharpe_ratio": round(sharpe, 2),
95
+ "max_drawdown_pct": round(max_dd * 100, 2) if not pd.isna(max_dd) else 0.0
96
+ }
@@ -0,0 +1,13 @@
1
+ # 让本子包也能穿透到私有 Arthera 仓的同名子包。
2
+ # 父层 (packages / quant_engine) 已经做了 __path__ 拼接,但 Python 找到
3
+ # 常规子包后就停止查找,不会继续看父包 __path__ 的其它条目——所以每一层
4
+ # 都得自己声明。规则:aria-code 自带的实现优先,Arthera 补齐缺口。
5
+ # 详见 packages/quant_engine/_namespace.py 的模块文档。
6
+ from .._namespace import extend as _extend_namespace
7
+ _extend_namespace(__path__, "portfolio")
8
+
9
+ """Portfolio optimization engine."""
10
+
11
+ from .optimizer import PortfolioOptimizer
12
+
13
+ __all__ = ["PortfolioOptimizer"]
@@ -0,0 +1,85 @@
1
+ import numpy as np
2
+ import pandas as pd
3
+ from scipy.optimize import minimize
4
+ from typing import Dict, List, Tuple
5
+
6
+ class PortfolioOptimizer:
7
+ """Quantitative Portfolio Optimization Engine"""
8
+
9
+ def __init__(self, risk_free_rate: float = 0.02):
10
+ self.risk_free_rate = risk_free_rate
11
+
12
+ def _get_returns_stats(self, prices_df: pd.DataFrame) -> Tuple[np.ndarray, np.ndarray]:
13
+ returns = prices_df.pct_change().dropna()
14
+ mean_returns = returns.mean().values * 252
15
+ cov_matrix = returns.cov().values * 252
16
+ return mean_returns, cov_matrix
17
+
18
+ def portfolio_performance(self, weights: np.ndarray, mean_returns: np.ndarray, cov_matrix: np.ndarray) -> Tuple[float, float]:
19
+ returns = np.sum(mean_returns * weights)
20
+ std = np.sqrt(np.dot(weights.T, np.dot(cov_matrix, weights)))
21
+ return returns, std
22
+
23
+ def min_variance(self, prices_df: pd.DataFrame) -> Dict[str, float]:
24
+ """Minimize portfolio variance"""
25
+ symbols = prices_df.columns.tolist()
26
+ num_assets = len(symbols)
27
+ _, cov_matrix = self._get_returns_stats(prices_df)
28
+
29
+ args = (cov_matrix,)
30
+ def portfolio_volatility(weights, cov):
31
+ return np.sqrt(np.dot(weights.T, np.dot(cov, weights)))
32
+
33
+ constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1})
34
+ bounds = tuple((0.0, 1.0) for asset in range(num_assets))
35
+ initial_guess = num_assets * [1. / num_assets,]
36
+
37
+ result = minimize(portfolio_volatility, initial_guess, args=args,
38
+ method='SLSQP', bounds=bounds, constraints=constraints)
39
+
40
+ return {sym: round(weight, 4) for sym, weight in zip(symbols, result.x)}
41
+
42
+ def max_sharpe(self, prices_df: pd.DataFrame) -> Dict[str, float]:
43
+ """Maximize Sharpe Ratio"""
44
+ symbols = prices_df.columns.tolist()
45
+ num_assets = len(symbols)
46
+ mean_returns, cov_matrix = self._get_returns_stats(prices_df)
47
+
48
+ def neg_sharpe_ratio(weights, mean_ret, cov, rf_rate):
49
+ p_ret, p_std = self.portfolio_performance(weights, mean_ret, cov)
50
+ return -(p_ret - rf_rate) / p_std
51
+
52
+ args = (mean_returns, cov_matrix, self.risk_free_rate)
53
+ constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1})
54
+ bounds = tuple((0.0, 1.0) for asset in range(num_assets))
55
+ initial_guess = num_assets * [1. / num_assets,]
56
+
57
+ result = minimize(neg_sharpe_ratio, initial_guess, args=args,
58
+ method='SLSQP', bounds=bounds, constraints=constraints)
59
+
60
+ return {sym: round(weight, 4) for sym, weight in zip(symbols, result.x)}
61
+
62
+ def risk_parity(self, prices_df: pd.DataFrame) -> Dict[str, float]:
63
+ """Inverse volatility weighting (naive risk parity)"""
64
+ returns = prices_df.pct_change().dropna()
65
+ volatilities = returns.std() * np.sqrt(252)
66
+ inv_vol = 1.0 / volatilities
67
+ weights = inv_vol / inv_vol.sum()
68
+
69
+ return {sym: round(weights[sym], 4) for sym in prices_df.columns}
70
+
71
+ def combine_agent_signals(self, optimal_weights: Dict[str, float], agent_confidences: Dict[str, float]) -> Dict[str, float]:
72
+ """
73
+ Adjust optimal weights based on Agent confidence.
74
+ For example, if max_sharpe gives AAPL 0.6, but Agent confidence is 0.5,
75
+ we scale it down and keep remaining in cash.
76
+ """
77
+ final_weights = {}
78
+ for sym, w in optimal_weights.items():
79
+ conf = agent_confidences.get(sym, 1.0)
80
+ final_weights[sym] = round(w * conf, 4)
81
+
82
+ cash_weight = round(1.0 - sum(final_weights.values()), 4)
83
+ final_weights['CASH'] = max(0.0, cash_weight)
84
+
85
+ return final_weights