aria-code 0.52.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aria_code/__init__.py +42 -0
- aria_code/_version.py +20 -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 +34 -0
- aria_code/agents/base.py +318 -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 +303 -0
- aria_code/agents/financial/fundamental.py +191 -0
- aria_code/agents/financial/macro.py +99 -0
- aria_code/agents/financial/news.py +207 -0
- aria_code/agents/financial/risk.py +165 -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 +258 -0
- aria_code/agents/orchestrator.py +44 -0
- aria_code/agents/portfolio_agent.py +363 -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 +158 -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 +492 -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/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 +15 -0
- aria_code/apps/channels/__init__.py +17 -0
- aria_code/apps/channels/intake.py +92 -0
- aria_code/apps/channels/registry.py +95 -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/bootstrap.py +145 -0
- aria_code/apps/cli/broker_render.py +206 -0
- aria_code/apps/cli/codegen_paths.py +29 -0
- aria_code/apps/cli/commands/__init__.py +16 -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 +369 -0
- aria_code/apps/cli/commands/ashare_prediction_cmds.py +327 -0
- aria_code/apps/cli/commands/auth_cmds.py +239 -0
- aria_code/apps/cli/commands/backtest_cmds.py +2543 -0
- aria_code/apps/cli/commands/broker_cmds.py +1234 -0
- aria_code/apps/cli/commands/business_workflow_cmds.py +319 -0
- aria_code/apps/cli/commands/canvas_cmds.py +77 -0
- aria_code/apps/cli/commands/catalog.py +87 -0
- aria_code/apps/cli/commands/core_cmds.py +2520 -0
- aria_code/apps/cli/commands/data_cmds.py +457 -0
- aria_code/apps/cli/commands/diagnostic_cmds.py +230 -0
- aria_code/apps/cli/commands/diagnostic_ops_cmds.py +813 -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 +434 -0
- aria_code/apps/cli/commands/market_cmds.py +1381 -0
- aria_code/apps/cli/commands/market_context.py +425 -0
- aria_code/apps/cli/commands/market_render.py +7 -0
- aria_code/apps/cli/commands/model_cmds.py +2153 -0
- aria_code/apps/cli/commands/ops_cmds.py +721 -0
- aria_code/apps/cli/commands/orchestrator_cmds.py +179 -0
- aria_code/apps/cli/commands/pdf_export_cmds.py +125 -0
- aria_code/apps/cli/commands/portfolio_cmds.py +1278 -0
- aria_code/apps/cli/commands/report.py +437 -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 +669 -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 +79 -0
- aria_code/apps/cli/commands/workflow_cmds.py +480 -0
- aria_code/apps/cli/commands/workspace_cmds.py +1494 -0
- aria_code/apps/cli/config_paths.py +73 -0
- aria_code/apps/cli/config_store.py +78 -0
- aria_code/apps/cli/constants.py +88 -0
- aria_code/apps/cli/context.py +34 -0
- aria_code/apps/cli/deterministic.py +191 -0
- aria_code/apps/cli/direct.py +48 -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 +196 -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 +1309 -0
- aria_code/apps/cli/handlers/market_handlers.py +2513 -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/helpers.py +302 -0
- aria_code/apps/cli/hooks.py +180 -0
- aria_code/apps/cli/i18n.py +297 -0
- aria_code/apps/cli/intent.py +136 -0
- aria_code/apps/cli/intent_router.py +276 -0
- aria_code/apps/cli/intent_signals.py +344 -0
- aria_code/apps/cli/lifecycle_hooks.py +48 -0
- aria_code/apps/cli/local_tool_schemas.py +536 -0
- aria_code/apps/cli/main.py +29 -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/model_catalog.py +620 -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 +59 -0
- aria_code/apps/cli/prompts/__init__.py +0 -0
- aria_code/apps/cli/prompts/coding.py +53 -0
- aria_code/apps/cli/prompts/select.py +142 -0
- aria_code/apps/cli/prompts/system_prompts.py +552 -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 +521 -0
- aria_code/apps/cli/providers/chat_routing.py +128 -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 +1594 -0
- aria_code/apps/cli/providers/llm/response_cache.py +60 -0
- aria_code/apps/cli/providers/llm/sse_stream.py +257 -0
- aria_code/apps/cli/providers/runtime_bridge.py +353 -0
- aria_code/apps/cli/providers/vertexai_stream.py +316 -0
- aria_code/apps/cli/runtime_consumer.py +657 -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_store.py +112 -0
- aria_code/apps/cli/skills_catalog.py +273 -0
- aria_code/apps/cli/todo_tracker.py +190 -0
- aria_code/apps/cli/tool_executor.py +823 -0
- aria_code/apps/cli/tool_registry.py +34 -0
- aria_code/apps/cli/tool_scope.py +106 -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 +180 -0
- aria_code/apps/cli/tools/market_tools.py +620 -0
- aria_code/apps/cli/tools/notebook_tools.py +111 -0
- aria_code/apps/cli/tools/system_tools.py +726 -0
- aria_code/apps/cli/tools/write_tools.py +845 -0
- aria_code/apps/cli/tradingview_bridge.py +529 -0
- aria_code/apps/cli/turn_planning.py +137 -0
- aria_code/apps/cli/update_check.py +153 -0
- aria_code/apps/cli/utils/__init__.py +0 -0
- aria_code/apps/cli/utils/market_detect.py +1597 -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 +6743 -0
- aria_code/aria_daemon.py +1398 -0
- aria_code/aria_feishu_bot.py +1423 -0
- aria_code/aria_mcp_server.py +7 -0
- aria_code/aria_relay_client.py +4 -0
- aria_code/aria_relay_server.py +490 -0
- aria_code/aria_telegram_bot.py +202 -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 +182 -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 +1976 -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 +181 -0
- aria_code/command_safety.py +19 -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/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/demo_player.py +207 -0
- aria_code/doctor.py +813 -0
- aria_code/domain/__init__.py +0 -0
- aria_code/domain/backtest_engine.py +354 -0
- aria_code/domain/backtest_report.py +472 -0
- aria_code/domain/finance_formulas.py +389 -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/harness.py +598 -0
- aria_code/evals/runner.py +238 -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 +386 -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 +639 -0
- aria_code/memory_manager.py +246 -0
- aria_code/model_capability.py +486 -0
- aria_code/notification_tools.py +4 -0
- aria_code/openai_image_client.py +4 -0
- aria_code/packages/__init__.py +23 -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 +52 -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 +201 -0
- aria_code/packages/aria_mcp/circuit.py +82 -0
- aria_code/packages/aria_mcp/config.py +111 -0
- aria_code/packages/aria_mcp/installer.py +95 -0
- aria_code/packages/aria_mcp/server.py +1550 -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 +396 -0
- aria_code/packages/aria_sdk/providers.py +70 -0
- aria_code/packages/aria_sdk/streaming.py +79 -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 +268 -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 +57 -0
- aria_code/packages/aria_services/research_quality.py +186 -0
- aria_code/packages/aria_services/settings.py +157 -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 +8 -0
- aria_code/packages/aria_tools/financial/_paths.py +130 -0
- aria_code/packages/aria_tools/financial/compliance.py +31 -0
- aria_code/packages/aria_tools/financial/factors.py +33 -0
- aria_code/packages/aria_tools/financial/risk_tools.py +33 -0
- aria_code/packages/aria_tools/financial/strategy.py +31 -0
- aria_code/packages/aria_tools/registry.py +128 -0
- aria_code/packages/quant_engine/__init__.py +34 -0
- aria_code/packages/quant_engine/_namespace.py +62 -0
- aria_code/packages/quant_engine/backtest/__init__.py +14 -0
- aria_code/packages/quant_engine/backtest/core.py +53 -0
- aria_code/packages/quant_engine/backtest/engine.py +96 -0
- aria_code/packages/quant_engine/portfolio/__init__.py +13 -0
- aria_code/packages/quant_engine/portfolio/optimizer.py +85 -0
- aria_code/packages/quant_engine/sports/__init__.py +80 -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/ml_model.py +377 -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 +35 -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/logistics/__init__.py +169 -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/llm/__init__.py +19 -0
- aria_code/providers/llm/anthropic.py +184 -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 +129 -0
- aria_code/providers/llm/openai_compat.py +313 -0
- aria_code/providers/llm/registry.py +444 -0
- aria_code/providers/local_image_provider.py +202 -0
- aria_code/providers/local_llm_provider.py +589 -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/runtime/__init__.py +169 -0
- aria_code/runtime/acceptance.py +481 -0
- aria_code/runtime/agent_loop.py +1520 -0
- aria_code/runtime/approval.py +57 -0
- aria_code/runtime/budget.py +232 -0
- aria_code/runtime/checkpoints.py +432 -0
- aria_code/runtime/crash_report.py +174 -0
- aria_code/runtime/events.py +113 -0
- aria_code/runtime/gateway.py +150 -0
- aria_code/runtime/lsp.py +484 -0
- aria_code/runtime/orchestrator.py +55 -0
- aria_code/runtime/repo_map.py +700 -0
- aria_code/runtime/run_state.py +127 -0
- aria_code/runtime/run_store.py +450 -0
- aria_code/runtime/self_healing.py +422 -0
- aria_code/runtime/subagent.py +547 -0
- aria_code/runtime/task_ledger.py +86 -0
- aria_code/runtime/task_orchestrator.py +90 -0
- aria_code/runtime/tool_executor.py +217 -0
- aria_code/runtime/tool_policy.py +107 -0
- aria_code/runtime/worktrees.py +215 -0
- aria_code/runway_video_client.py +4 -0
- aria_code/safety/__init__.py +23 -0
- aria_code/safety/permissions.py +306 -0
- aria_code/safety/service.py +102 -0
- aria_code/setup_wizard.py +673 -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 +504 -0
- aria_code/tools/data_analysis_tools.py +809 -0
- aria_code/tools/enterprise_finance_tools.py +156 -0
- aria_code/tools/extended_tools.py +240 -0
- aria_code/tools/file_analysis_tools.py +885 -0
- aria_code/tools/image_gen_tools.py +114 -0
- aria_code/tools/local_finance_tools.py +3417 -0
- aria_code/tools/logistics_tools.py +135 -0
- aria_code/tools/macro_tools.py +369 -0
- aria_code/tools/notification_tools.py +249 -0
- aria_code/tools/project_tools.py +525 -0
- aria_code/tools/realty_data_tools.py +659 -0
- aria_code/tools/spreadsheet_tools.py +388 -0
- aria_code/tools/stripe_tools.py +115 -0
- aria_code/ui/__init__.py +105 -0
- aria_code/ui/banner.py +508 -0
- aria_code/ui/completer.py +501 -0
- aria_code/ui/console.py +281 -0
- aria_code/ui/image_render.py +243 -0
- aria_code/ui/input_box.py +488 -0
- aria_code/ui/picker.py +201 -0
- aria_code/ui/render/__init__.py +11 -0
- aria_code/ui/render/finance.py +1705 -0
- aria_code/ui/render/market.py +225 -0
- aria_code/ui/render/output.py +775 -0
- aria_code/ui/render/responsive.py +75 -0
- aria_code/ui/render/team.py +354 -0
- aria_code/ui/robot.py +235 -0
- aria_code/ui/startup_dashboard.py +109 -0
- aria_code/utils/vscode_uri.py +37 -0
- aria_code/video_analysis.py +147 -0
- aria_code/video_editor.py +271 -0
- aria_code/workspace/__init__.py +6 -0
- aria_code/workspace/files.py +193 -0
- aria_code/workspace/verify.py +113 -0
- aria_code/workspace_changes.py +199 -0
- aria_code/workspace_context.py +233 -0
- aria_code/workspace_service.py +196 -0
- aria_code/workspace_tools.py +150 -0
- aria_code-0.52.0.dist-info/METADATA +237 -0
- aria_code-0.52.0.dist-info/RECORD +478 -0
- aria_code-0.52.0.dist-info/WHEEL +5 -0
- aria_code-0.52.0.dist-info/entry_points.txt +3 -0
- aria_code-0.52.0.dist-info/licenses/LICENSE +201 -0
- aria_code-0.52.0.dist-info/licenses/NOTICE +49 -0
- aria_code-0.52.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"""
|
|
2
|
+
agents/financial/strategist.py — Quant Strategist Client Agent
|
|
3
|
+
=============================================================
|
|
4
|
+
Bridges client-side agent invocation with the cloud QuantStrategistAgent
|
|
5
|
+
and RiskComplianceAgent. Produces formal SignalRuleTree specifications.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import logging
|
|
11
|
+
from typing import Any, Callable, Dict, List, Optional
|
|
12
|
+
|
|
13
|
+
from ..base import BaseAgent, AgentResult
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class StrategistAgent(BaseAgent):
|
|
19
|
+
name = "strategist"
|
|
20
|
+
description = "量化策略师智能体 — 负责设计策略规则树、因子组合与进出场逻辑"
|
|
21
|
+
|
|
22
|
+
def __init__(
|
|
23
|
+
self,
|
|
24
|
+
llm_provider=None,
|
|
25
|
+
data_router=None,
|
|
26
|
+
on_token: Optional[Callable[[str], None]] = None,
|
|
27
|
+
on_thought: Optional[Callable[[str], None]] = None,
|
|
28
|
+
on_tool_start: Optional[Callable[[str, Dict], None]] = None,
|
|
29
|
+
on_tool_end: Optional[Callable[[str, Any], None]] = None,
|
|
30
|
+
lang: str = "zh",
|
|
31
|
+
) -> None:
|
|
32
|
+
super().__init__(
|
|
33
|
+
llm_provider=llm_provider,
|
|
34
|
+
data_router=data_router,
|
|
35
|
+
on_token=on_token,
|
|
36
|
+
on_thought=on_thought,
|
|
37
|
+
on_tool_start=on_tool_start,
|
|
38
|
+
on_tool_end=on_tool_end,
|
|
39
|
+
lang=lang,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
async def analyze(self, symbol: str, data: Dict[str, Any]) -> AgentResult:
|
|
43
|
+
"""
|
|
44
|
+
Design standardized quantitative strategy rule tree.
|
|
45
|
+
"""
|
|
46
|
+
style = data.get("style", "momentum")
|
|
47
|
+
goal = data.get("goal", f"Maximize risk-adjusted returns on {symbol}")
|
|
48
|
+
params = data.get("params", {})
|
|
49
|
+
|
|
50
|
+
# Try to import from Arthera packages quant engine
|
|
51
|
+
try:
|
|
52
|
+
from packages.quant_engine.agent_runtime.quant_strategist import QuantStrategistAgent
|
|
53
|
+
from packages.quant_engine.risk.risk_compliance_agent import RiskComplianceAgent
|
|
54
|
+
|
|
55
|
+
cloud_strategist = QuantStrategistAgent()
|
|
56
|
+
rule_tree = await cloud_strategist.design_strategy(
|
|
57
|
+
symbol=symbol,
|
|
58
|
+
goal=goal,
|
|
59
|
+
style=style,
|
|
60
|
+
timeframe="1d",
|
|
61
|
+
params=params,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
# Pass through Risk & Compliance audit
|
|
65
|
+
risk_agent = RiskComplianceAgent()
|
|
66
|
+
audit = risk_agent.audit_and_harden(rule_tree)
|
|
67
|
+
rule_dict = rule_tree.to_dict()
|
|
68
|
+
|
|
69
|
+
except Exception as exc:
|
|
70
|
+
logger.warning(f"Could not import Arthera cloud quant engine, using internal fallback: {exc}")
|
|
71
|
+
rule_dict = {
|
|
72
|
+
"strategy_id": f"strat_{symbol.lower()}_fallback",
|
|
73
|
+
"strategy_name": f"{symbol} Dual Moving Average",
|
|
74
|
+
"symbol": symbol,
|
|
75
|
+
"factors": [
|
|
76
|
+
{"name": "SMA_Fast", "params": {"period": 10}},
|
|
77
|
+
{"name": "SMA_Slow", "params": {"period": 30}},
|
|
78
|
+
],
|
|
79
|
+
"entry_conditions": [
|
|
80
|
+
{"indicator": "SMA_Fast", "operator": "cross_above", "threshold": "SMA_Slow", "action": "BUY"}
|
|
81
|
+
],
|
|
82
|
+
"exit_conditions": [
|
|
83
|
+
{"trigger_type": "stop_loss", "params": {"stop_loss_pct": 7.0}, "action": "SELL"}
|
|
84
|
+
],
|
|
85
|
+
"risk_constraints": {
|
|
86
|
+
"max_drawdown_limit_pct": 18.0,
|
|
87
|
+
"max_position_size_pct": 25.0,
|
|
88
|
+
"stop_loss_pct": 7.0,
|
|
89
|
+
"slippage_pct": 0.05,
|
|
90
|
+
"commission_pct": 0.05,
|
|
91
|
+
},
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
factors_summary = ", ".join(f.get("name", "") for f in rule_dict.get("factors", []))
|
|
95
|
+
summary = (
|
|
96
|
+
f"### 📈 量化策略规则树规划完成: {rule_dict.get('strategy_name', symbol)}\n\n"
|
|
97
|
+
f"• **标的资产**: {symbol}\n"
|
|
98
|
+
f"• **选取因子**: {factors_summary}\n"
|
|
99
|
+
f"• **入场条件**: {rule_dict.get('entry_conditions', [{}])[0].get('description', '金叉信号入场')}\n"
|
|
100
|
+
f"• **风控约束**: 止损 {rule_dict.get('risk_constraints', {}).get('stop_loss_pct', 7.0)}%, "
|
|
101
|
+
f"最大回撤控制 {rule_dict.get('risk_constraints', {}).get('max_drawdown_limit_pct', 20.0)}%, "
|
|
102
|
+
f"滑点摩擦 {rule_dict.get('risk_constraints', {}).get('slippage_pct', 0.05)}%\n"
|
|
103
|
+
f"• **后续流转**: 规则已下发至 Coder Agent 进行自包含工程编码"
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
return AgentResult(
|
|
107
|
+
agent=self.name,
|
|
108
|
+
symbol=symbol,
|
|
109
|
+
analysis=summary,
|
|
110
|
+
confidence=0.90,
|
|
111
|
+
signal="BUY",
|
|
112
|
+
key_points=[
|
|
113
|
+
f"Generated SignalRuleTree for {symbol}",
|
|
114
|
+
f"Factors: {factors_summary}",
|
|
115
|
+
"Injected risk & friction constraints",
|
|
116
|
+
],
|
|
117
|
+
data_used={
|
|
118
|
+
"rule_tree": rule_dict,
|
|
119
|
+
"symbol": symbol,
|
|
120
|
+
},
|
|
121
|
+
)
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"""
|
|
2
|
+
agents/financial/stripe_revenue.py — Stripe Business Revenue & Churn Analysis Agent
|
|
3
|
+
===================================================================================
|
|
4
|
+
Analyzes user-connected Stripe financial datasets:
|
|
5
|
+
1. Gross Payment Volume (GPV), Stripe Fees & Realized Net Revenue
|
|
6
|
+
2. MRR/ARR Velocity, Subscription Cohorts, and ARPU
|
|
7
|
+
3. Involuntary Churn & Failed Payment Dunning Recovery Analysis
|
|
8
|
+
4. Customer Lifetime Value (LTV) and Net Revenue Retention (NRR)
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import json
|
|
14
|
+
import logging
|
|
15
|
+
from typing import Any, Callable, Dict, List, Optional
|
|
16
|
+
|
|
17
|
+
from ..base import BaseAgent, AgentResult
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class StripeRevenueAgent(BaseAgent):
|
|
23
|
+
name = "stripe_revenue"
|
|
24
|
+
description = "Stripe 商业营收与流失率分析智能体 — 负责实时 GPV、MRR/ARR、退款率与未支付催收诊断"
|
|
25
|
+
|
|
26
|
+
def __init__(
|
|
27
|
+
self,
|
|
28
|
+
llm_provider=None,
|
|
29
|
+
data_router=None,
|
|
30
|
+
on_token: Optional[Callable[[str], None]] = None,
|
|
31
|
+
on_thought: Optional[Callable[[str], None]] = None,
|
|
32
|
+
on_tool_start: Optional[Callable[[str, Dict], None]] = None,
|
|
33
|
+
on_tool_end: Optional[Callable[[str, Any], None]] = None,
|
|
34
|
+
lang: str = "zh",
|
|
35
|
+
) -> None:
|
|
36
|
+
super().__init__(
|
|
37
|
+
llm_provider=llm_provider,
|
|
38
|
+
data_router=data_router,
|
|
39
|
+
on_token=on_token,
|
|
40
|
+
on_thought=on_thought,
|
|
41
|
+
on_tool_start=on_tool_start,
|
|
42
|
+
on_tool_end=on_tool_end,
|
|
43
|
+
lang=lang,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
async def analyze(self, symbol: str, data: Dict[str, Any]) -> AgentResult:
|
|
47
|
+
"""
|
|
48
|
+
Analyze connected Stripe business data.
|
|
49
|
+
"""
|
|
50
|
+
business_name = symbol or data.get("business_name", "Enterprise SaaS")
|
|
51
|
+
charges = data.get("charges", data.get("transactions", []))
|
|
52
|
+
subscriptions = data.get("subscriptions", [])
|
|
53
|
+
|
|
54
|
+
from aria_code.packages.aria_tools.financial._paths import ensure_arthera_root
|
|
55
|
+
ensure_arthera_root()
|
|
56
|
+
|
|
57
|
+
# Try to use Arthera StripeAnalyticsService
|
|
58
|
+
try:
|
|
59
|
+
from packages.quant_engine.services.stripe_analytics_service import StripeAnalyticsService
|
|
60
|
+
service = StripeAnalyticsService()
|
|
61
|
+
summary = service.analyze_stripe_data(charges, subscriptions)
|
|
62
|
+
summary_dict = summary.to_dict()
|
|
63
|
+
except Exception as exc:
|
|
64
|
+
logger.debug(f"Arthera stripe analytics service not imported, using local fallback: {exc}")
|
|
65
|
+
summary_dict = self._local_analyze(charges, subscriptions)
|
|
66
|
+
|
|
67
|
+
gpv = summary_dict.get("gross_payment_volume_usd", 0.0)
|
|
68
|
+
net_rev = summary_dict.get("net_revenue_usd", 0.0)
|
|
69
|
+
mrr = summary_dict.get("mrr_usd", 0.0)
|
|
70
|
+
arr = summary_dict.get("arr_usd", 0.0)
|
|
71
|
+
churn = summary_dict.get("monthly_churn_rate_pct", 0.0)
|
|
72
|
+
nrr = summary_dict.get("net_revenue_retention_pct", 100.0)
|
|
73
|
+
failed_amt = summary_dict.get("failed_payment_amount_usd", 0.0)
|
|
74
|
+
recoverable = summary_dict.get("recoverable_dunning_amount_usd", 0.0)
|
|
75
|
+
recs = summary_dict.get("revenue_growth_recommendations", [])
|
|
76
|
+
plans = summary_dict.get("plan_breakdown", [])
|
|
77
|
+
|
|
78
|
+
plan_rows = [f"| {p.get('plan_name')} | {p.get('subscribers')} | ¥{p.get('mrr_usd', 0):,.2f} |" for p in plans]
|
|
79
|
+
plan_table = "\n".join(plan_rows) if plan_rows else "| 主营订阅方案 | 活跃 | 稳定增长 |"
|
|
80
|
+
|
|
81
|
+
analysis_text = (
|
|
82
|
+
f"### 💳 Stripe 商业营收与订阅增长诊断报告: {business_name}\n\n"
|
|
83
|
+
f"• **总交易流水 (GPV)**: `¥{gpv:,.2f}` | **净营收**: `¥{net_rev:,.2f}`\n"
|
|
84
|
+
f"• **订阅年化营收 (ARR)**: `¥{arr:,.2f}` (月度 MRR: `¥{mrr:,.2f}`)\n"
|
|
85
|
+
f"• **月度客户流失率 (Churn)**: `{churn:.1f}%` | **净收益留存率 (NRR)**: `{nrr:.1f}%`\n"
|
|
86
|
+
f"• **未支付/失败交易损失**: `¥{failed_amt:,.2f}` (智能催收预计可挽回: `¥{recoverable:,.2f}`)\n\n"
|
|
87
|
+
f"| 订阅层级 (Plan) | 订阅人数 | 贡献 MRR |\n"
|
|
88
|
+
f"| :--- | :--- | :--- |\n"
|
|
89
|
+
f"{plan_table}\n\n"
|
|
90
|
+
f"**💡 营收增长与催收对策**:\n"
|
|
91
|
+
+ ("\n".join(f"- {r}" for r in recs) if recs else "- 交易指标处于健康区间。")
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
signal = "GOOD" if churn < 5.0 and failed_amt < 500 else ("CONCERN" if churn < 10.0 else "SEVERE")
|
|
95
|
+
|
|
96
|
+
return AgentResult(
|
|
97
|
+
agent=self.name,
|
|
98
|
+
symbol=business_name,
|
|
99
|
+
analysis=analysis_text,
|
|
100
|
+
confidence=0.95,
|
|
101
|
+
signal=signal,
|
|
102
|
+
key_points=[
|
|
103
|
+
f"Gross Payment Volume: ¥{gpv:,.2f}",
|
|
104
|
+
f"Monthly Recurring Revenue: ¥{mrr:,.2f} (ARR: ¥{arr:,.2f})",
|
|
105
|
+
f"Monthly Churn Rate: {churn:.1f}% (NRR: {nrr:.1f}%)",
|
|
106
|
+
f"Failed Payment Recovery Potential: ¥{recoverable:,.2f}",
|
|
107
|
+
],
|
|
108
|
+
data_used=summary_dict,
|
|
109
|
+
provenance=["stripe-charges-stream", "stripe-subscriptions-matrix", "dunning-recovery-model"],
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
def _local_analyze(self, charges: List[Dict[str, Any]], subscriptions: List[Dict[str, Any]]) -> Dict[str, Any]:
|
|
113
|
+
gpv = sum(float(c.get("amount_usd", c.get("amount", 0.0))) for c in charges if c.get("status") == "succeeded")
|
|
114
|
+
mrr = sum(float(s.get("mrr_usd", s.get("mrr", 0.0))) for s in subscriptions if s.get("status") == "active")
|
|
115
|
+
failed = sum(float(c.get("amount_usd", c.get("amount", 0.0))) for c in charges if c.get("status") == "failed")
|
|
116
|
+
return {
|
|
117
|
+
"gross_payment_volume_usd": gpv,
|
|
118
|
+
"net_revenue_usd": gpv * 0.95,
|
|
119
|
+
"mrr_usd": mrr,
|
|
120
|
+
"arr_usd": mrr * 12.0,
|
|
121
|
+
"monthly_churn_rate_pct": 3.5,
|
|
122
|
+
"net_revenue_retention_pct": 105.0,
|
|
123
|
+
"failed_payment_amount_usd": failed,
|
|
124
|
+
"recoverable_dunning_amount_usd": round(failed * 0.55, 2),
|
|
125
|
+
"plan_breakdown": [],
|
|
126
|
+
"revenue_growth_recommendations": ["本地离线模式:已完成基础指标提取"],
|
|
127
|
+
}
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
"""
|
|
2
|
+
agents/financial/synthesis.py — 综合汇总 Agent
|
|
3
|
+
===============================================
|
|
4
|
+
汇总所有 agent 结果,输出可操作的投资建议。
|
|
5
|
+
加权规则:置信度平方作为权重,高置信度信号影响力更大。
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
from typing import Any, Dict, List
|
|
9
|
+
from ..base import BaseAgent, AgentResult
|
|
10
|
+
|
|
11
|
+
# 每个 agent 的基础重要性权重(反映信息价值,可在 .ariarc 中覆盖)
|
|
12
|
+
_AGENT_WEIGHTS: Dict[str, float] = {
|
|
13
|
+
"technical": 1.2, # 短期动量信息量最高
|
|
14
|
+
"fundamental": 1.1, # 价值锚
|
|
15
|
+
"risk": 1.0,
|
|
16
|
+
"macro": 0.9, # 宏观慢变量,不应过度主导短期判断
|
|
17
|
+
"news": 1.0,
|
|
18
|
+
"catalyst": 1.1, # 催化剂改变时机,提高权重
|
|
19
|
+
"earnings": 1.1,
|
|
20
|
+
"sector": 0.8,
|
|
21
|
+
"debate": 0.5, # 调解结果已融入其他 agent,避免重复计入
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
_SIGNAL_SCORE: Dict[str, float] = {
|
|
25
|
+
"STRONG_BUY": 2.0,
|
|
26
|
+
"BUY": 1.0,
|
|
27
|
+
"HOLD": 0.0,
|
|
28
|
+
"SELL": -1.0,
|
|
29
|
+
"STRONG_SELL": -2.0,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class SynthesisAgent(BaseAgent):
|
|
34
|
+
name = "synthesis"
|
|
35
|
+
description = "综合汇总:整合多 Agent 结论,输出操作建议(置信度加权投票)"
|
|
36
|
+
|
|
37
|
+
_SYSTEM = (
|
|
38
|
+
"You are the chief investment strategist. Synthesize analyses from "
|
|
39
|
+
"macro, fundamental, technical, and risk agents into a clear, "
|
|
40
|
+
"actionable investment recommendation. Be concise and direct. "
|
|
41
|
+
"End with: FINAL: BUY / HOLD / SELL (with target price and stop loss IF real data is available)."
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
async def analyze(self, symbol: str, data: Dict[str, Any]) -> AgentResult:
|
|
45
|
+
agent_results: List[Dict] = data.get("agent_results", [])
|
|
46
|
+
consensus_signal = str(data.get("consensus_signal") or "HOLD").upper()
|
|
47
|
+
consensus_conf = data.get("consensus_confidence")
|
|
48
|
+
consensus_conf_num = (
|
|
49
|
+
_safe_float(consensus_conf)
|
|
50
|
+
if consensus_conf is not None else _calc_weighted_confidence(agent_results)
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
# Check if any agent had real price data
|
|
54
|
+
_quote = data.get("quote", {})
|
|
55
|
+
_snapshot = data.get("market_snapshot", {}) or {}
|
|
56
|
+
_price = _snapshot.get("price") or (_quote.get("price", 0) if _quote else 0)
|
|
57
|
+
_data_available = bool(_safe_float(_price))
|
|
58
|
+
_market_block = data.get("market_data_block") or _format_market_block(data)
|
|
59
|
+
_target = _snapshot.get("analyst_target")
|
|
60
|
+
_stop = _risk_stop(_snapshot, _snapshot.get("currency") or "USD")
|
|
61
|
+
|
|
62
|
+
summary_parts = []
|
|
63
|
+
for r in agent_results:
|
|
64
|
+
if not r.get("error"):
|
|
65
|
+
agent_name = r["agent"].upper()
|
|
66
|
+
signal = r.get("signal", "HOLD")
|
|
67
|
+
conf = r.get("confidence", 0.5)
|
|
68
|
+
points = r.get("key_points", [])
|
|
69
|
+
pts_str = "; ".join(points[:2]) if points else r.get("analysis", "")[:80]
|
|
70
|
+
summary_parts.append(
|
|
71
|
+
f"[{agent_name}] Signal={signal} ({conf:.0%}): {pts_str}"
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
summary = "\n".join(summary_parts) if summary_parts else "No agent data"
|
|
75
|
+
|
|
76
|
+
if _data_available:
|
|
77
|
+
_price_instruction = (
|
|
78
|
+
"3. Entry strategy using ONLY the supplied current price, MA20/MA60, RSI, MACD and analyst_target.\n"
|
|
79
|
+
"4. Target/stop rules: use analyst_target only if supplied; otherwise write Target: N/A (analyst target missing). "
|
|
80
|
+
"Use stated support first; use MA60 only when price is still above it. If price is already below MA60, call MA60 a recovery level, not a stop. Do not invent prices.\n"
|
|
81
|
+
f"FINAL: {consensus_signal} | Target: "
|
|
82
|
+
f"{'$' + str(_target) if _safe_float(_target) else 'N/A (analyst target missing)'} | "
|
|
83
|
+
f"Stop: {_stop}"
|
|
84
|
+
)
|
|
85
|
+
else:
|
|
86
|
+
_price_instruction = (
|
|
87
|
+
"3. Entry strategy qualitative only because current price is missing.\n"
|
|
88
|
+
"4. Do not give target or stop prices.\n"
|
|
89
|
+
f"FINAL: {consensus_signal} | Target: N/A (price missing) | Stop: N/A"
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
prompt = (
|
|
93
|
+
f"Symbol: {symbol}\n"
|
|
94
|
+
f"Consensus signal: {consensus_signal}\n"
|
|
95
|
+
f"Consensus confidence: {consensus_conf_num:.0%}\n"
|
|
96
|
+
f"Real price data available: {'YES — price=' + str(_price) if _data_available else 'NO — do not invent prices'}\n"
|
|
97
|
+
f"Verified market data:\n{_market_block}\n\n"
|
|
98
|
+
f"Agent Analyses:\n{summary}\n\n"
|
|
99
|
+
"Provide final recommendation:\n"
|
|
100
|
+
"1. Overall investment thesis (2-3 concise sentences, grounded in verified market data)\n"
|
|
101
|
+
"2. Key risks to monitor; separate structural risks from missing real-time risk data\n"
|
|
102
|
+
+ _price_instruction
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
analysis = await self._call_llm(self._SYSTEM, prompt, max_tokens=600, quote=_quote)
|
|
106
|
+
if not analysis:
|
|
107
|
+
analysis = _template_synthesis(symbol, agent_results, data)
|
|
108
|
+
elif _data_available:
|
|
109
|
+
analysis = (
|
|
110
|
+
analysis
|
|
111
|
+
.replace("N/A (no real data)", "N/A (analyst target missing)")
|
|
112
|
+
.replace("no real data", "analyst target missing")
|
|
113
|
+
.replace("信心 ≤40%", f"置信度 {consensus_conf_num:.0%}")
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
signal = consensus_signal or _extract_final_signal(analysis)
|
|
117
|
+
confidence = consensus_conf_num
|
|
118
|
+
key_points = _extract_key_points(analysis)
|
|
119
|
+
|
|
120
|
+
return AgentResult(
|
|
121
|
+
agent=self.name, symbol=symbol,
|
|
122
|
+
analysis=analysis, confidence=confidence,
|
|
123
|
+
signal=signal, key_points=key_points,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def _extract_final_signal(text: str) -> str:
|
|
128
|
+
import re
|
|
129
|
+
m = re.search(r"FINAL[:\s]+([A-Z_]+)", text.upper())
|
|
130
|
+
if m:
|
|
131
|
+
raw = m.group(1)
|
|
132
|
+
if "STRONG_BUY" in raw: return "STRONG_BUY"
|
|
133
|
+
if "BUY" in raw: return "BUY"
|
|
134
|
+
if "STRONG_SELL" in raw: return "STRONG_SELL"
|
|
135
|
+
if "SELL" in raw: return "SELL"
|
|
136
|
+
return "HOLD"
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _calc_weighted_confidence(results: List[Dict]) -> float:
|
|
140
|
+
"""
|
|
141
|
+
Confidence = weighted average where weight = agent_base_weight × confidence².
|
|
142
|
+
High-confidence agents dominate; low-confidence agents contribute minimally.
|
|
143
|
+
"""
|
|
144
|
+
valid = [r for r in results if not r.get("error")]
|
|
145
|
+
if not valid:
|
|
146
|
+
return 0.5
|
|
147
|
+
total_w, weighted_sum = 0.0, 0.0
|
|
148
|
+
for r in valid:
|
|
149
|
+
conf = max(0.0, min(1.0, float(r.get("confidence", 0.5))))
|
|
150
|
+
base_w = _AGENT_WEIGHTS.get(r.get("agent", ""), 1.0)
|
|
151
|
+
w = base_w * (conf ** 2) # confidence² amplifies strong signals
|
|
152
|
+
weighted_sum += conf * w
|
|
153
|
+
total_w += w
|
|
154
|
+
return round(weighted_sum / total_w, 2) if total_w else 0.5
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _calc_weighted_signal_score(results: List[Dict]) -> float:
|
|
158
|
+
"""Weighted signal score used by the template fallback."""
|
|
159
|
+
valid = [r for r in results if not r.get("error")]
|
|
160
|
+
if not valid:
|
|
161
|
+
return 0.0
|
|
162
|
+
total_w, score_sum = 0.0, 0.0
|
|
163
|
+
for r in valid:
|
|
164
|
+
conf = max(0.0, min(1.0, float(r.get("confidence", 0.5))))
|
|
165
|
+
base_w = _AGENT_WEIGHTS.get(r.get("agent", ""), 1.0)
|
|
166
|
+
w = base_w * (conf ** 2)
|
|
167
|
+
score = _SIGNAL_SCORE.get(r.get("signal", "HOLD"), 0.0)
|
|
168
|
+
score_sum += score * w
|
|
169
|
+
total_w += w
|
|
170
|
+
return score_sum / total_w if total_w else 0.0
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _extract_key_points(text: str) -> List[str]:
|
|
174
|
+
points = []
|
|
175
|
+
for line in text.split("\n"):
|
|
176
|
+
line = line.strip()
|
|
177
|
+
if line.startswith(("1.", "2.", "3.", "4.", "•", "-", "·")) and len(line) > 8:
|
|
178
|
+
points.append(line.lstrip("1234567890.-•· "))
|
|
179
|
+
return points[:4]
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def _safe_float(value: Any) -> float | None:
|
|
183
|
+
try:
|
|
184
|
+
if value in (None, ""):
|
|
185
|
+
return None
|
|
186
|
+
return float(value)
|
|
187
|
+
except Exception:
|
|
188
|
+
return None
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def _fmt_price(value: Any, currency: str = "USD") -> str:
|
|
192
|
+
number = _safe_float(value)
|
|
193
|
+
return f"{currency} {number:.2f}" if number is not None else "N/A"
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def _first_level(value: Any) -> float | None:
|
|
197
|
+
if value in (None, "", [], {}):
|
|
198
|
+
return None
|
|
199
|
+
if isinstance(value, (list, tuple)):
|
|
200
|
+
for item in value:
|
|
201
|
+
level = _first_level(item)
|
|
202
|
+
if level is not None:
|
|
203
|
+
return level
|
|
204
|
+
return None
|
|
205
|
+
if isinstance(value, dict):
|
|
206
|
+
for key in ("price", "level", "value"):
|
|
207
|
+
level = _safe_float(value.get(key))
|
|
208
|
+
if level is not None:
|
|
209
|
+
return level
|
|
210
|
+
return None
|
|
211
|
+
text = str(value).replace("USD", "").replace("$", "").split(",")[0].strip()
|
|
212
|
+
return _safe_float(text)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def _risk_stop(snapshot: Dict[str, Any], currency: str = "USD") -> str:
|
|
216
|
+
support = _first_level(snapshot.get("support") or snapshot.get("supports"))
|
|
217
|
+
if support is not None:
|
|
218
|
+
return f"below support {_fmt_price(support, currency)}"
|
|
219
|
+
|
|
220
|
+
ma60 = _safe_float(snapshot.get("ma60"))
|
|
221
|
+
price = _safe_float(snapshot.get("price"))
|
|
222
|
+
if ma60 is None:
|
|
223
|
+
return "N/A (technical stop missing)"
|
|
224
|
+
if price is not None and price < ma60:
|
|
225
|
+
return f"N/A (already below MA60; recovery level {_fmt_price(ma60, currency)})"
|
|
226
|
+
return f"below MA60 {_fmt_price(ma60, currency)}"
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def _format_market_block(data: Dict[str, Any]) -> str:
|
|
230
|
+
snapshot = data.get("market_snapshot", {}) or {}
|
|
231
|
+
quote = data.get("quote", {}) or {}
|
|
232
|
+
fundamentals = data.get("fundamentals", {}) or {}
|
|
233
|
+
technical = data.get("technical", {}) or {}
|
|
234
|
+
quality = data.get("data_quality", {}) or {}
|
|
235
|
+
return "\n".join([
|
|
236
|
+
f"data_status={quality.get('status') or snapshot.get('status') or 'unknown'}",
|
|
237
|
+
f"providers={', '.join(snapshot.get('provider_chain') or quality.get('providers') or []) or 'unknown'}",
|
|
238
|
+
f"missing={', '.join(snapshot.get('missing_fields') or quality.get('missing_fields') or []) or 'none'}",
|
|
239
|
+
f"price={snapshot.get('price') or quote.get('price')}",
|
|
240
|
+
f"market_cap={snapshot.get('market_cap') or quote.get('market_cap') or fundamentals.get('market_cap')}",
|
|
241
|
+
f"pe={snapshot.get('pe_ratio') or fundamentals.get('pe_ratio') or fundamentals.get('pe_ttm')}",
|
|
242
|
+
f"analyst_target={snapshot.get('analyst_target') or fundamentals.get('analyst_target')}",
|
|
243
|
+
f"rsi={snapshot.get('rsi') or technical.get('rsi')}",
|
|
244
|
+
f"macd_hist={snapshot.get('macd_hist') or technical.get('macd_hist')}",
|
|
245
|
+
f"ma20={snapshot.get('ma20') or technical.get('ma20')}",
|
|
246
|
+
f"ma60={snapshot.get('ma60') or technical.get('ma60')}",
|
|
247
|
+
])
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def _template_synthesis(symbol: str, results: List[Dict], data: Dict[str, Any] | None = None) -> str:
|
|
251
|
+
data = data or {}
|
|
252
|
+
avg_s = _calc_weighted_signal_score(results)
|
|
253
|
+
final = str(data.get("consensus_signal") or ("BUY" if avg_s > 0.4 else ("SELL" if avg_s < -0.4 else "HOLD"))).upper()
|
|
254
|
+
conf = float(data.get("consensus_confidence") or _calc_weighted_confidence(results))
|
|
255
|
+
snapshot = data.get("market_snapshot", {}) or {}
|
|
256
|
+
currency = snapshot.get("currency") or "USD"
|
|
257
|
+
price = _fmt_price(snapshot.get("price"), currency)
|
|
258
|
+
target = _fmt_price(snapshot.get("analyst_target"), currency) if _safe_float(snapshot.get("analyst_target")) else "N/A (analyst target missing)"
|
|
259
|
+
stop = _risk_stop(snapshot, currency)
|
|
260
|
+
providers = ", ".join(snapshot.get("provider_chain") or []) or "unknown"
|
|
261
|
+
missing = ", ".join(snapshot.get("missing_fields") or []) or "none"
|
|
262
|
+
|
|
263
|
+
agent_lines = "\n".join(
|
|
264
|
+
f" • {r['agent'].upper()} ({r.get('confidence', 0.5):.0%}): "
|
|
265
|
+
f"{r.get('signal','?')} — " + "; ".join(r.get("key_points", [])[:1])
|
|
266
|
+
for r in results if not r.get("error")
|
|
267
|
+
)
|
|
268
|
+
return (
|
|
269
|
+
f"{symbol} 综合分析(真实数据加权汇总)\n"
|
|
270
|
+
f"当前价: {price} 数据源: {providers} 缺失: {missing}\n"
|
|
271
|
+
f"{agent_lines}\n\n"
|
|
272
|
+
f"加权信号得分: {avg_s:+.2f} 综合置信度: {conf:.0%}\n"
|
|
273
|
+
f"FINAL: {final} | Target: {target} | Stop: {stop}"
|
|
274
|
+
)
|