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.
- aria_bots/__init__.py +7 -0
- aria_bots/channels/README.md +97 -0
- aria_bots/channels/__init__.py +1 -0
- aria_bots/channels/approvals.py +263 -0
- aria_bots/channels/conversation.py +280 -0
- aria_bots/channels/digest.py +186 -0
- aria_bots/channels/registry.py +95 -0
- aria_bots/engine.py +144 -0
- aria_bots/feishu_bot.py +1385 -0
- aria_bots/logistics/__init__.py +1 -0
- aria_bots/logistics/carriers.py +253 -0
- aria_bots/logistics/freight.py +154 -0
- aria_bots/logistics/inventory.py +242 -0
- aria_bots/logistics/mcp_server.py +156 -0
- aria_bots/logistics/records.py +119 -0
- aria_bots/logistics/tenancy.py +152 -0
- aria_bots/market.py +91 -0
- aria_bots/relay_client.py +326 -0
- aria_bots/telegram_bot.py +299 -0
- aria_code/__init__.py +111 -0
- aria_code/_bin/aria-native.exe +0 -0
- aria_code/_bin/aria-runtime.exe +0 -0
- aria_code/_version.py +20 -0
- aria_code/account_memory.py +296 -0
- aria_code/account_session.py +166 -0
- aria_code/adk_apps/__init__.py +1 -0
- aria_code/adk_apps/aria_code_review/__init__.py +1 -0
- aria_code/adk_apps/aria_code_review/agent.py +32 -0
- aria_code/adk_apps/aria_research/__init__.py +1 -0
- aria_code/adk_apps/aria_research/agent.py +31 -0
- aria_code/agents/__init__.py +49 -0
- aria_code/agents/base.py +329 -0
- aria_code/agents/code_review.py +200 -0
- aria_code/agents/deep/__init__.py +37 -0
- aria_code/agents/deep/calibration_loop.py +144 -0
- aria_code/agents/deep/critic.py +125 -0
- aria_code/agents/deep/deepen.py +193 -0
- aria_code/agents/deep/models.py +149 -0
- aria_code/agents/deep/pipeline.py +164 -0
- aria_code/agents/deep/quant_fusion.py +192 -0
- aria_code/agents/deep/themes.py +95 -0
- aria_code/agents/deep/tiers.py +106 -0
- aria_code/agents/engineering/__init__.py +14 -0
- aria_code/agents/engineering/coder.py +222 -0
- aria_code/agents/engineering/tester.py +145 -0
- aria_code/agents/financial/__init__.py +21 -0
- aria_code/agents/financial/cashflow_burn.py +119 -0
- aria_code/agents/financial/catalyst.py +279 -0
- aria_code/agents/financial/corporate_finance.py +175 -0
- aria_code/agents/financial/debate.py +224 -0
- aria_code/agents/financial/earnings.py +315 -0
- aria_code/agents/financial/fundamental.py +178 -0
- aria_code/agents/financial/macro.py +111 -0
- aria_code/agents/financial/news.py +231 -0
- aria_code/agents/financial/risk.py +146 -0
- aria_code/agents/financial/sector.py +279 -0
- aria_code/agents/financial/strategist.py +121 -0
- aria_code/agents/financial/stripe_revenue.py +127 -0
- aria_code/agents/financial/synthesis.py +274 -0
- aria_code/agents/financial/technical.py +277 -0
- aria_code/agents/orchestrator.py +44 -0
- aria_code/agents/portfolio_agent.py +392 -0
- aria_code/agents/realty/__init__.py +62 -0
- aria_code/agents/realty/asset_diagnosis.py +152 -0
- aria_code/agents/realty/business_match.py +166 -0
- aria_code/agents/realty/cashflow_verify.py +209 -0
- aria_code/agents/realty/contract_rules.py +210 -0
- aria_code/agents/realty/energy_anomaly.py +189 -0
- aria_code/agents/realty/exit_settlement.py +208 -0
- aria_code/agents/realty/fulfillment_risk.py +206 -0
- aria_code/agents/realty/ops_optimize.py +160 -0
- aria_code/agents/realty/revenue_share.py +215 -0
- aria_code/agents/registry.py +168 -0
- aria_code/agents/signal_scheme.py +111 -0
- aria_code/agents/sports/__init__.py +0 -0
- aria_code/agents/sports/football_agent.py +197 -0
- aria_code/agents/supervisor.py +113 -0
- aria_code/agents/team.py +500 -0
- aria_code/agents/video/__init__.py +16 -0
- aria_code/agents/video/director.py +376 -0
- aria_code/agents/video/qa_agent.py +143 -0
- aria_code/agents/video/script_doctor.py +112 -0
- aria_code/agents/warehouse/__init__.py +25 -0
- aria_code/agents/warehouse/contracts.py +26 -0
- aria_code/agents/warehouse/dashboard.py +155 -0
- aria_code/agents/warehouse/fulfillment_leadtime.py +95 -0
- aria_code/agents/warehouse/inbound_exceptions.py +25 -0
- aria_code/agents/warehouse/inventory_health.py +24 -0
- aria_code/agents/warehouse/local_run.py +71 -0
- aria_code/agents/warehouse/local_snapshot.py +132 -0
- aria_code/agents/warehouse/logistics_cost.py +84 -0
- aria_code/agents/warehouse/logistics_sync.py +21 -0
- aria_code/agents/warehouse/navigation.schema.json +110 -0
- aria_code/agents/warehouse/task_agent.py +172 -0
- aria_code/agents/warehouse/workflow.py +31 -0
- aria_code/aliyun_data_client.py +4 -0
- aria_code/apps/README.md +12 -0
- aria_code/apps/__init__.py +2 -0
- aria_code/apps/channels/README.md +9 -0
- aria_code/apps/channels/__init__.py +17 -0
- aria_code/apps/channels/approvals.py +11 -0
- aria_code/apps/channels/conversation.py +11 -0
- aria_code/apps/channels/digest.py +11 -0
- aria_code/apps/channels/intake.py +92 -0
- aria_code/apps/channels/registry.py +11 -0
- aria_code/apps/channels/tradingview.py +94 -0
- aria_code/apps/cli/README.md +13 -0
- aria_code/apps/cli/__init__.py +2 -0
- aria_code/apps/cli/_optional.py +120 -0
- aria_code/apps/cli/app_server.py +656 -0
- aria_code/apps/cli/auto_update.py +125 -0
- aria_code/apps/cli/bootstrap.py +206 -0
- aria_code/apps/cli/broker_render.py +206 -0
- aria_code/apps/cli/chat_turn.py +1327 -0
- aria_code/apps/cli/cloud_models.py +231 -0
- aria_code/apps/cli/codegen_paths.py +29 -0
- aria_code/apps/cli/commands/__init__.py +34 -0
- aria_code/apps/cli/commands/_business_render.py +78 -0
- aria_code/apps/cli/commands/_ui.py +71 -0
- aria_code/apps/cli/commands/analysis_cmds.py +378 -0
- aria_code/apps/cli/commands/ashare_prediction_cmds.py +327 -0
- aria_code/apps/cli/commands/auth_cmds.py +215 -0
- aria_code/apps/cli/commands/backtest_cmds.py +2518 -0
- aria_code/apps/cli/commands/broker_cmds.py +1236 -0
- aria_code/apps/cli/commands/business_workflow_cmds.py +379 -0
- aria_code/apps/cli/commands/canvas_cmds.py +77 -0
- aria_code/apps/cli/commands/catalog.py +189 -0
- aria_code/apps/cli/commands/core_cmds.py +2748 -0
- aria_code/apps/cli/commands/data_cmds.py +521 -0
- aria_code/apps/cli/commands/diagnostic_cmds.py +285 -0
- aria_code/apps/cli/commands/diagnostic_ops_cmds.py +813 -0
- aria_code/apps/cli/commands/engineering_cmds.py +399 -0
- aria_code/apps/cli/commands/file_cmds.py +312 -0
- aria_code/apps/cli/commands/finance_service_cmds.py +60 -0
- aria_code/apps/cli/commands/fx_commodity_cmds.py +123 -0
- aria_code/apps/cli/commands/market.py +544 -0
- aria_code/apps/cli/commands/market_cmds.py +1419 -0
- aria_code/apps/cli/commands/market_context.py +432 -0
- aria_code/apps/cli/commands/market_render.py +7 -0
- aria_code/apps/cli/commands/model_cmds.py +2374 -0
- aria_code/apps/cli/commands/ops_cmds.py +721 -0
- aria_code/apps/cli/commands/orchestrator_cmds.py +181 -0
- aria_code/apps/cli/commands/pdf_export_cmds.py +125 -0
- aria_code/apps/cli/commands/portfolio_cmds.py +1316 -0
- aria_code/apps/cli/commands/report.py +476 -0
- aria_code/apps/cli/commands/scaffold_templates.py +617 -0
- aria_code/apps/cli/commands/session_cmds.py +236 -0
- aria_code/apps/cli/commands/session_ux_cmds.py +359 -0
- aria_code/apps/cli/commands/team.py +723 -0
- aria_code/apps/cli/commands/team_render.py +8 -0
- aria_code/apps/cli/commands/ui_cmds.py +401 -0
- aria_code/apps/cli/commands/warehouse_cmds.py +297 -0
- aria_code/apps/cli/commands/workflow_cmds.py +629 -0
- aria_code/apps/cli/commands/workspace_cmds.py +1543 -0
- aria_code/apps/cli/config_paths.py +73 -0
- aria_code/apps/cli/config_store.py +158 -0
- aria_code/apps/cli/constants.py +88 -0
- aria_code/apps/cli/context.py +34 -0
- aria_code/apps/cli/conversation_policy.py +53 -0
- aria_code/apps/cli/deterministic.py +200 -0
- aria_code/apps/cli/direct.py +48 -0
- aria_code/apps/cli/earnings_view.py +172 -0
- aria_code/apps/cli/endpoint_migration.py +64 -0
- aria_code/apps/cli/exec_events.py +255 -0
- aria_code/apps/cli/file_references.py +155 -0
- aria_code/apps/cli/finance_service_catalog.py +111 -0
- aria_code/apps/cli/football_reports.py +231 -0
- aria_code/apps/cli/github_app_auth.py +135 -0
- aria_code/apps/cli/google_login.py +239 -0
- aria_code/apps/cli/handlers/__init__.py +11 -0
- aria_code/apps/cli/handlers/broker_handlers.py +122 -0
- aria_code/apps/cli/handlers/chart_handlers.py +1314 -0
- aria_code/apps/cli/handlers/market_handlers.py +2570 -0
- aria_code/apps/cli/handlers/realty_handlers.py +114 -0
- aria_code/apps/cli/handlers/sports_handlers.py +22 -0
- aria_code/apps/cli/handlers/strategy_advice.py +82 -0
- aria_code/apps/cli/headless.py +352 -0
- aria_code/apps/cli/helpers.py +326 -0
- aria_code/apps/cli/hooks.py +180 -0
- aria_code/apps/cli/i18n.py +310 -0
- aria_code/apps/cli/intent.py +136 -0
- aria_code/apps/cli/intent_router.py +305 -0
- aria_code/apps/cli/intent_shadow.py +72 -0
- aria_code/apps/cli/intent_signals.py +347 -0
- aria_code/apps/cli/lifecycle_hooks.py +48 -0
- aria_code/apps/cli/local_tool_schemas.py +550 -0
- aria_code/apps/cli/main.py +39 -0
- aria_code/apps/cli/market_hours.py +100 -0
- aria_code/apps/cli/market_metadata.py +135 -0
- aria_code/apps/cli/market_universe.py +487 -0
- aria_code/apps/cli/message_processing.py +310 -0
- aria_code/apps/cli/mixin_binding.py +32 -0
- aria_code/apps/cli/model_catalog.py +652 -0
- aria_code/apps/cli/model_probe.py +169 -0
- aria_code/apps/cli/model_retirement.py +65 -0
- aria_code/apps/cli/native_branding.py +12 -0
- aria_code/apps/cli/native_bridge.py +118 -0
- aria_code/apps/cli/native_entry.py +58 -0
- aria_code/apps/cli/pdf_report.py +977 -0
- aria_code/apps/cli/plan_mode.py +139 -0
- aria_code/apps/cli/plotly_html.py +15 -0
- aria_code/apps/cli/prediction_feedback.py +202 -0
- aria_code/apps/cli/preflight.py +502 -0
- aria_code/apps/cli/project_aria.py +60 -0
- aria_code/apps/cli/prompt_assembly.py +78 -0
- aria_code/apps/cli/prompts/__init__.py +0 -0
- aria_code/apps/cli/prompts/coding.py +71 -0
- aria_code/apps/cli/prompts/select.py +193 -0
- aria_code/apps/cli/prompts/system_prompts.py +562 -0
- aria_code/apps/cli/prompts/ui.py +436 -0
- aria_code/apps/cli/provider_endpoints.py +237 -0
- aria_code/apps/cli/provider_keys.py +73 -0
- aria_code/apps/cli/providers/__init__.py +1 -0
- aria_code/apps/cli/providers/base.py +775 -0
- aria_code/apps/cli/providers/chat_routing.py +139 -0
- aria_code/apps/cli/providers/collaboration.py +98 -0
- aria_code/apps/cli/providers/llm/__init__.py +1 -0
- aria_code/apps/cli/providers/llm/offline_responses.py +68 -0
- aria_code/apps/cli/providers/llm/ollama_stream.py +1574 -0
- aria_code/apps/cli/providers/llm/response_cache.py +60 -0
- aria_code/apps/cli/providers/llm/sse_stream.py +298 -0
- aria_code/apps/cli/providers/runtime_bridge.py +586 -0
- aria_code/apps/cli/providers/vertexai_stream.py +592 -0
- aria_code/apps/cli/release_download.py +159 -0
- aria_code/apps/cli/review_runner.py +111 -0
- aria_code/apps/cli/runtime_consumer.py +769 -0
- aria_code/apps/cli/sandbox.py +32 -0
- aria_code/apps/cli/session_export.py +120 -0
- aria_code/apps/cli/session_jsonl.py +208 -0
- aria_code/apps/cli/session_refresh.py +123 -0
- aria_code/apps/cli/session_store.py +125 -0
- aria_code/apps/cli/skills_catalog.py +273 -0
- aria_code/apps/cli/task_isolation.py +211 -0
- aria_code/apps/cli/terminal_chrome.py +412 -0
- aria_code/apps/cli/todo_tracker.py +190 -0
- aria_code/apps/cli/tool_executor.py +932 -0
- aria_code/apps/cli/tool_registry.py +34 -0
- aria_code/apps/cli/tool_scope.py +113 -0
- aria_code/apps/cli/tools/__init__.py +40 -0
- aria_code/apps/cli/tools/context.py +46 -0
- aria_code/apps/cli/tools/file_tools.py +181 -0
- aria_code/apps/cli/tools/market_tools.py +626 -0
- aria_code/apps/cli/tools/notebook_tools.py +111 -0
- aria_code/apps/cli/tools/system_tools.py +656 -0
- aria_code/apps/cli/tools/write_tools.py +961 -0
- aria_code/apps/cli/tradingview_bridge.py +529 -0
- aria_code/apps/cli/transactions.py +269 -0
- aria_code/apps/cli/turn_planning.py +137 -0
- aria_code/apps/cli/update_check.py +257 -0
- aria_code/apps/cli/updater.py +373 -0
- aria_code/apps/cli/utils/__init__.py +0 -0
- aria_code/apps/cli/utils/market_detect.py +1663 -0
- aria_code/apps/cli/web_login.py +136 -0
- aria_code/apps/cli/workflow_runner.py +127 -0
- aria_code/apps/cli/workspace_route.py +121 -0
- aria_code/apps/daemon/README.md +14 -0
- aria_code/apps/vscode/README.md +115 -0
- aria_code/apps/vscode/package.json +70 -0
- aria_code/aria_cli.py +5244 -0
- aria_code/aria_daemon.py +1372 -0
- aria_code/aria_feishu_bot.py +16 -0
- aria_code/aria_mcp_server.py +61 -0
- aria_code/aria_relay_client.py +4 -0
- aria_code/aria_telegram_bot.py +11 -0
- aria_code/ariarc.py +385 -0
- aria_code/artifacts.py +581 -0
- aria_code/backtest_engine.py +4 -0
- aria_code/backtest_report.py +4 -0
- aria_code/brokers/__init__.py +78 -0
- aria_code/brokers/automation.py +193 -0
- aria_code/brokers/base.py +231 -0
- aria_code/brokers/capabilities.py +264 -0
- aria_code/brokers/cn/__init__.py +10 -0
- aria_code/brokers/cn/easytrader_broker.py +193 -0
- aria_code/brokers/cn/futu_broker.py +194 -0
- aria_code/brokers/cn/longbridge_broker.py +190 -0
- aria_code/brokers/cn/tiger_broker.py +196 -0
- aria_code/brokers/cn/xtquant_broker.py +225 -0
- aria_code/brokers/config.py +414 -0
- aria_code/brokers/intl/__init__.py +5 -0
- aria_code/brokers/intl/alpaca_broker.py +183 -0
- aria_code/brokers/intl/ibkr_broker.py +215 -0
- aria_code/brokers/intl/trading212_broker.py +183 -0
- aria_code/brokers/intl/webull_broker.py +156 -0
- aria_code/brokers/paper_broker.py +266 -0
- aria_code/brokers/planning.py +296 -0
- aria_code/brokers/registry.py +213 -0
- aria_code/brokers/trading.py +267 -0
- aria_code/canva_client.py +4 -0
- aria_code/change_store.py +127 -0
- aria_code/clients/__init__.py +0 -0
- aria_code/clients/aliyun_data_client.py +660 -0
- aria_code/clients/aria_relay_client.py +16 -0
- aria_code/clients/canva_client.py +284 -0
- aria_code/clients/figma_client.py +100 -0
- aria_code/clients/football_data_client.py +1671 -0
- aria_code/clients/kling_video_client.py +182 -0
- aria_code/clients/market_data_client.py +1985 -0
- aria_code/clients/openai_image_client.py +242 -0
- aria_code/clients/runway_video_client.py +157 -0
- aria_code/clients/warehouse_erp_client.py +105 -0
- aria_code/cloud_memory.py +190 -0
- aria_code/command_safety.py +19 -0
- aria_code/computer_use_server.py +276 -0
- aria_code/computer_use_tools.py +4 -0
- aria_code/dashboard_generator.py +579 -0
- aria_code/data_analysis_tools.py +4 -0
- aria_code/data_cleaner.py +483 -0
- aria_code/data_service.py +513 -0
- aria_code/datasources/__init__.py +23 -0
- aria_code/datasources/base.py +166 -0
- aria_code/datasources/router.py +253 -0
- aria_code/datasources/sec_statements.py +217 -0
- aria_code/datasources/sources/__init__.py +15 -0
- aria_code/datasources/sources/akshare_source.py +269 -0
- aria_code/datasources/sources/alpha_vantage_source.py +203 -0
- aria_code/datasources/sources/edgar_source.py +219 -0
- aria_code/datasources/sources/finnhub_source.py +198 -0
- aria_code/datasources/sources/fred_source.py +223 -0
- aria_code/datasources/sources/tushare_source.py +143 -0
- aria_code/datasources/sources/web_scraper_source.py +278 -0
- aria_code/datasources/sources/world_bank_source.py +206 -0
- aria_code/datasources/sources/yfinance_source.py +152 -0
- aria_code/doctor.py +860 -0
- aria_code/domain/__init__.py +0 -0
- aria_code/domain/_finance_core/__init__.py +5 -0
- aria_code/domain/_finance_core/backtest_engine.py +325 -0
- aria_code/domain/_finance_core/performance_stats.py +101 -0
- aria_code/domain/backtest_engine.py +75 -0
- aria_code/domain/backtest_report.py +488 -0
- aria_code/domain/finance_formulas.py +389 -0
- aria_code/domain/performance_stats.py +6 -0
- aria_code/domain/portfolio_ledger.py +307 -0
- aria_code/domain/strategy_vault.py +421 -0
- aria_code/evals/__init__.py +37 -0
- aria_code/evals/behavior.py +113 -0
- aria_code/evals/gap.py +93 -0
- aria_code/evals/harness.py +949 -0
- aria_code/evals/review_probe.py +132 -0
- aria_code/evals/runner.py +425 -0
- aria_code/evals/scorecard.py +322 -0
- aria_code/evals/summary.py +125 -0
- aria_code/external_agent_runner.py +115 -0
- aria_code/figma_client.py +4 -0
- aria_code/file_analysis_tools.py +4 -0
- aria_code/finance_formulas.py +4 -0
- aria_code/football_data_client.py +4 -0
- aria_code/image_gen_tools.py +4 -0
- aria_code/intent_classifier.py +459 -0
- aria_code/kling_video_client.py +4 -0
- aria_code/licensing.py +151 -0
- aria_code/local_finance_tools.py +4 -0
- aria_code/local_image_provider.py +4 -0
- aria_code/local_llm_provider.py +4 -0
- aria_code/macro_tools.py +4 -0
- aria_code/markdown_pdf.py +289 -0
- aria_code/market_data_client.py +4 -0
- aria_code/mcp_client.py +744 -0
- aria_code/memory_manager.py +273 -0
- aria_code/model_capability.py +512 -0
- aria_code/notification_tools.py +4 -0
- aria_code/openai_image_client.py +4 -0
- aria_code/packages/__init__.py +26 -0
- aria_code/packages/adk_bridge/__init__.py +11 -0
- aria_code/packages/adk_bridge/code_review_tools.py +49 -0
- aria_code/packages/adk_bridge/market_tools.py +125 -0
- aria_code/packages/aria_agents/__init__.py +5 -0
- aria_code/packages/aria_agents/manifest.py +78 -0
- aria_code/packages/aria_core/__init__.py +34 -0
- aria_code/packages/aria_core/architecture.py +269 -0
- aria_code/packages/aria_core/export.py +147 -0
- aria_code/packages/aria_core/manifest.py +65 -0
- aria_code/packages/aria_core/paths.py +57 -0
- aria_code/packages/aria_core/secure_file.py +68 -0
- aria_code/packages/aria_infra/__init__.py +15 -0
- aria_code/packages/aria_infra/arthera.py +58 -0
- aria_code/packages/aria_infra/doctor.py +246 -0
- aria_code/packages/aria_infra/product.py +40 -0
- aria_code/packages/aria_mcp/__init__.py +25 -0
- aria_code/packages/aria_mcp/bridge.py +232 -0
- aria_code/packages/aria_mcp/circuit.py +82 -0
- aria_code/packages/aria_mcp/config.py +162 -0
- aria_code/packages/aria_mcp/installer.py +95 -0
- aria_code/packages/aria_mcp/server.py +1705 -0
- aria_code/packages/aria_mcp/tools.py +81 -0
- aria_code/packages/aria_sdk/__init__.py +19 -0
- aria_code/packages/aria_sdk/client.py +393 -0
- aria_code/packages/aria_sdk/providers.py +70 -0
- aria_code/packages/aria_sdk/streaming.py +75 -0
- aria_code/packages/aria_sdk/types.py +86 -0
- aria_code/packages/aria_services/__init__.py +92 -0
- aria_code/packages/aria_services/cache.py +60 -0
- aria_code/packages/aria_services/context.py +356 -0
- aria_code/packages/aria_services/context_checkpoints.py +157 -0
- aria_code/packages/aria_services/data.py +11 -0
- aria_code/packages/aria_services/provider_health.py +304 -0
- aria_code/packages/aria_services/references.py +247 -0
- aria_code/packages/aria_services/registry.py +249 -0
- aria_code/packages/aria_services/research_protocol.py +137 -0
- aria_code/packages/aria_services/research_quality.py +186 -0
- aria_code/packages/aria_services/settings.py +160 -0
- aria_code/packages/aria_services/usage.py +151 -0
- aria_code/packages/aria_skills/__init__.py +46 -0
- aria_code/packages/aria_skills/catalog.py +149 -0
- aria_code/packages/aria_skills/loader.py +455 -0
- aria_code/packages/aria_skills/registry.py +84 -0
- aria_code/packages/aria_tools/__init__.py +5 -0
- aria_code/packages/aria_tools/financial/__init__.py +5 -0
- aria_code/packages/aria_tools/financial/_paths.py +92 -0
- aria_code/packages/aria_tools/registry.py +129 -0
- aria_code/packages/quant_engine/__init__.py +33 -0
- aria_code/packages/quant_engine/_namespace.py +24 -0
- aria_code/packages/quant_engine/backtest/__init__.py +10 -0
- aria_code/packages/quant_engine/backtest/core.py +53 -0
- aria_code/packages/quant_engine/backtest/engine.py +102 -0
- aria_code/packages/quant_engine/portfolio/__init__.py +9 -0
- aria_code/packages/quant_engine/portfolio/optimizer.py +85 -0
- aria_code/packages/quant_engine/sports/__init__.py +76 -0
- aria_code/packages/quant_engine/sports/calibrator.py +354 -0
- aria_code/packages/quant_engine/sports/dixon_coles.py +234 -0
- aria_code/packages/quant_engine/sports/elo.py +300 -0
- aria_code/packages/quant_engine/sports/form.py +188 -0
- aria_code/packages/quant_engine/sports/h2h.py +195 -0
- aria_code/packages/quant_engine/sports/predictor.py +312 -0
- aria_code/packages/quant_engine/sports/tracker.py +665 -0
- aria_code/packages/quant_engine/stochastic/__init__.py +31 -0
- aria_code/packages/quant_engine/stochastic/gbm_enhanced.py +195 -0
- aria_code/packages/quant_engine/stochastic/ito_calculus.py +477 -0
- aria_code/packages/quant_engine/stochastic/kelly_criterion.py +181 -0
- aria_code/packages/quant_engine/stochastic/monte_carlo_advanced.py +95 -0
- aria_code/packages/quant_engine/stochastic/options_pricing.py +576 -0
- aria_code/packages/quant_engine/stochastic/stochastic_processes.py +90 -0
- aria_code/packs/__init__.py +85 -0
- aria_code/packs/base.py +168 -0
- aria_code/packs/finance/__init__.py +250 -0
- aria_code/packs/healthcare/__init__.py +40 -0
- aria_code/packs/logistics/__init__.py +171 -0
- aria_code/packs/payments/__init__.py +139 -0
- aria_code/packs/realty/__init__.py +190 -0
- aria_code/packs/registry.py +202 -0
- aria_code/packs/rules.py +90 -0
- aria_code/plan_utils.py +194 -0
- aria_code/plugin_loader.py +328 -0
- aria_code/portfolio_ledger.py +4 -0
- aria_code/preview_server.py +449 -0
- aria_code/privacy/__init__.py +5 -0
- aria_code/privacy/feedback.py +123 -0
- aria_code/project_review.py +278 -0
- aria_code/project_review_api.py +235 -0
- aria_code/project_review_server.py +18 -0
- aria_code/project_tools.py +4 -0
- aria_code/providers/__init__.py +30 -0
- aria_code/providers/google_video_provider.py +256 -0
- aria_code/providers/llm/__init__.py +19 -0
- aria_code/providers/llm/anthropic.py +184 -0
- aria_code/providers/llm/arthera_gateway.py +90 -0
- aria_code/providers/llm/autoconfig.py +213 -0
- aria_code/providers/llm/base.py +139 -0
- aria_code/providers/llm/custom.py +158 -0
- aria_code/providers/llm/ollama.py +137 -0
- aria_code/providers/llm/openai_compat.py +350 -0
- aria_code/providers/llm/registry.py +457 -0
- aria_code/providers/local_image_provider.py +202 -0
- aria_code/providers/local_llm_provider.py +549 -0
- aria_code/providers/ollama_models.py +79 -0
- aria_code/providers/openai_params.py +32 -0
- aria_code/providers/tool_messages.py +100 -0
- aria_code/realty_data_tools.py +4 -0
- aria_code/report_exporters.py +150 -0
- aria_code/report_generator.py +1764 -0
- aria_code/review_service.py +497 -0
- aria_code/runtime/__init__.py +176 -0
- aria_code/runtime/acceptance.py +632 -0
- aria_code/runtime/agent_loop.py +1851 -0
- aria_code/runtime/agent_profiles.py +75 -0
- aria_code/runtime/approval.py +71 -0
- aria_code/runtime/baseline.py +219 -0
- aria_code/runtime/budget.py +232 -0
- aria_code/runtime/checkpoints.py +481 -0
- aria_code/runtime/consult.py +65 -0
- aria_code/runtime/contract.py +282 -0
- aria_code/runtime/delivery.py +432 -0
- aria_code/runtime/events.py +113 -0
- aria_code/runtime/gateway.py +167 -0
- aria_code/runtime/lsp.py +484 -0
- aria_code/runtime/native_index.py +153 -0
- aria_code/runtime/orchestrator.py +55 -0
- aria_code/runtime/processes.py +343 -0
- aria_code/runtime/project_graph.py +614 -0
- aria_code/runtime/repo_map.py +712 -0
- aria_code/runtime/research_bundle.py +105 -0
- aria_code/runtime/review.py +269 -0
- aria_code/runtime/run_state.py +127 -0
- aria_code/runtime/run_store.py +522 -0
- aria_code/runtime/scoped_runs.py +113 -0
- aria_code/runtime/self_healing.py +422 -0
- aria_code/runtime/semantic_diff.py +171 -0
- aria_code/runtime/subagent.py +721 -0
- aria_code/runtime/symbol_edit.py +117 -0
- aria_code/runtime/task_brief.py +46 -0
- aria_code/runtime/task_context.py +145 -0
- aria_code/runtime/task_ledger.py +108 -0
- aria_code/runtime/task_orchestrator.py +90 -0
- aria_code/runtime/task_outcome.py +33 -0
- aria_code/runtime/task_verification.py +266 -0
- aria_code/runtime/task_worktree.py +448 -0
- aria_code/runtime/tool_executor.py +329 -0
- aria_code/runtime/tool_policy.py +107 -0
- aria_code/runtime/transactions.py +216 -0
- aria_code/runtime/windows_job.py +115 -0
- aria_code/runtime/workflows.py +222 -0
- aria_code/runtime/worktrees.py +215 -0
- aria_code/runway_video_client.py +4 -0
- aria_code/safety/__init__.py +27 -0
- aria_code/safety/client_isolation.py +178 -0
- aria_code/safety/permissions.py +339 -0
- aria_code/safety/risk.py +699 -0
- aria_code/safety/sandbox.py +148 -0
- aria_code/safety/service.py +102 -0
- aria_code/service_endpoints.py +14 -0
- aria_code/setup_wizard.py +684 -0
- aria_code/spreadsheet_tools.py +4 -0
- aria_code/strategy_vault.py +4 -0
- aria_code/tools/__init__.py +0 -0
- aria_code/tools/artifact_tools.py +252 -0
- aria_code/tools/broker_tools.py +92 -0
- aria_code/tools/build_quant_engine.py +97 -0
- aria_code/tools/code_audit_tools.py +192 -0
- aria_code/tools/computer_use_tools.py +509 -0
- aria_code/tools/data_analysis_tools.py +831 -0
- aria_code/tools/enterprise_finance_tools.py +202 -0
- aria_code/tools/extended_tools.py +240 -0
- aria_code/tools/file_analysis_tools.py +880 -0
- aria_code/tools/image_gen_tools.py +114 -0
- aria_code/tools/local_finance_tools.py +3488 -0
- aria_code/tools/logistics_carriers.py +11 -0
- aria_code/tools/logistics_inventory.py +11 -0
- aria_code/tools/logistics_io.py +11 -0
- aria_code/tools/logistics_tenancy.py +11 -0
- aria_code/tools/logistics_tools.py +11 -0
- aria_code/tools/macro_tools.py +412 -0
- aria_code/tools/notification_tools.py +249 -0
- aria_code/tools/project_tools.py +525 -0
- aria_code/tools/realty_data_tools.py +662 -0
- aria_code/tools/spreadsheet_tools.py +399 -0
- aria_code/tools/stripe_tools.py +115 -0
- aria_code/tools/video_tools.py +500 -0
- aria_code/training/__init__.py +1 -0
- aria_code/training/compare.py +117 -0
- aria_code/training/prelude_commands.py +111 -0
- aria_code/training/prelude_eval.py +390 -0
- aria_code/training/prelude_real.py +183 -0
- aria_code/training/prelude_train.py +248 -0
- aria_code/training/sft_dataset.py +230 -0
- aria_code/training/trajectory_dataset.py +263 -0
- aria_code/ui/__init__.py +105 -0
- aria_code/ui/banner.py +404 -0
- aria_code/ui/completer.py +571 -0
- aria_code/ui/console.py +285 -0
- aria_code/ui/input_box.py +505 -0
- aria_code/ui/mentions.py +206 -0
- aria_code/ui/picker.py +248 -0
- aria_code/ui/render/__init__.py +11 -0
- aria_code/ui/render/actions.py +297 -0
- aria_code/ui/render/finance.py +1732 -0
- aria_code/ui/render/market.py +253 -0
- aria_code/ui/render/output.py +954 -0
- aria_code/ui/render/responsive.py +75 -0
- aria_code/ui/render/team.py +367 -0
- aria_code/ui/robot.py +239 -0
- aria_code/ui/startup_dashboard.py +110 -0
- aria_code/video_analysis.py +147 -0
- aria_code/video_editor.py +518 -0
- aria_code/video_workflow/__init__.py +8 -0
- aria_code/video_workflow/__main__.py +61 -0
- aria_code/video_workflow/engines/__init__.py +18 -0
- aria_code/video_workflow/engines/base.py +69 -0
- aria_code/video_workflow/engines/custom_model.py +204 -0
- aria_code/video_workflow/engines/google_veo.py +94 -0
- aria_code/video_workflow/engines/local_engine.py +71 -0
- aria_code/video_workflow/engines/registry.py +98 -0
- aria_code/video_workflow/google_models.py +278 -0
- aria_code/video_workflow/music/__init__.py +5 -0
- aria_code/video_workflow/music/foley_service.py +132 -0
- aria_code/video_workflow/music/service.py +212 -0
- aria_code/video_workflow/pipeline.py +620 -0
- aria_code/video_workflow/plan.py +202 -0
- aria_code/video_workflow/session.py +297 -0
- aria_code/workspace/__init__.py +6 -0
- aria_code/workspace/files.py +219 -0
- aria_code/workspace/verify.py +167 -0
- aria_code/workspace_changes.py +199 -0
- aria_code/workspace_service.py +196 -0
- aria_code/workspace_tools.py +150 -0
- aria_code-0.167.0.dist-info/METADATA +330 -0
- aria_code-0.167.0.dist-info/RECORD +601 -0
- aria_code-0.167.0.dist-info/WHEEL +5 -0
- aria_code-0.167.0.dist-info/entry_points.txt +5 -0
- aria_code-0.167.0.dist-info/licenses/LICENSE +201 -0
- aria_code-0.167.0.dist-info/licenses/NOTICE +49 -0
- aria_code-0.167.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
"""Market symbol resolution across A-shares, HK, global tickers, FX and futures.
|
|
2
|
+
|
|
3
|
+
The resolver is intentionally cache-first. Static aliases cover common global
|
|
4
|
+
assets and critical names; optional akshare loaders populate full A-share/HK
|
|
5
|
+
name tables into a local cache when available.
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
import json
|
|
11
|
+
import os
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
import re
|
|
14
|
+
import time
|
|
15
|
+
from typing import Callable, Iterable
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass(frozen=True)
|
|
19
|
+
class MarketSymbol:
|
|
20
|
+
name: str
|
|
21
|
+
symbol: str
|
|
22
|
+
market: str
|
|
23
|
+
source: str = "static"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
STATIC_MARKET_ALIASES: dict[str, MarketSymbol] = {
|
|
27
|
+
# A-share fixes and high-frequency names not guaranteed in older static maps
|
|
28
|
+
"斯迪克": MarketSymbol("斯迪克", "300806", "CN", "static"),
|
|
29
|
+
"四环生物": MarketSymbol("四环生物", "000518", "CN", "static"),
|
|
30
|
+
# China / HK indices
|
|
31
|
+
"上证指数": MarketSymbol("上证指数", "000001.SS", "INDEX", "static"),
|
|
32
|
+
"上证": MarketSymbol("上证指数", "000001.SS", "INDEX", "static"),
|
|
33
|
+
"深证成指": MarketSymbol("深证成指", "399001.SZ", "INDEX", "static"),
|
|
34
|
+
"创业板指": MarketSymbol("创业板指", "399006.SZ", "INDEX", "static"),
|
|
35
|
+
"沪深300": MarketSymbol("沪深300", "000300.SS", "INDEX", "static"),
|
|
36
|
+
"中证500": MarketSymbol("中证500", "000905.SS", "INDEX", "static"),
|
|
37
|
+
"恒生指数": MarketSymbol("恒生指数", "^HSI", "INDEX", "static"),
|
|
38
|
+
"恒指": MarketSymbol("恒生指数", "^HSI", "INDEX", "static"),
|
|
39
|
+
# US/global indices
|
|
40
|
+
"标普500": MarketSymbol("标普500", "^GSPC", "INDEX", "static"),
|
|
41
|
+
"标普": MarketSymbol("标普500", "^GSPC", "INDEX", "static"),
|
|
42
|
+
"纳斯达克": MarketSymbol("纳斯达克综合", "^IXIC", "INDEX", "static"),
|
|
43
|
+
"纳指": MarketSymbol("纳斯达克综合", "^IXIC", "INDEX", "static"),
|
|
44
|
+
"道琼斯": MarketSymbol("道琼斯工业指数", "^DJI", "INDEX", "static"),
|
|
45
|
+
"道指": MarketSymbol("道琼斯工业指数", "^DJI", "INDEX", "static"),
|
|
46
|
+
"罗素2000": MarketSymbol("罗素2000", "^RUT", "INDEX", "static"),
|
|
47
|
+
"恐慌指数": MarketSymbol("VIX", "^VIX", "INDEX", "static"),
|
|
48
|
+
"vix": MarketSymbol("VIX", "^VIX", "INDEX", "static"),
|
|
49
|
+
"富时100": MarketSymbol("FTSE 100", "^FTSE", "INDEX", "static"),
|
|
50
|
+
"德国dax": MarketSymbol("DAX", "^GDAXI", "INDEX", "static"),
|
|
51
|
+
"dax": MarketSymbol("DAX", "^GDAXI", "INDEX", "static"),
|
|
52
|
+
"法国cac": MarketSymbol("CAC 40", "^FCHI", "INDEX", "static"),
|
|
53
|
+
"日经225": MarketSymbol("Nikkei 225", "^N225", "INDEX", "static"),
|
|
54
|
+
# Europe equities / brands frequently asked by name rather than ticker.
|
|
55
|
+
"lvmh": MarketSymbol("LVMH Moet Hennessy Louis Vuitton SE", "MC.PA", "EU", "static"),
|
|
56
|
+
"路易威登": MarketSymbol("LVMH Moet Hennessy Louis Vuitton SE", "MC.PA", "EU", "static"),
|
|
57
|
+
"路易斯威登": MarketSymbol("LVMH Moet Hennessy Louis Vuitton SE", "MC.PA", "EU", "static"),
|
|
58
|
+
"louis vuitton": MarketSymbol("LVMH Moet Hennessy Louis Vuitton SE", "MC.PA", "EU", "static"),
|
|
59
|
+
"爱马仕": MarketSymbol("Hermes International SCA", "RMS.PA", "EU", "static"),
|
|
60
|
+
"开云集团": MarketSymbol("Kering SA", "KER.PA", "EU", "static"),
|
|
61
|
+
"古驰": MarketSymbol("Kering SA", "KER.PA", "EU", "static"),
|
|
62
|
+
# Crypto
|
|
63
|
+
"比特币": MarketSymbol("比特币", "BTC-USD", "CRYPTO", "static"),
|
|
64
|
+
"btc": MarketSymbol("Bitcoin", "BTC-USD", "CRYPTO", "static"),
|
|
65
|
+
"以太坊": MarketSymbol("以太坊", "ETH-USD", "CRYPTO", "static"),
|
|
66
|
+
"eth": MarketSymbol("Ethereum", "ETH-USD", "CRYPTO", "static"),
|
|
67
|
+
"狗狗币": MarketSymbol("Dogecoin", "DOGE-USD", "CRYPTO", "static"),
|
|
68
|
+
"sol": MarketSymbol("Solana", "SOL-USD", "CRYPTO", "static"),
|
|
69
|
+
"索拉纳": MarketSymbol("Solana", "SOL-USD", "CRYPTO", "static"),
|
|
70
|
+
# FX
|
|
71
|
+
"美元人民币": MarketSymbol("USD/CNY", "CNY=X", "FX", "static"),
|
|
72
|
+
"人民币汇率": MarketSymbol("USD/CNY", "CNY=X", "FX", "static"),
|
|
73
|
+
"美元兑人民币": MarketSymbol("USD/CNY", "CNY=X", "FX", "static"),
|
|
74
|
+
"美元指数": MarketSymbol("美元指数", "DX-Y.NYB", "FX", "static"),
|
|
75
|
+
"欧元美元": MarketSymbol("EUR/USD", "EURUSD=X", "FX", "static"),
|
|
76
|
+
"欧元兑美元": MarketSymbol("EUR/USD", "EURUSD=X", "FX", "static"),
|
|
77
|
+
"美元日元": MarketSymbol("USD/JPY", "JPY=X", "FX", "static"),
|
|
78
|
+
"英镑美元": MarketSymbol("GBP/USD", "GBPUSD=X", "FX", "static"),
|
|
79
|
+
# Futures / commodities via Yahoo continuous futures
|
|
80
|
+
"黄金": MarketSymbol("黄金期货", "GC=F", "FUTURES", "static"),
|
|
81
|
+
"白银": MarketSymbol("白银期货", "SI=F", "FUTURES", "static"),
|
|
82
|
+
"原油": MarketSymbol("WTI原油期货", "CL=F", "FUTURES", "static"),
|
|
83
|
+
"wti": MarketSymbol("WTI原油期货", "CL=F", "FUTURES", "static"),
|
|
84
|
+
"布伦特": MarketSymbol("布伦特原油期货", "BZ=F", "FUTURES", "static"),
|
|
85
|
+
"铜": MarketSymbol("铜期货", "HG=F", "FUTURES", "static"),
|
|
86
|
+
"天然气": MarketSymbol("天然气期货", "NG=F", "FUTURES", "static"),
|
|
87
|
+
"玉米": MarketSymbol("玉米期货", "ZC=F", "FUTURES", "static"),
|
|
88
|
+
"大豆": MarketSymbol("大豆期货", "ZS=F", "FUTURES", "static"),
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _cache_path() -> Path:
|
|
93
|
+
root = Path(os.getenv("ARIA_CACHE_DIR") or (Path.home() / ".aria" / "cache"))
|
|
94
|
+
return root / "market_universe.json"
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _load_cache(path: Path | None = None, *, max_age_seconds: int = 7 * 86400) -> list[MarketSymbol]:
|
|
98
|
+
path = path or _cache_path()
|
|
99
|
+
try:
|
|
100
|
+
if not path.exists() or time.time() - path.stat().st_mtime > max_age_seconds:
|
|
101
|
+
return []
|
|
102
|
+
payload = json.loads(path.read_text(encoding="utf-8"))
|
|
103
|
+
return [
|
|
104
|
+
MarketSymbol(
|
|
105
|
+
name=str(item.get("name") or ""),
|
|
106
|
+
symbol=str(item.get("symbol") or ""),
|
|
107
|
+
market=str(item.get("market") or ""),
|
|
108
|
+
source=str(item.get("source") or "cache"),
|
|
109
|
+
)
|
|
110
|
+
for item in payload.get("symbols", [])
|
|
111
|
+
if item.get("name") and item.get("symbol")
|
|
112
|
+
]
|
|
113
|
+
except Exception:
|
|
114
|
+
return []
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _write_cache(symbols: Iterable[MarketSymbol], path: Path | None = None) -> None:
|
|
118
|
+
path = path or _cache_path()
|
|
119
|
+
try:
|
|
120
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
121
|
+
data = {
|
|
122
|
+
"updated_at": int(time.time()),
|
|
123
|
+
"symbols": [s.__dict__ for s in symbols if s.name and s.symbol],
|
|
124
|
+
}
|
|
125
|
+
path.write_text(json.dumps(data, ensure_ascii=False), encoding="utf-8")
|
|
126
|
+
except Exception:
|
|
127
|
+
pass
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _iter_static_symbols() -> list[MarketSymbol]:
|
|
131
|
+
seen: set[tuple[str, str]] = set()
|
|
132
|
+
out: list[MarketSymbol] = []
|
|
133
|
+
for item in STATIC_MARKET_ALIASES.values():
|
|
134
|
+
key = (item.name, item.symbol)
|
|
135
|
+
if key not in seen:
|
|
136
|
+
out.append(item)
|
|
137
|
+
seen.add(key)
|
|
138
|
+
return out
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _symbols_from_frame(frame, *, name_cols: tuple[str, ...], code_cols: tuple[str, ...], market: str, source: str) -> list[MarketSymbol]:
|
|
142
|
+
out: list[MarketSymbol] = []
|
|
143
|
+
try:
|
|
144
|
+
columns = {str(c).lower(): c for c in frame.columns}
|
|
145
|
+
name_col = next((columns[c.lower()] for c in name_cols if c.lower() in columns), None)
|
|
146
|
+
code_col = next((columns[c.lower()] for c in code_cols if c.lower() in columns), None)
|
|
147
|
+
if name_col is None or code_col is None:
|
|
148
|
+
return []
|
|
149
|
+
for _, row in frame.iterrows():
|
|
150
|
+
name = str(row.get(name_col, "")).strip()
|
|
151
|
+
code = str(row.get(code_col, "")).strip().upper()
|
|
152
|
+
if not name or not code or code.lower() == "nan":
|
|
153
|
+
continue
|
|
154
|
+
if market == "HK":
|
|
155
|
+
digits = re.sub(r"\D", "", code)
|
|
156
|
+
if digits:
|
|
157
|
+
code = f"{digits.zfill(4)}.HK"
|
|
158
|
+
out.append(MarketSymbol(name, code, market, source))
|
|
159
|
+
except Exception:
|
|
160
|
+
return []
|
|
161
|
+
return out
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def is_offline() -> bool:
|
|
165
|
+
"""True 时跳过一切联网抓取,只用静态符号表。
|
|
166
|
+
|
|
167
|
+
2026-08-19:fetch_market_universe() 会真的打 akshare(stock_info_a_code_name
|
|
168
|
+
与 stock_hk_spot_em),既没有超时也没有开关。CI 上这两个请求会挂住,
|
|
169
|
+
tests/test_aria_cli_core.py::test_send_message_visual_route_helper 因此撞
|
|
170
|
+
pytest-timeout 的 60 秒上限而失败——测的明明是"自然语言路由到 /chart"这种
|
|
171
|
+
纯本地逻辑,答案(Apple→AAPL)来自 market_detect.py 的静态映射,根本不需要
|
|
172
|
+
联网,网络只是扫描全量宇宙时的副作用。
|
|
173
|
+
|
|
174
|
+
默认行为不变(有网就抓)。设 ARIA_OFFLINE=1 即可让它立刻退回静态表,
|
|
175
|
+
供 CI、离线环境和确定性测试使用。
|
|
176
|
+
"""
|
|
177
|
+
return os.getenv("ARIA_OFFLINE", "").strip().lower() in {"1", "true", "yes", "on"}
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def _fetch_timeout_seconds() -> float:
|
|
181
|
+
"""Wall-clock budget for one remote universe fetch.
|
|
182
|
+
|
|
183
|
+
``is_offline()`` documents that these akshare calls had neither a timeout
|
|
184
|
+
nor a switch, so a slow or hanging endpoint stalled the caller
|
|
185
|
+
indefinitely — on the routing hot path that reads as the CLI freezing.
|
|
186
|
+
ARIA_OFFLINE=1 still skips the network entirely; this bounds the wait when
|
|
187
|
+
the network *is* used.
|
|
188
|
+
"""
|
|
189
|
+
try:
|
|
190
|
+
value = float(os.getenv("ARIA_UNIVERSE_FETCH_TIMEOUT", "8") or 8)
|
|
191
|
+
except (TypeError, ValueError):
|
|
192
|
+
return 8.0
|
|
193
|
+
return max(1.0, value)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def _call_with_timeout(fn, timeout: float):
|
|
197
|
+
"""Run *fn* with a wall-clock budget; return None if it overruns.
|
|
198
|
+
|
|
199
|
+
The worker thread is a daemon and is abandoned on timeout — akshare offers
|
|
200
|
+
no cancellation — but the caller is released instead of blocking forever.
|
|
201
|
+
"""
|
|
202
|
+
import concurrent.futures
|
|
203
|
+
|
|
204
|
+
executor = concurrent.futures.ThreadPoolExecutor(max_workers=1)
|
|
205
|
+
try:
|
|
206
|
+
future = executor.submit(fn)
|
|
207
|
+
try:
|
|
208
|
+
return future.result(timeout=timeout)
|
|
209
|
+
except Exception:
|
|
210
|
+
return None
|
|
211
|
+
finally:
|
|
212
|
+
executor.shutdown(wait=False)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def fetch_market_universe() -> list[MarketSymbol]:
|
|
216
|
+
"""Fetch A-share and HK symbol tables when akshare is available."""
|
|
217
|
+
symbols = _iter_static_symbols()
|
|
218
|
+
if is_offline():
|
|
219
|
+
return symbols
|
|
220
|
+
budget = _fetch_timeout_seconds()
|
|
221
|
+
try:
|
|
222
|
+
import akshare as ak
|
|
223
|
+
try:
|
|
224
|
+
a_df = _call_with_timeout(ak.stock_info_a_code_name, budget)
|
|
225
|
+
if a_df is None:
|
|
226
|
+
raise TimeoutError("stock_info_a_code_name timed out")
|
|
227
|
+
symbols.extend(_symbols_from_frame(
|
|
228
|
+
a_df,
|
|
229
|
+
name_cols=("name", "证券简称", "股票简称", "名称"),
|
|
230
|
+
code_cols=("code", "证券代码", "股票代码", "代码"),
|
|
231
|
+
market="CN",
|
|
232
|
+
source="akshare:a_code_name",
|
|
233
|
+
))
|
|
234
|
+
except Exception:
|
|
235
|
+
pass
|
|
236
|
+
try:
|
|
237
|
+
hk_df = _call_with_timeout(ak.stock_hk_spot_em, budget)
|
|
238
|
+
if hk_df is None:
|
|
239
|
+
raise TimeoutError("stock_hk_spot_em timed out")
|
|
240
|
+
symbols.extend(_symbols_from_frame(
|
|
241
|
+
hk_df,
|
|
242
|
+
name_cols=("名称", "股票简称", "name"),
|
|
243
|
+
code_cols=("代码", "code", "股票代码"),
|
|
244
|
+
market="HK",
|
|
245
|
+
source="akshare:hk_spot",
|
|
246
|
+
))
|
|
247
|
+
except Exception:
|
|
248
|
+
pass
|
|
249
|
+
except Exception:
|
|
250
|
+
pass
|
|
251
|
+
|
|
252
|
+
dedup: dict[tuple[str, str], MarketSymbol] = {}
|
|
253
|
+
for item in symbols:
|
|
254
|
+
dedup[(item.name.lower(), item.symbol.upper())] = item
|
|
255
|
+
return list(dedup.values())
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
# Guard against repeating an expensive remote refresh within one process. The
|
|
259
|
+
# fetch pulls the full A-share + HK symbol universe over the network; when it
|
|
260
|
+
# fails or returns nothing, retrying it on the next message just stalls the REPL
|
|
261
|
+
# again for the same result.
|
|
262
|
+
_UNIVERSE_REFRESH_ATTEMPTED = False
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def _universe_refresh_attempted() -> bool:
|
|
266
|
+
return _UNIVERSE_REFRESH_ATTEMPTED
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def _mark_universe_refresh_attempted() -> None:
|
|
270
|
+
global _UNIVERSE_REFRESH_ATTEMPTED
|
|
271
|
+
_UNIVERSE_REFRESH_ATTEMPTED = True
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def reset_universe_refresh_guard() -> None:
|
|
275
|
+
"""Clear the once-per-process refresh guard (tests, explicit /refresh)."""
|
|
276
|
+
global _UNIVERSE_REFRESH_ATTEMPTED
|
|
277
|
+
_UNIVERSE_REFRESH_ATTEMPTED = False
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def ensure_market_universe(*, force: bool = False) -> list[MarketSymbol]:
|
|
281
|
+
cached = [] if force else _load_cache()
|
|
282
|
+
if cached:
|
|
283
|
+
return _iter_static_symbols() + cached
|
|
284
|
+
_mark_universe_refresh_attempted()
|
|
285
|
+
fetched = fetch_market_universe()
|
|
286
|
+
_write_cache(fetched)
|
|
287
|
+
return fetched
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def _find_mention(low_text: str, needle: str) -> int:
|
|
291
|
+
"""Position of *needle* in lowercased text, or -1.
|
|
292
|
+
|
|
293
|
+
ASCII needles must sit on word boundaries — plain substring matching
|
|
294
|
+
turned "whether" into an ETH hit and "gateway" into GE (observed in the
|
|
295
|
+
channels e2e drill). CJK names keep substring semantics: Chinese has no
|
|
296
|
+
word boundaries, which is why find() was used originally.
|
|
297
|
+
"""
|
|
298
|
+
n = str(needle or "").lower()
|
|
299
|
+
if not n:
|
|
300
|
+
return -1
|
|
301
|
+
if re.fullmatch(r"[a-z0-9.\-]+", n):
|
|
302
|
+
m = re.search(rf"(?<![a-z0-9]){re.escape(n)}(?![a-z0-9])", low_text)
|
|
303
|
+
return m.start() if m else -1
|
|
304
|
+
return low_text.find(n)
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def resolve_market_mentions(
|
|
308
|
+
text: str,
|
|
309
|
+
*,
|
|
310
|
+
limit: int = 6,
|
|
311
|
+
load_universe: Callable[[], list[MarketSymbol]] | None = None,
|
|
312
|
+
) -> list[tuple[int, MarketSymbol]]:
|
|
313
|
+
"""Resolve named market assets mentioned in text, preserving positions."""
|
|
314
|
+
if not text:
|
|
315
|
+
return []
|
|
316
|
+
low = text.lower()
|
|
317
|
+
hits: list[tuple[int, MarketSymbol]] = []
|
|
318
|
+
for alias, item in sorted(STATIC_MARKET_ALIASES.items(), key=lambda kv: -len(kv[0])):
|
|
319
|
+
idx = _find_mention(low, alias)
|
|
320
|
+
if idx >= 0:
|
|
321
|
+
hits.append((idx, item))
|
|
322
|
+
|
|
323
|
+
def scan(items: Iterable[MarketSymbol]) -> None:
|
|
324
|
+
for item in sorted(items, key=lambda s: -len(s.name)):
|
|
325
|
+
if not item.name:
|
|
326
|
+
continue
|
|
327
|
+
idx = _find_mention(low, item.name)
|
|
328
|
+
if idx >= 0:
|
|
329
|
+
hits.append((idx, item))
|
|
330
|
+
|
|
331
|
+
if load_universe is not None:
|
|
332
|
+
scan(load_universe())
|
|
333
|
+
else:
|
|
334
|
+
scan(_load_cache())
|
|
335
|
+
market_words = "走势|预测|股价|股票|行情|趋势|技术面|基本面|涨跌|价格|市值|k线|图表|财报"
|
|
336
|
+
if (
|
|
337
|
+
not hits
|
|
338
|
+
and re.search(r"[\u4e00-\u9fff]", text)
|
|
339
|
+
and re.search(market_words, text, re.I)
|
|
340
|
+
and not _universe_refresh_attempted()
|
|
341
|
+
):
|
|
342
|
+
# Refresh only when the local cache cannot answer, and only once per
|
|
343
|
+
# process. This used to pass force=True, which skipped the 7-day
|
|
344
|
+
# cache and re-downloaded the entire A-share + HK universe over the
|
|
345
|
+
# network on *every* message containing a word like "行情" — a
|
|
346
|
+
# multi-second synchronous stall on the routing hot path, repeated
|
|
347
|
+
# even for messages such as "现在的行情呢" that name no company
|
|
348
|
+
# at all and so can never be resolved by any refresh.
|
|
349
|
+
_mark_universe_refresh_attempted()
|
|
350
|
+
scan(ensure_market_universe())
|
|
351
|
+
|
|
352
|
+
ordered: list[tuple[int, MarketSymbol]] = []
|
|
353
|
+
seen_symbols: set[str] = set()
|
|
354
|
+
for idx, item in sorted(hits, key=lambda pair: (pair[0], -len(pair[1].name))):
|
|
355
|
+
sym = item.symbol.upper()
|
|
356
|
+
if sym in seen_symbols:
|
|
357
|
+
continue
|
|
358
|
+
ordered.append((idx, item))
|
|
359
|
+
seen_symbols.add(sym)
|
|
360
|
+
if len(ordered) >= limit:
|
|
361
|
+
break
|
|
362
|
+
return ordered
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
def ambiguous_market_candidates(
|
|
366
|
+
text: str,
|
|
367
|
+
*,
|
|
368
|
+
limit: int = 20,
|
|
369
|
+
load_universe: Callable[[], list[MarketSymbol]] | None = None,
|
|
370
|
+
) -> list[tuple[int, str, list[MarketSymbol]]]:
|
|
371
|
+
"""Return same-name mentions that map to more than one market symbol.
|
|
372
|
+
|
|
373
|
+
Different assets mentioned in one sentence are not considered ambiguous;
|
|
374
|
+
candidates must start at the same position and have the same display name.
|
|
375
|
+
"""
|
|
376
|
+
# Ambiguity checks run on every natural-language message, so they must stay
|
|
377
|
+
# cache-only. A missing cache must not turn an ordinary methodology
|
|
378
|
+
# question into a slow network refresh.
|
|
379
|
+
loader = load_universe or _load_cache
|
|
380
|
+
hits = resolve_market_mentions(text, limit=limit, load_universe=loader)
|
|
381
|
+
return _ambiguous_groups_from_hits(hits)
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
def _ambiguous_groups_from_hits(
|
|
385
|
+
hits: Iterable[tuple[int, MarketSymbol]],
|
|
386
|
+
) -> list[tuple[int, str, list[MarketSymbol]]]:
|
|
387
|
+
grouped: dict[tuple[int, str], list[MarketSymbol]] = {}
|
|
388
|
+
display_names: dict[tuple[int, str], str] = {}
|
|
389
|
+
for position, item in hits:
|
|
390
|
+
normalized_name = re.sub(r"\s+", "", item.name).casefold()
|
|
391
|
+
key = (position, normalized_name)
|
|
392
|
+
grouped.setdefault(key, []).append(item)
|
|
393
|
+
display_names[key] = item.name
|
|
394
|
+
|
|
395
|
+
ambiguous: list[tuple[int, str, list[MarketSymbol]]] = []
|
|
396
|
+
for key, candidates in grouped.items():
|
|
397
|
+
unique: list[MarketSymbol] = []
|
|
398
|
+
seen: set[str] = set()
|
|
399
|
+
for candidate in candidates:
|
|
400
|
+
symbol = candidate.symbol.upper()
|
|
401
|
+
if symbol not in seen:
|
|
402
|
+
unique.append(candidate)
|
|
403
|
+
seen.add(symbol)
|
|
404
|
+
if len(unique) > 1:
|
|
405
|
+
ambiguous.append((key[0], display_names[key], unique))
|
|
406
|
+
ambiguous.sort(key=lambda item: item[0])
|
|
407
|
+
return ambiguous
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
def select_market_candidate(reply: str, candidates: Iterable[MarketSymbol]) -> MarketSymbol | None:
|
|
411
|
+
"""Resolve a short clarification reply to one of the offered candidates."""
|
|
412
|
+
options = list(candidates)
|
|
413
|
+
text = str(reply or "").strip()
|
|
414
|
+
if not text:
|
|
415
|
+
return None
|
|
416
|
+
normalized = re.sub(r"\s+", "", text).casefold()
|
|
417
|
+
for option in options:
|
|
418
|
+
market_aliases = {
|
|
419
|
+
"CN": {"a股", "沪深", "中国a股"},
|
|
420
|
+
"HK": {"港股", "香港"},
|
|
421
|
+
"US": {"美股", "美国"},
|
|
422
|
+
"EU": {"欧股", "欧洲"},
|
|
423
|
+
}.get(option.market.upper(), set())
|
|
424
|
+
labels = {
|
|
425
|
+
option.symbol,
|
|
426
|
+
option.name,
|
|
427
|
+
option.market,
|
|
428
|
+
f"{option.name}{option.symbol}",
|
|
429
|
+
f"{option.name}{option.market}",
|
|
430
|
+
*market_aliases,
|
|
431
|
+
}
|
|
432
|
+
if normalized in {re.sub(r"\s+", "", value).casefold() for value in labels if value}:
|
|
433
|
+
return option
|
|
434
|
+
if text.isdigit():
|
|
435
|
+
index = int(text) - 1
|
|
436
|
+
return options[index] if 0 <= index < len(options) else None
|
|
437
|
+
return None
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
def resolve_market_symbol(text: str) -> str:
|
|
441
|
+
hits = resolve_market_mentions(text, limit=20)
|
|
442
|
+
if _ambiguous_groups_from_hits(hits):
|
|
443
|
+
return ""
|
|
444
|
+
return hits[0][1].symbol if hits else ""
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
# Words that routinely sit in front of a market term without naming a company:
|
|
448
|
+
# time adverbs, demonstratives and scope words. Without this stoplist the guard
|
|
449
|
+
# below read "现在的行情呢" as the unknown company "现在", which blocked the very
|
|
450
|
+
# follow-up case it exists to support — "现在的股票和趋势呢" is the example named
|
|
451
|
+
# in _is_market_snapshot_request's own docstring, and it did not work.
|
|
452
|
+
_NON_COMPANY_QUALIFIERS = (
|
|
453
|
+
"现在", "目前", "当前", "今天", "今日", "昨天", "昨日", "明天", "近期",
|
|
454
|
+
"最新", "最近", "短期", "中期", "长期", "未来", "后续", "以上", "上面",
|
|
455
|
+
"刚才", "这个", "那个", "这些", "那些", "整体", "总体", "大盘", "所有",
|
|
456
|
+
"上述", "全部", "其他", "别的", "同类", "相关", "本周", "本月", "今年",
|
|
457
|
+
"去年", "它", "他", "她", "我", "你",
|
|
458
|
+
)
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
def looks_like_unresolved_market_name(text: str) -> bool:
|
|
462
|
+
"""Heuristic guard: a Chinese name before market words should not inherit history."""
|
|
463
|
+
if resolve_market_symbol(text):
|
|
464
|
+
return False
|
|
465
|
+
if not re.search(r"[\u4e00-\u9fff]{2,12}", text or ""):
|
|
466
|
+
return False
|
|
467
|
+
market_words = "走势|预测|股价|股票|行情|趋势|技术面|基本面|涨跌|价格|市值"
|
|
468
|
+
# A market term can also precede another one ("股价涨跌怎么样"); such a
|
|
469
|
+
# qualifier names no company either and must be stripped alongside the
|
|
470
|
+
# generic time/scope words.
|
|
471
|
+
droppable = tuple(market_words.split("|")) + _NON_COMPANY_QUALIFIERS
|
|
472
|
+
pattern = rf"([\u4e00-\u9fffA-Za-z0-9]{{2,16}}?)(?:的)?(?:{market_words})"
|
|
473
|
+
for match in re.finditer(pattern, text or ""):
|
|
474
|
+
qualifier = match.group(1)
|
|
475
|
+
# Strip trailing non-company words so "腾讯现在的股价" still reports the
|
|
476
|
+
# name "腾讯", while "现在的股价" and "股价涨跌" report nothing.
|
|
477
|
+
changed = True
|
|
478
|
+
while changed and qualifier:
|
|
479
|
+
changed = False
|
|
480
|
+
for word in droppable:
|
|
481
|
+
if qualifier.endswith(word):
|
|
482
|
+
qualifier = qualifier[: -len(word)]
|
|
483
|
+
changed = True
|
|
484
|
+
break
|
|
485
|
+
if len(qualifier) >= 2:
|
|
486
|
+
return True
|
|
487
|
+
return False
|