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,513 @@
1
+ """
2
+ data_service.py — unified market data facade
3
+ ============================================
4
+
5
+ This module sits above MarketDataClient and datasources.DataRouter. It returns
6
+ one normalized shape for quotes, history, fundamentals, and technical signals
7
+ so report/backtest code does not need to know provider-specific schemas.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import time
13
+ from dataclasses import asdict, dataclass, field, is_dataclass
14
+ from datetime import datetime, timezone
15
+ from typing import Any, Dict, List, Optional, Tuple
16
+
17
+ try:
18
+ from packages.aria_services.cache import DistributedCacheManager
19
+ except ImportError:
20
+ DistributedCacheManager = None
21
+
22
+ from aria_code.packages.aria_services.provider_health import (
23
+ GLOBAL_PROVIDER_HEALTH,
24
+ ProviderHealthRegistry,
25
+ ProviderIssue,
26
+ classify_provider_error,
27
+ )
28
+
29
+
30
+ def _dedupe(values: List[Any]) -> List[str]:
31
+ return list(dict.fromkeys(str(v) for v in values if v not in (None, "", [], {})))
32
+
33
+
34
+ def _is_present(value: Any) -> bool:
35
+ return value not in (None, "", [], {})
36
+
37
+
38
+ def _to_dict(value: Any) -> Dict[str, Any]:
39
+ if value is None:
40
+ return {}
41
+ if isinstance(value, dict):
42
+ return dict(value)
43
+ if is_dataclass(value):
44
+ return asdict(value)
45
+ if hasattr(value, "to_dict"):
46
+ try:
47
+ return dict(value.to_dict())
48
+ except Exception:
49
+ pass
50
+ if hasattr(value, "__dict__"):
51
+ return dict(value.__dict__)
52
+ return {}
53
+
54
+
55
+ def _provider_chain(data: Dict[str, Any], fallback: str) -> List[str]:
56
+ chain = data.get("provider_chain")
57
+ if isinstance(chain, list):
58
+ return _dedupe(chain)
59
+ return _dedupe([data.get("provider"), data.get("source"), fallback])
60
+
61
+
62
+ def _provider_from_call(method: str, data: Dict[str, Any] | None = None) -> str:
63
+ data = data or {}
64
+ provider = data.get("provider") or data.get("source")
65
+ if provider:
66
+ return str(provider)
67
+ return "market_data_client" if method in {"quote", "history", "fundamentals", "technical_indicators"} else method
68
+
69
+
70
+ def _data_with_success(data: Dict[str, Any], success: bool) -> Dict[str, Any]:
71
+ """Return payload with its embedded success flag matching DataServiceResult."""
72
+ if not data:
73
+ return {}
74
+ out = dict(data)
75
+ out["success"] = bool(success)
76
+ return out
77
+
78
+
79
+ def _utc_now() -> datetime:
80
+ return datetime.now(timezone.utc)
81
+
82
+
83
+ def _utc_timestamp() -> str:
84
+ return _utc_now().isoformat(timespec="seconds").replace("+00:00", "Z")
85
+
86
+
87
+ def _parse_timestamp(value: Any) -> Optional[datetime]:
88
+ if not value:
89
+ return None
90
+ if isinstance(value, datetime):
91
+ return value if value.tzinfo else value.replace(tzinfo=timezone.utc)
92
+ text = str(value).strip()
93
+ if not text:
94
+ return None
95
+ if text.endswith("Z"):
96
+ text = text[:-1] + "+00:00"
97
+ try:
98
+ dt = datetime.fromisoformat(text)
99
+ return dt if dt.tzinfo else dt.replace(tzinfo=timezone.utc)
100
+ except ValueError:
101
+ return None
102
+
103
+
104
+ @dataclass
105
+ class DataServiceResult:
106
+ kind: str
107
+ symbol: str
108
+ success: bool
109
+ data: Dict[str, Any] = field(default_factory=dict)
110
+ provider_chain: List[str] = field(default_factory=list)
111
+ warnings: List[str] = field(default_factory=list)
112
+ errors: List[str] = field(default_factory=list)
113
+ missing_fields: List[str] = field(default_factory=list)
114
+ source: str = ""
115
+ stale: bool = False
116
+ quality: Dict[str, Any] = field(default_factory=dict)
117
+ timestamp: str = field(default_factory=_utc_timestamp)
118
+
119
+
120
+ @dataclass
121
+ class DataBundle:
122
+ symbol: str
123
+ quote: Dict[str, Any] = field(default_factory=dict)
124
+ history: Dict[str, Any] = field(default_factory=dict)
125
+ fundamentals: Dict[str, Any] = field(default_factory=dict)
126
+ technical: Dict[str, Any] = field(default_factory=dict)
127
+ provider_chain: List[str] = field(default_factory=list)
128
+ warnings: List[str] = field(default_factory=list)
129
+ errors: List[str] = field(default_factory=list)
130
+ missing_fields: List[str] = field(default_factory=list)
131
+ quality: Dict[str, Any] = field(default_factory=dict)
132
+ status: str = "data_unavailable"
133
+ timestamp: str = field(default_factory=_utc_timestamp)
134
+
135
+
136
+ class DataService:
137
+ """Unified data entrypoint with cache, fallback, provenance and validation."""
138
+
139
+ def __init__(
140
+ self,
141
+ market_client: Any = None,
142
+ router: Any = None,
143
+ ttl_seconds: int = 60,
144
+ max_quote_age_seconds: int = 900,
145
+ provider_health: ProviderHealthRegistry | None = None,
146
+ ):
147
+ if market_client is None:
148
+ from market_data_client import MarketDataClient
149
+ market_client = MarketDataClient()
150
+ self._router_disabled = router is False
151
+ if self._router_disabled:
152
+ router = None
153
+ if router is None:
154
+ if not self._router_disabled:
155
+ try:
156
+ from datasources.router import get_router
157
+ router = get_router()
158
+ except Exception:
159
+ router = None
160
+ self.market_client = market_client
161
+ self.router = router
162
+ self.ttl_seconds = ttl_seconds
163
+ self.max_quote_age_seconds = max_quote_age_seconds
164
+ self.provider_health = provider_health or GLOBAL_PROVIDER_HEALTH
165
+ import os
166
+ redis_url = os.environ.get("REDIS_URL", None)
167
+ if DistributedCacheManager:
168
+ self._cache_manager = DistributedCacheManager(redis_url=redis_url)
169
+ else:
170
+ self._cache_manager = None
171
+ self._cache: Dict[Tuple[Any, ...], Tuple[float, DataServiceResult]] = {}
172
+ def quote(self, symbol: str) -> DataServiceResult:
173
+ return self._cached(("quote", symbol), lambda: self._quote_uncached(symbol))
174
+
175
+ def history(self, symbol: str, days: int = 370, interval: str = "1d") -> DataServiceResult:
176
+ return self._cached(("history", symbol, days, interval), lambda: self._history_uncached(symbol, days, interval))
177
+
178
+ def fundamentals(self, symbol: str) -> DataServiceResult:
179
+ return self._cached(("fundamentals", symbol), lambda: self._fundamentals_uncached(symbol))
180
+
181
+ def technical_indicators(self, symbol: str, days: int = 120) -> DataServiceResult:
182
+ return self._cached(("technical", symbol, days), lambda: self._technical_uncached(symbol, days))
183
+
184
+ def bundle(self, symbol: str, history_days: int = 370, technical_days: int = 120) -> DataBundle:
185
+ quote = self.quote(symbol)
186
+ history = self.history(symbol, days=history_days)
187
+ fundamentals = self.fundamentals(symbol)
188
+ technical = self.technical_indicators(symbol, days=technical_days)
189
+
190
+ provider_chain = _dedupe(
191
+ quote.provider_chain + history.provider_chain + fundamentals.provider_chain + technical.provider_chain
192
+ )
193
+ warnings = quote.warnings + history.warnings + fundamentals.warnings + technical.warnings
194
+ errors = quote.errors + history.errors + fundamentals.errors + technical.errors
195
+ missing_fields = self._bundle_missing_fields(quote, history, fundamentals, technical)
196
+ stale = quote.stale or history.stale or technical.stale
197
+
198
+ core_success = quote.success and history.success and technical.success
199
+ any_success = quote.success or history.success or fundamentals.success or technical.success
200
+ status = "complete" if core_success and not missing_fields else "partial" if any_success else "data_unavailable"
201
+ if stale and status == "complete":
202
+ status = "stale"
203
+ return DataBundle(
204
+ symbol=symbol,
205
+ quote=quote.data,
206
+ history=history.data,
207
+ fundamentals=fundamentals.data,
208
+ technical=technical.data,
209
+ provider_chain=provider_chain,
210
+ warnings=warnings[:10],
211
+ errors=errors[:10],
212
+ missing_fields=missing_fields,
213
+ quality={
214
+ "status": status,
215
+ "stale": stale,
216
+ "providers": provider_chain,
217
+ "provider_health": self.provider_health.snapshot(),
218
+ "missing_fields": missing_fields,
219
+ "warnings": warnings[:10],
220
+ "errors": errors[:10],
221
+ },
222
+ status=status,
223
+ )
224
+
225
+ def _cached(self, key: Tuple[Any, ...], factory: Any) -> DataServiceResult:
226
+ # Convert tuple key to string for Redis
227
+ str_key = "|".join(str(k) for k in key)
228
+
229
+ if self._cache_manager:
230
+ import json
231
+ cached = self._cache_manager.get(str_key)
232
+ if cached:
233
+ # If cached is dict (from redis json), we might need to cast it back to DataServiceResult
234
+ # For simplicity, if we rely on pickle or raw dict, we assume the factory returns raw or dataclass
235
+ # Since DataServiceResult is a dataclass, we could recreate it or just return it.
236
+ if isinstance(cached, dict):
237
+ return DataServiceResult(**cached)
238
+ return cached
239
+
240
+ result = factory()
241
+ # To cache it in redis, convert dataclass to dict if necessary
242
+ val_to_cache = result.__dict__ if hasattr(result, '__dict__') else result
243
+ self._cache_manager.set(str_key, val_to_cache, self.ttl_seconds)
244
+ return result
245
+ else:
246
+ now = time.time()
247
+ cached = self._cache.get(key)
248
+ if cached and now - cached[0] <= self.ttl_seconds:
249
+ return cached[1]
250
+ result = factory()
251
+ self._cache[key] = (now, result)
252
+ return result
253
+
254
+ def _quote_uncached(self, symbol: str) -> DataServiceResult:
255
+ warnings: List[str] = []
256
+ data = self._call_market("quote", symbol, warnings)
257
+ if not self._valid_quote(data):
258
+ primary = data
259
+ fallback = self._call_router("quote", symbol, warnings)
260
+ data = fallback or primary
261
+ return self._result("quote", symbol, data, warnings, required=["price"], validator=self._valid_quote)
262
+
263
+ def _history_uncached(self, symbol: str, days: int, interval: str) -> DataServiceResult:
264
+ warnings: List[str] = []
265
+ data = self._call_market("history", symbol, warnings, days=days, interval=interval)
266
+ if not self._valid_history(data):
267
+ data = self._call_router("history", symbol, warnings, days=days, interval=interval)
268
+ return self._result("history", symbol, data, warnings, required=["data"], validator=self._valid_history)
269
+
270
+ def _fundamentals_uncached(self, symbol: str) -> DataServiceResult:
271
+ warnings: List[str] = []
272
+ data = self._call_market("fundamentals", symbol, warnings)
273
+ if not self._valid_payload(data):
274
+ data = self._call_router("fundamentals", symbol, warnings)
275
+ return self._result("fundamentals", symbol, data, warnings, required=[])
276
+
277
+ def _technical_uncached(self, symbol: str, days: int) -> DataServiceResult:
278
+ warnings: List[str] = []
279
+ data = self._call_market("technical_indicators", symbol, warnings, days=days)
280
+
281
+ # Yahoo Finance v8 fallback — for US symbols when primary TA source is rate-limited
282
+ # or returns insufficient data (newly-listed stocks, ETFs without MDC coverage)
283
+ _sym = symbol.upper().strip()
284
+ _is_us = not (_sym.endswith((".SZ", ".SS", ".SH", ".HK")) or _sym.isdigit())
285
+ _needs_fallback = _is_us and (
286
+ not data or
287
+ data.get("success") is False or
288
+ (data.get("success") and data.get("rsi") is None)
289
+ )
290
+ if _needs_fallback:
291
+ try:
292
+ import json as _jv8
293
+ import urllib.request as _uv8
294
+ import statistics as _sv8
295
+ _url = (
296
+ f"https://query1.finance.yahoo.com/v8/finance/chart/{_sym}"
297
+ "?interval=1d&range=6mo"
298
+ )
299
+ _req = _uv8.Request(_url, headers={
300
+ "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
301
+ "Accept": "application/json",
302
+ })
303
+ with _uv8.urlopen(_req, timeout=10) as _r:
304
+ _raw = _jv8.loads(_r.read())
305
+ _res = _raw["chart"]["result"][0]
306
+ _q = _res["indicators"]["quote"][0]
307
+ _c = [x for x in _q.get("close", []) if x is not None]
308
+ _v = [x for x in _q.get("volume", []) if x is not None]
309
+ if len(_c) >= 14:
310
+ def _ema(p, n):
311
+ k, r = 2/(n+1), [p[0]]
312
+ for x in p[1:]: r.append(x*k + r[-1]*(1-k))
313
+ return r
314
+ _d = [_c[i]-_c[i-1] for i in range(1, len(_c))]
315
+ _g = [max(x,0) for x in _d]; _l = [max(-x,0) for x in _d]
316
+ _ag = sum(_g[:14])/14; _al = sum(_l[:14])/14
317
+ for i in range(14, len(_g)):
318
+ _ag = (_ag*13+_g[i])/14; _al = (_al*13+_l[i])/14
319
+ _rsi = (100 - 100/(1+_ag/_al)) if _al else 100.0
320
+ n = len(_c)
321
+ _ma20 = sum(_c[-20:])/min(20, n)
322
+ _ma60 = sum(_c[-60:])/min(60, n) if n >= 14 else _ma20
323
+ _std = _sv8.stdev(_c[-min(20,n):]) if n >= 2 else 0
324
+ _v8_data: Dict[str, Any] = {
325
+ "success": True,
326
+ "price": round(_c[-1], 2),
327
+ "rsi": round(_rsi, 2),
328
+ "ma20": round(_ma20, 2),
329
+ "ma60": round(_ma60, 2),
330
+ "bb_upper": round(_ma20 + 2*_std, 2),
331
+ "bb_mid": round(_ma20, 2),
332
+ "bb_lower": round(_ma20 - 2*_std, 2),
333
+ "provider": "yahoo_v8",
334
+ "history_bars": n,
335
+ }
336
+ if n >= 26:
337
+ _e12 = _ema(_c, 12); _e26 = _ema(_c, 26)
338
+ _md = [a-b for a,b in zip(_e12, _e26)]
339
+ _sg = _ema(_md, 9)
340
+ _v8_data["macd"] = round(_md[-1], 4)
341
+ _v8_data["macd_signal"] = round(_sg[-1], 4)
342
+ _v8_data["macd_hist"] = round(_md[-1]-_sg[-1], 4)
343
+ if _v:
344
+ _v8_data["volume"] = int(_v[-1])
345
+ data = _v8_data
346
+ warnings.append(f"yahoo_v8 fallback ({n} bars)")
347
+ elif len(_c) > 0:
348
+ # Too few bars for TA — still surface current price and bar count
349
+ data = {
350
+ "success": False,
351
+ "price": round(_c[-1], 2),
352
+ "history_bars": len(_c),
353
+ "provider": "yahoo_v8",
354
+ }
355
+ if _v:
356
+ data["volume"] = int(_v[-1])
357
+ _bar_str = f"{len(_c)} 个交易日"
358
+ warnings.append(f"数据不足(仅 {_bar_str})— 新上市标的,TA 指标需至少 14 日历史")
359
+ except Exception:
360
+ pass
361
+
362
+ return self._result("technical", symbol, data, warnings, required=["rsi", "macd", "ma20"])
363
+
364
+ def _call_market(self, method: str, symbol: str, warnings: List[str], **kwargs: Any) -> Dict[str, Any]:
365
+ try:
366
+ fn = getattr(self.market_client, method)
367
+ data = _to_dict(fn(symbol, **kwargs))
368
+ provider = _provider_from_call(method, data)
369
+ if data.get("success") is False:
370
+ issue = classify_provider_error(provider, data.get("error") or "unavailable")
371
+ self.provider_health.mark_issue(issue)
372
+ warnings.append(self._format_issue(method, issue))
373
+ elif data:
374
+ self.provider_health.mark_success(provider)
375
+ return data
376
+ except Exception as exc:
377
+ issue = classify_provider_error("market_data_client", exc)
378
+ self.provider_health.mark_issue(issue)
379
+ warnings.append(self._format_issue(method, issue))
380
+ return {}
381
+
382
+ def _call_router(self, method: str, symbol: str, warnings: List[str], **kwargs: Any) -> Dict[str, Any]:
383
+ if self._router_disabled:
384
+ return {}
385
+ if self.router is None:
386
+ issue = classify_provider_error("data_router", "router unavailable")
387
+ self.provider_health.mark_issue(issue)
388
+ warnings.append(self._format_issue(method, issue))
389
+ return {}
390
+ try:
391
+ fn = getattr(self.router, method)
392
+ data = _to_dict(fn(symbol, **kwargs))
393
+ if data:
394
+ data.setdefault("success", True)
395
+ data.setdefault("provider", data.get("source") or f"data_router.{method}")
396
+ data.setdefault("provider_chain", _dedupe([data.get("provider"), data.get("source")]))
397
+ self.provider_health.mark_success(str(data.get("provider")))
398
+ return data
399
+ except Exception as exc:
400
+ issue = classify_provider_error("data_router", exc)
401
+ self.provider_health.mark_issue(issue)
402
+ warnings.append(self._format_issue(method, issue))
403
+ return {}
404
+
405
+ @staticmethod
406
+ def _format_issue(method: str, issue: ProviderIssue) -> str:
407
+ return f"{issue.provider}.{method}: {issue.category} — {issue.message}"
408
+
409
+ def _result(
410
+ self,
411
+ kind: str,
412
+ symbol: str,
413
+ data: Dict[str, Any],
414
+ warnings: List[str],
415
+ required: List[str],
416
+ validator: Any = None,
417
+ ) -> DataServiceResult:
418
+ validator = validator or self._valid_payload
419
+ success = validator(data)
420
+ missing = [key for key in required if not _is_present(data.get(key))]
421
+ if kind == "quote" and "price" in required and not self._valid_quote(data):
422
+ if "price" not in missing:
423
+ missing.append("price")
424
+ if data.get("success") is False:
425
+ success = False
426
+ payload = _data_with_success(data, success)
427
+ source = str(data.get("provider") or data.get("source") or "")
428
+ payload_ts = data.get("timestamp") or data.get("asof") or data.get("as_of")
429
+ timestamp = str(payload_ts or _utc_timestamp())
430
+ stale = self._is_stale(kind, payload_ts)
431
+ errors = []
432
+ if data.get("error"):
433
+ errors.append(str(data.get("error")))
434
+ status = "ok" if success and not missing and not stale else (
435
+ "stale" if success and stale else "partial" if success else "unavailable"
436
+ )
437
+ return DataServiceResult(
438
+ kind=kind,
439
+ symbol=symbol,
440
+ success=success,
441
+ data=payload if payload else {},
442
+ provider_chain=_provider_chain(data, kind) if data else [],
443
+ warnings=warnings[:5],
444
+ errors=errors[:5],
445
+ missing_fields=missing,
446
+ source=source,
447
+ stale=stale,
448
+ quality={
449
+ "status": status,
450
+ "stale": stale,
451
+ "source": source,
452
+ "providers": _provider_chain(data, kind) if data else [],
453
+ "provider_health": self.provider_health.snapshot(),
454
+ "missing_fields": missing,
455
+ "warnings": warnings[:5],
456
+ "errors": errors[:5],
457
+ },
458
+ timestamp=timestamp,
459
+ )
460
+
461
+ def _is_stale(self, kind: str, timestamp: Any) -> bool:
462
+ if kind != "quote":
463
+ return False
464
+ dt = _parse_timestamp(timestamp)
465
+ if dt is None:
466
+ return False
467
+ return (_utc_now() - dt).total_seconds() > self.max_quote_age_seconds
468
+
469
+ @staticmethod
470
+ def _valid_payload(data: Dict[str, Any]) -> bool:
471
+ return bool(data) and data.get("success") is not False
472
+
473
+ @staticmethod
474
+ def _valid_quote(data: Dict[str, Any]) -> bool:
475
+ if not data or data.get("success") is False:
476
+ return False
477
+ price = data.get("price")
478
+ try:
479
+ return price is not None and float(price) > 0
480
+ except (TypeError, ValueError):
481
+ return False
482
+
483
+ @staticmethod
484
+ def _valid_history(data: Dict[str, Any]) -> bool:
485
+ if not data or data.get("success") is False:
486
+ return False
487
+ rows = data.get("data")
488
+ try:
489
+ return rows is not None and len(rows) > 0
490
+ except TypeError:
491
+ return False
492
+
493
+ @staticmethod
494
+ def _bundle_missing_fields(
495
+ quote: DataServiceResult,
496
+ history: DataServiceResult,
497
+ fundamentals: DataServiceResult,
498
+ technical: DataServiceResult,
499
+ ) -> List[str]:
500
+ missing: List[str] = []
501
+ if not quote.success or not _is_present(quote.data.get("price")):
502
+ missing.append("price")
503
+ if not history.success:
504
+ missing.append("history")
505
+ for key in ("pe_ratio", "pe_ttm", "pb_ratio", "pb", "roe"):
506
+ if _is_present(fundamentals.data.get(key)):
507
+ break
508
+ else:
509
+ missing.append("fundamentals")
510
+ for key in ("rsi", "macd", "ma20"):
511
+ if not _is_present(technical.data.get(key)):
512
+ missing.append(key)
513
+ return _dedupe(missing)
@@ -0,0 +1,23 @@
1
+ """
2
+ datasources/ — Aria Code 统一市场数据层
3
+ ========================================
4
+ 用户在 ~/.aria/datasources.yaml 配置数据源优先级,
5
+ 路由器按序尝试,首个成功的结果直接返回。
6
+
7
+ 支持市场:
8
+ A股 → akshare / tushare / eastmoney
9
+ 美股 → yfinance / polygon / finnhub / alphavantage
10
+ 加密 → ccxt (binance/okx) / yfinance
11
+ 基本面 → tushare / yfinance
12
+
13
+ 快速使用:
14
+ from datasources.router import DataRouter
15
+ router = DataRouter()
16
+ print(router.quote("AAPL"))
17
+ print(router.quote("000001")) # A股
18
+ print(router.quote("BTC/USDT")) # 加密
19
+ """
20
+
21
+ from .router import DataRouter, get_router
22
+
23
+ __all__ = ["DataRouter", "get_router"]