aria-code 4.1.7__tar.gz → 4.2.0__tar.gz
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-4.1.7 → aria_code-4.2.0}/PKG-INFO +4 -2
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/__init__.py +2 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/base.py +6 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/portfolio_agent.py +43 -13
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/realty/asset_diagnosis.py +6 -4
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/realty/business_match.py +5 -4
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/realty/cashflow_verify.py +6 -5
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/realty/contract_rules.py +5 -4
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/realty/energy_anomaly.py +6 -5
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/realty/exit_settlement.py +6 -5
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/realty/fulfillment_risk.py +8 -7
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/realty/ops_optimize.py +7 -6
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/realty/revenue_share.py +7 -6
- aria_code-4.2.0/agents/signal_scheme.py +97 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/sports/football_agent.py +33 -5
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/team.py +146 -52
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/bootstrap.py +2 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/catalog.py +1 -1
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/diagnostic_ops_cmds.py +51 -10
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/market.py +19 -1
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/model_cmds.py +102 -0
- aria_code-4.2.0/apps/cli/commands/pdf_export_cmds.py +97 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/portfolio_cmds.py +110 -19
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/report.py +60 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/team.py +70 -2
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/workflow_cmds.py +109 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/intent_router.py +32 -5
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/market_universe.py +79 -1
- aria_code-4.2.0/apps/cli/pdf_report.py +977 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/preflight.py +33 -28
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/prompts/system_prompts.py +8 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/providers/llm/ollama_stream.py +94 -6
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/providers/runtime_bridge.py +6 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/runtime_consumer.py +61 -6
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/tools/write_tools.py +79 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/utils/market_detect.py +3 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/aria_cli.py +508 -178
- {aria_code-4.1.7 → aria_code-4.2.0}/aria_code.egg-info/PKG-INFO +4 -2
- {aria_code-4.1.7 → aria_code-4.2.0}/aria_code.egg-info/SOURCES.txt +27 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/aria_code.egg-info/requires.txt +4 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/artifacts.py +66 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/file_analysis_tools.py +36 -9
- {aria_code-4.1.7 → aria_code-4.2.0}/market_data_client.py +87 -16
- {aria_code-4.1.7 → aria_code-4.2.0}/mcp_client.py +20 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_mcp/tools.py +2 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_services/__init__.py +13 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_services/context.py +100 -13
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_services/registry.py +24 -2
- aria_code-4.2.0/packages/aria_services/research_protocol.py +57 -0
- aria_code-4.2.0/packages/aria_services/research_quality.py +186 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_services/usage.py +7 -2
- aria_code-4.2.0/packages/aria_skills/__init__.py +46 -0
- aria_code-4.2.0/packages/aria_skills/catalog.py +148 -0
- aria_code-4.2.0/packages/aria_skills/loader.py +429 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_skills/registry.py +26 -1
- {aria_code-4.1.7 → aria_code-4.2.0}/pyproject.toml +14 -2
- {aria_code-4.1.7 → aria_code-4.2.0}/report_generator.py +201 -4
- {aria_code-4.1.7 → aria_code-4.2.0}/runtime/__init__.py +40 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/runtime/agent_loop.py +69 -6
- {aria_code-4.1.7 → aria_code-4.2.0}/runtime/approval.py +6 -0
- aria_code-4.2.0/runtime/checkpoints.py +432 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/runtime/events.py +13 -2
- {aria_code-4.1.7 → aria_code-4.2.0}/runtime/gateway.py +6 -0
- aria_code-4.2.0/runtime/run_state.py +127 -0
- aria_code-4.2.0/runtime/run_store.py +449 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/runtime/subagent.py +176 -5
- {aria_code-4.1.7 → aria_code-4.2.0}/runtime/tool_executor.py +35 -7
- aria_code-4.2.0/runtime/worktrees.py +215 -0
- aria_code-4.2.0/tests/test_agent_team_fallback.py +105 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_analyze_file_tool.py +20 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_aria_cli_core.py +2 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_artifacts_and_reports.py +26 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_cli_app_split.py +71 -2
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_cli_runtime_consumer.py +27 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_context_service.py +41 -4
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_finance_renderers.py +52 -2
- aria_code-4.2.0/tests/test_football_agent.py +103 -0
- aria_code-4.2.0/tests/test_markdown_pdf.py +60 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_market_data_client.py +50 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_market_universe.py +36 -0
- aria_code-4.2.0/tests/test_ollama_stream_tools.py +137 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_output_rendering.py +33 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_packages_facade.py +6 -0
- aria_code-4.2.0/tests/test_pdf_report.py +270 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_preflight.py +30 -2
- aria_code-4.2.0/tests/test_report_generator.py +65 -0
- aria_code-4.2.0/tests/test_research_protocol.py +26 -0
- aria_code-4.2.0/tests/test_research_quality.py +96 -0
- aria_code-4.2.0/tests/test_responsive_rendering.py +90 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_runtime_agent_loop.py +129 -1
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_runtime_approval.py +31 -0
- aria_code-4.2.0/tests/test_runtime_checkpoints.py +175 -0
- aria_code-4.2.0/tests/test_runtime_run_store.py +146 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_runtime_tool_executor.py +26 -0
- aria_code-4.2.0/tests/test_runtime_worktrees.py +151 -0
- aria_code-4.2.0/tests/test_skill_agent_binding.py +103 -0
- aria_code-4.2.0/tests/test_skill_catalog.py +187 -0
- aria_code-4.2.0/tests/test_skill_loader.py +208 -0
- aria_code-4.2.0/tests/test_spreadsheet_tools.py +92 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_subagent.py +44 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_ui_console_theme.py +8 -1
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_ui_input_box.py +22 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/ui/banner.py +9 -2
- {aria_code-4.1.7 → aria_code-4.2.0}/ui/console.py +8 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/ui/input_box.py +17 -7
- {aria_code-4.1.7 → aria_code-4.2.0}/ui/render/finance.py +148 -21
- {aria_code-4.1.7 → aria_code-4.2.0}/ui/render/output.py +78 -0
- aria_code-4.2.0/ui/render/responsive.py +75 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/ui/render/team.py +10 -2
- aria_code-4.1.7/packages/aria_skills/__init__.py +0 -5
- aria_code-4.1.7/tests/test_ollama_stream_tools.py +0 -57
- {aria_code-4.1.7 → aria_code-4.2.0}/LICENSE +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/README.md +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/deep/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/deep/calibration_loop.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/deep/critic.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/deep/deepen.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/deep/models.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/deep/pipeline.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/deep/quant_fusion.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/deep/themes.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/deep/tiers.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/financial/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/financial/catalyst.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/financial/debate.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/financial/earnings.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/financial/fundamental.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/financial/macro.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/financial/news.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/financial/risk.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/financial/sector.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/financial/synthesis.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/financial/technical.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/realty/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/registry.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/agents/sports/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/aliyun_data_client.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/README.md +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/channels/README.md +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/channels/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/channels/intake.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/channels/registry.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/channels/tradingview.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/README.md +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/codegen_paths.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/analysis_cmds.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/auth_cmds.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/backtest_cmds.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/broker_cmds.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/business_workflow_cmds.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/data_cmds.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/diagnostic_cmds.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/file_cmds.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/finance_render.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/fx_commodity_cmds.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/market_cmds.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/market_context.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/market_render.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/ops_cmds.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/scaffold_templates.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/session_cmds.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/session_ux_cmds.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/team_render.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/ui_cmds.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/workspace_cmds.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/config_paths.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/config_store.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/deterministic.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/direct.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/github_app_auth.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/handlers/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/handlers/broker_handlers.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/handlers/chart_handlers.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/handlers/market_handlers.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/handlers/realty_handlers.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/handlers/strategy_advice.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/hooks.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/i18n.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/intent.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/lifecycle_hooks.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/main.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/market_metadata.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/message_processing.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/plan_mode.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/plotly_html.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/prediction_feedback.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/project_aria.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/prompt_assembly.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/prompts/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/prompts/coding.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/prompts/ui.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/providers/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/providers/base.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/providers/chat_routing.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/providers/llm/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/providers/llm/sse_stream.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/session_export.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/session_jsonl.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/session_store.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/todo_tracker.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/tools/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/tools/context.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/tools/file_tools.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/tools/market_tools.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/tools/notebook_tools.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/tools/system_tools.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/tradingview_bridge.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/turn_planning.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/update_check.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/utils/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/daemon/README.md +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/vscode/README.md +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/apps/vscode/package.json +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/aria_code.egg-info/dependency_links.txt +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/aria_code.egg-info/entry_points.txt +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/aria_code.egg-info/top_level.txt +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/aria_daemon.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/aria_feishu_bot.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/aria_relay_client.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/aria_relay_server.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/aria_telegram_bot.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/ariarc.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/backtest_engine.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/backtest_report.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/brokers/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/brokers/automation.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/brokers/base.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/brokers/capabilities.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/brokers/cn/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/brokers/cn/easytrader_broker.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/brokers/cn/futu_broker.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/brokers/cn/longbridge_broker.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/brokers/cn/tiger_broker.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/brokers/cn/xtquant_broker.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/brokers/config.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/brokers/intl/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/brokers/intl/alpaca_broker.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/brokers/intl/ibkr_broker.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/brokers/intl/webull_broker.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/brokers/paper_broker.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/brokers/planning.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/brokers/registry.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/brokers/trading.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/change_store.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/command_safety.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/computer_use_tools.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/dashboard_generator.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/data_analysis_tools.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/data_cleaner.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/data_service.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/datasources/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/datasources/base.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/datasources/router.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/datasources/sources/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/datasources/sources/akshare_source.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/datasources/sources/alpha_vantage_source.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/datasources/sources/edgar_source.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/datasources/sources/finnhub_source.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/datasources/sources/fred_source.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/datasources/sources/tushare_source.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/datasources/sources/web_scraper_source.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/datasources/sources/world_bank_source.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/datasources/sources/yfinance_source.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/demo_player.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/doctor.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/finance_formulas.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/football_data_client.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/intent_classifier.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/licensing.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/local_finance_tools.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/local_llm_provider.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/macro_tools.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/memory_manager.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/model_capability.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/notification_tools.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_agents/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_agents/manifest.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_core/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_core/architecture.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_core/export.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_core/manifest.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_infra/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_infra/arthera.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_infra/doctor.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_infra/product.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_mcp/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_mcp/bridge.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_mcp/circuit.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_mcp/config.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_sdk/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_sdk/client.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_sdk/providers.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_sdk/streaming.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_sdk/types.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_services/context_checkpoints.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_services/data.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_services/provider_health.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_services/references.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_services/settings.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_tools/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_tools/registry.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/sports/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/sports/calibrator.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/sports/dixon_coles.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/sports/elo.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/sports/form.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/sports/h2h.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/sports/ml_model.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/sports/predictor.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/sports/tracker.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/stochastic/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/stochastic/gbm_enhanced.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/stochastic/ito_calculus.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/stochastic/kelly_criterion.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/stochastic/monte_carlo_advanced.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/stochastic/options_pricing.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/stochastic/stochastic_processes.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/plan_utils.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/plugin_loader.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/portfolio_ledger.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/privacy/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/privacy/feedback.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/project_tools.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/providers/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/providers/llm/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/providers/llm/anthropic.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/providers/llm/base.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/providers/llm/ollama.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/providers/llm/openai_compat.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/providers/llm/registry.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/realty_data_tools.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/runtime/lsp.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/runtime/tool_policy.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/safety/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/safety/permissions.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/safety/service.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/setup.cfg +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/setup_wizard.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/strategy_vault.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_architecture_report.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_aria_sdk.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_backtest_cmds.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_backtest_engine.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_backtest_report.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_broker_automation.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_broker_planning.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_broker_safety.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_business_workflow_cmds.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_channel_intake.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_channels.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_chart_handlers.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_chat_routing.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_cli_bootstrap.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_cli_config_store.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_cli_lifecycle_hooks.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_codegen_output.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_command_safety.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_completions_builder.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_config_paths.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_configured_provider.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_context_checkpoints.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_context_references.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_dashboard_generator.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_data_service.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_deep_analysis.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_doctor.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_football_prediction_output.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_image_inputs.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_intent_router.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_licensing.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_lsp.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_market_history_tool.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_market_symbol_extraction.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_mcp_circuit.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_mcp_client.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_model_selection_state.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_new_modules.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_pick_best_installed_model.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_plan_mode.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_plotly_html_output.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_portfolio_ledger.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_privacy_feedback.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_project_aria.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_prompt_assembly.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_provider_integration.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_provider_registry.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_runtime_bridge.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_runtime_bridge_fallback.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_runtime_gateway.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_safety_permissions.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_safety_service.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_session_search.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_settings_service.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_startup_dashboard.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_streaming_pipeline.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_system_prompts.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_system_tools_output.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_team_synthesis.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_tool_policy.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_trading_service.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_tradingview_bridge.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_turn_planning.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_ui_completer_references.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_ui_robot_banner.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_workspace_files.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_workspace_verify.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/ui/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/ui/completer.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/ui/image_render.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/ui/picker.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/ui/render/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/ui/render/market.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/ui/robot.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/ui/startup_dashboard.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/workspace/__init__.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/workspace/files.py +0 -0
- {aria_code-4.1.7 → aria_code-4.2.0}/workspace/verify.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aria-code
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.2.0
|
|
4
4
|
Summary: AI-powered financial terminal — local LLM + multi-source market data
|
|
5
5
|
License: BUSL-1.1
|
|
6
6
|
Project-URL: Homepage, https://github.com/artherahq/aria-code
|
|
@@ -18,7 +18,7 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.13
|
|
19
19
|
Classifier: Topic :: Office/Business :: Financial
|
|
20
20
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
21
|
-
Requires-Python:
|
|
21
|
+
Requires-Python: <3.14,>=3.10
|
|
22
22
|
Description-Content-Type: text/markdown
|
|
23
23
|
License-File: LICENSE
|
|
24
24
|
Requires-Dist: aiohttp>=3.9.0
|
|
@@ -37,6 +37,8 @@ Requires-Dist: pandas>=2.2.0
|
|
|
37
37
|
Requires-Dist: scipy>=1.13.0
|
|
38
38
|
Requires-Dist: pandas_ta>=0.4.67b0; python_version >= "3.12"
|
|
39
39
|
Requires-Dist: yfinance>=0.2.55
|
|
40
|
+
Requires-Dist: pyobjc-framework-WebKit>=10.0; sys_platform == "darwin"
|
|
41
|
+
Requires-Dist: markdown>=3.6
|
|
40
42
|
Provides-Extra: cn
|
|
41
43
|
Requires-Dist: akshare>=1.14.68; extra == "cn"
|
|
42
44
|
Provides-Extra: crypto
|
|
@@ -24,9 +24,11 @@ agents/ — Aria Code 可组合多智能体系统
|
|
|
24
24
|
from .base import BaseAgent, AgentResult
|
|
25
25
|
from .registry import AgentRegistry, get_registry
|
|
26
26
|
from .team import AgentTeam, run_team
|
|
27
|
+
from .signal_scheme import SignalScheme, FINANCIAL_SCHEME, REALTY_SCHEME
|
|
27
28
|
|
|
28
29
|
__all__ = [
|
|
29
30
|
"BaseAgent", "AgentResult",
|
|
30
31
|
"AgentRegistry", "get_registry",
|
|
31
32
|
"AgentTeam", "run_team",
|
|
33
|
+
"SignalScheme", "FINANCIAL_SCHEME", "REALTY_SCHEME",
|
|
32
34
|
]
|
|
@@ -26,6 +26,9 @@ class AgentResult:
|
|
|
26
26
|
key_points: List[str] = field(default_factory=list) # 关键结论(用于 synthesis)
|
|
27
27
|
data_used: Dict[str, Any] = field(default_factory=dict) # 使用的原始数据
|
|
28
28
|
error: Optional[str] = None # 失败时的错误信息
|
|
29
|
+
degraded: bool = False # True when a deterministic fallback was used
|
|
30
|
+
provenance: List[str] = field(default_factory=list)
|
|
31
|
+
limitations: List[str] = field(default_factory=list)
|
|
29
32
|
|
|
30
33
|
@property
|
|
31
34
|
def success(self) -> bool:
|
|
@@ -40,6 +43,9 @@ class AgentResult:
|
|
|
40
43
|
"signal": self.signal,
|
|
41
44
|
"key_points": self.key_points,
|
|
42
45
|
"error": self.error,
|
|
46
|
+
"degraded": self.degraded,
|
|
47
|
+
"provenance": list(self.provenance),
|
|
48
|
+
"limitations": list(self.limitations),
|
|
43
49
|
}
|
|
44
50
|
|
|
45
51
|
|
|
@@ -47,12 +47,24 @@ class PortfolioAgent(BaseAgent):
|
|
|
47
47
|
|
|
48
48
|
# ── Multi-symbol interface ────────────────────────────────────────────────
|
|
49
49
|
|
|
50
|
-
async def run_portfolio(
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
async def run_portfolio(
|
|
51
|
+
self, symbols: List[str], weights: Optional[Dict[str, float]] = None
|
|
52
|
+
) -> AgentResult:
|
|
53
|
+
"""Primary entry point for multi-symbol analysis.
|
|
54
|
+
|
|
55
|
+
weights: optional {symbol: dollar_cost_basis} from the user's real
|
|
56
|
+
holdings (portfolio_ledger.PortfolioLedger.get_positions()). Without
|
|
57
|
+
it, every position is silently treated as equal-weight — which used
|
|
58
|
+
to be the ONLY mode this agent supported, so a user who actually
|
|
59
|
+
holds 80% NVDA and 20% everything else got a risk verdict computed
|
|
60
|
+
on a fictional 1/n-weighted portfolio instead of their real exposure.
|
|
61
|
+
"""
|
|
62
|
+
data = await self.fetch_portfolio_data(symbols, weights=weights)
|
|
53
63
|
return await self.analyze_portfolio(symbols, data)
|
|
54
64
|
|
|
55
|
-
async def fetch_portfolio_data(
|
|
65
|
+
async def fetch_portfolio_data(
|
|
66
|
+
self, symbols: List[str], weights: Optional[Dict[str, float]] = None
|
|
67
|
+
) -> Dict[str, Any]:
|
|
56
68
|
data: Dict[str, Any] = {"symbols": symbols}
|
|
57
69
|
if len(symbols) < 2:
|
|
58
70
|
return data
|
|
@@ -97,8 +109,15 @@ class PortfolioAgent(BaseAgent):
|
|
|
97
109
|
cov_matrix = returns.cov() * 252
|
|
98
110
|
valid_syms = list(df.columns)
|
|
99
111
|
n = len(valid_syms)
|
|
100
|
-
weights
|
|
101
|
-
|
|
112
|
+
if weights and any(weights.get(s, 0) > 0 for s in valid_syms):
|
|
113
|
+
raw = np.array([max(weights.get(s, 0.0), 0.0) for s in valid_syms])
|
|
114
|
+
w_vec = raw / raw.sum() if raw.sum() > 0 else np.ones(n) / n
|
|
115
|
+
weight_source = "ledger"
|
|
116
|
+
else:
|
|
117
|
+
w_vec = np.ones(n) / n
|
|
118
|
+
weight_source = "equal"
|
|
119
|
+
port_vol = float(np.sqrt(w_vec @ cov_matrix.values @ w_vec))
|
|
120
|
+
position_weights = {s: round(float(w_vec[i]), 4) for i, s in enumerate(valid_syms)}
|
|
102
121
|
|
|
103
122
|
# High correlation pairs (|r| > 0.70)
|
|
104
123
|
high_corr: List[Dict] = []
|
|
@@ -112,8 +131,10 @@ class PortfolioAgent(BaseAgent):
|
|
|
112
131
|
"corr": round(c, 3),
|
|
113
132
|
})
|
|
114
133
|
|
|
115
|
-
# Diversification ratio: weighted avg individual vol / portfolio vol
|
|
116
|
-
|
|
134
|
+
# Diversification ratio: weighted avg individual vol / portfolio vol.
|
|
135
|
+
# Was np.mean() (unweighted) despite the comment already claiming
|
|
136
|
+
# "weighted" — with real ledger weights now available, actually weight it.
|
|
137
|
+
avg_vol = float(sum(w_vec[i] * float(ann_vols.get(s, 0)) for i, s in enumerate(valid_syms)))
|
|
117
138
|
div_ratio = round(avg_vol / port_vol, 2) if port_vol > 0 else 1.0
|
|
118
139
|
|
|
119
140
|
# 52-week return per symbol
|
|
@@ -140,6 +161,8 @@ class PortfolioAgent(BaseAgent):
|
|
|
140
161
|
"best_performer": sorted_ret[0] if sorted_ret else None,
|
|
141
162
|
"worst_performer": sorted_ret[-1] if sorted_ret else None,
|
|
142
163
|
"sector_map": sector_map,
|
|
164
|
+
"position_weights": position_weights,
|
|
165
|
+
"weight_source": weight_source,
|
|
143
166
|
})
|
|
144
167
|
|
|
145
168
|
except ImportError:
|
|
@@ -171,9 +194,11 @@ class PortfolioAgent(BaseAgent):
|
|
|
171
194
|
|
|
172
195
|
valid_syms = data.get("valid_symbols", symbols)
|
|
173
196
|
port_block = _format_portfolio_stats(data)
|
|
197
|
+
weight_desc = ("your actual position sizes" if data.get("weight_source") == "ledger"
|
|
198
|
+
else "equal weight — no real position sizes available")
|
|
174
199
|
|
|
175
200
|
prompt = (
|
|
176
|
-
f"Portfolio: {', '.join(valid_syms)} ({len(valid_syms)} positions,
|
|
201
|
+
f"Portfolio: {', '.join(valid_syms)} ({len(valid_syms)} positions, weighted by {weight_desc})\n\n"
|
|
177
202
|
f"{port_block}\n\n"
|
|
178
203
|
"Analyze this portfolio:\n"
|
|
179
204
|
"1. Overall risk level (Low / Medium / High)\n"
|
|
@@ -217,15 +242,17 @@ def _format_portfolio_stats(d: Dict) -> str:
|
|
|
217
242
|
vols = d.get("ann_vols", {})
|
|
218
243
|
rets = d.get("ann_returns", {})
|
|
219
244
|
rets_1y = d.get("returns_1y", {})
|
|
245
|
+
pweights = d.get("position_weights", {})
|
|
220
246
|
if vols:
|
|
221
|
-
lines.append("Symbol │ Ann.Vol │ Ann.Ret │ 1Y Return")
|
|
222
|
-
lines.append("─" *
|
|
247
|
+
lines.append("Symbol │ Weight │ Ann.Vol │ Ann.Ret │ 1Y Return")
|
|
248
|
+
lines.append("─" * 52)
|
|
223
249
|
for sym in d.get("valid_symbols", list(vols)):
|
|
224
250
|
v = vols.get(sym, 0)
|
|
225
251
|
r = rets.get(sym, 0)
|
|
226
252
|
y = rets_1y.get(sym, 0)
|
|
253
|
+
w = pweights.get(sym, 0)
|
|
227
254
|
lines.append(
|
|
228
|
-
f"{sym:<6} │ {v*100:>6.1f}% │ {r*100:>6.1f}% │ {y*100:>+7.1f}%"
|
|
255
|
+
f"{sym:<6} │ {w*100:>5.1f}% │ {v*100:>6.1f}% │ {r*100:>6.1f}% │ {y*100:>+7.1f}%"
|
|
229
256
|
)
|
|
230
257
|
|
|
231
258
|
port_vol = d.get("port_vol_ann", 0)
|
|
@@ -288,7 +315,10 @@ def _estimate_confidence(d: Dict) -> float:
|
|
|
288
315
|
def _build_key_points(d: Dict, verdict: str) -> List[str]:
|
|
289
316
|
pts = []
|
|
290
317
|
n = len(d.get("valid_symbols", []))
|
|
291
|
-
|
|
318
|
+
if d.get("weight_source") == "ledger":
|
|
319
|
+
pts.append(f"{n} 个标的,按真实持仓成本加权")
|
|
320
|
+
else:
|
|
321
|
+
pts.append(f"{n} 个标的,等权配置(无真实持仓数据,非实际风险暴露)")
|
|
292
322
|
|
|
293
323
|
port_vol = d.get("port_vol_ann", 0)
|
|
294
324
|
if port_vol:
|
|
@@ -10,7 +10,9 @@ agents/realty/asset_diagnosis.py — 资产诊断 Agent
|
|
|
10
10
|
|
|
11
11
|
输出:
|
|
12
12
|
analysis — 详细分析文本
|
|
13
|
-
signal —
|
|
13
|
+
signal — GOOD=推荐共创 / WATCH=需观察 / CONCERN=建议出租或出售
|
|
14
|
+
(地产健康度尺度,见 agents/signal_scheme.py::REALTY_SCHEME,
|
|
15
|
+
不是股票 BUY/SELL 那套交易动作词汇)
|
|
14
16
|
key_points — 3-5 条关键结论
|
|
15
17
|
"""
|
|
16
18
|
from __future__ import annotations
|
|
@@ -101,9 +103,9 @@ def _score_to_signal(asset: Dict, reno: float) -> str:
|
|
|
101
103
|
if state != "正常": score -= 2
|
|
102
104
|
if reno > rent * 24: score -= 1 # 改造成本超过2年租金则不划算
|
|
103
105
|
|
|
104
|
-
if score >= 4: return "
|
|
105
|
-
if score >= 2: return "
|
|
106
|
-
return "
|
|
106
|
+
if score >= 4: return "GOOD" # 非常适合共创
|
|
107
|
+
if score >= 2: return "WATCH" # 需进一步评估
|
|
108
|
+
return "CONCERN" # 建议传统出租或出售
|
|
107
109
|
|
|
108
110
|
|
|
109
111
|
def _calc_confidence(asset: Dict) -> float:
|
|
@@ -10,7 +10,8 @@ agents/realty/business_match.py — 业态匹配 Agent
|
|
|
10
10
|
|
|
11
11
|
输出:
|
|
12
12
|
analysis — 业态匹配建议
|
|
13
|
-
signal —
|
|
13
|
+
signal — GOOD=高度匹配 / WATCH=一般匹配 / CONCERN=低匹配
|
|
14
|
+
(地产健康度尺度,见 signal_scheme.py)
|
|
14
15
|
key_points — 推荐业态 Top3 + 理由
|
|
15
16
|
"""
|
|
16
17
|
from __future__ import annotations
|
|
@@ -115,9 +116,9 @@ def _match_signal(asset: Dict, market: Dict) -> str:
|
|
|
115
116
|
if market_score >= 7: score += 1
|
|
116
117
|
elif 0 < market_score <= 3: score -= 1
|
|
117
118
|
|
|
118
|
-
if score >= 4: return "
|
|
119
|
-
if score >= 2: return "
|
|
120
|
-
return "
|
|
119
|
+
if score >= 4: return "GOOD"
|
|
120
|
+
if score >= 2: return "WATCH"
|
|
121
|
+
return "CONCERN"
|
|
121
122
|
|
|
122
123
|
|
|
123
124
|
def _match_confidence(asset: Dict, market: Dict) -> float:
|
|
@@ -14,7 +14,8 @@ agents/realty/cashflow_verify.py — 流水核验 Agent
|
|
|
14
14
|
|
|
15
15
|
输出:
|
|
16
16
|
analysis — 核验报告
|
|
17
|
-
signal —
|
|
17
|
+
signal — GOOD=流水真实 / WATCH=轻度异常需复核 / CONCERN=疑似造假/私账
|
|
18
|
+
/ SEVERE=多项异常+差距极大(地产健康度尺度,见 signal_scheme.py)
|
|
18
19
|
key_points — 异常项目清单
|
|
19
20
|
"""
|
|
20
21
|
from __future__ import annotations
|
|
@@ -174,10 +175,10 @@ def _cross_verify(
|
|
|
174
175
|
def _verify_signal(check: Dict) -> str:
|
|
175
176
|
n = check.get("anomaly_count", 0)
|
|
176
177
|
gap = abs(check.get("gap_pct", 0))
|
|
177
|
-
if n == 0 and gap < 15: return "
|
|
178
|
-
if n <= 1 and gap < 30: return "
|
|
179
|
-
if n <= 2 and gap < 50: return "
|
|
180
|
-
return "
|
|
178
|
+
if n == 0 and gap < 15: return "GOOD"
|
|
179
|
+
if n <= 1 and gap < 30: return "WATCH"
|
|
180
|
+
if n <= 2 and gap < 50: return "CONCERN"
|
|
181
|
+
return "SEVERE"
|
|
181
182
|
|
|
182
183
|
|
|
183
184
|
def _verify_confidence(check: Dict) -> float:
|
|
@@ -10,7 +10,8 @@ agents/realty/contract_rules.py — 合同规则 Agent
|
|
|
10
10
|
|
|
11
11
|
输出:
|
|
12
12
|
analysis — 合同条款草案文本
|
|
13
|
-
signal —
|
|
13
|
+
signal — GOOD=条款清晰可执行 / WATCH=需补充条款 / CONCERN=有重大风险条款
|
|
14
|
+
(地产健康度尺度,见 signal_scheme.py)
|
|
14
15
|
key_points — 关键条款摘要(保底金额/分润比例/结算周期/违约条款)
|
|
15
16
|
"""
|
|
16
17
|
from __future__ import annotations
|
|
@@ -139,9 +140,9 @@ def _contract_signal(nego: Dict) -> str:
|
|
|
139
140
|
if not nego.get("settlement_cycle"): issues += 1
|
|
140
141
|
if not nego.get("contract_years"): issues += 1
|
|
141
142
|
|
|
142
|
-
if issues == 0: return "
|
|
143
|
-
if issues <= 2: return "
|
|
144
|
-
return "
|
|
143
|
+
if issues == 0: return "GOOD"
|
|
144
|
+
if issues <= 2: return "WATCH"
|
|
145
|
+
return "CONCERN"
|
|
145
146
|
|
|
146
147
|
|
|
147
148
|
def _contract_confidence(nego: Dict) -> float:
|
|
@@ -13,7 +13,8 @@ agents/realty/energy_anomaly.py — 能耗异常 Agent
|
|
|
13
13
|
|
|
14
14
|
输出:
|
|
15
15
|
analysis — 能耗分析报告
|
|
16
|
-
signal —
|
|
16
|
+
signal — GOOD=正常 / WATCH=轻度异常 / CONCERN=中度异常 / SEVERE=严重异常/疑似空置
|
|
17
|
+
(地产健康度尺度,见 signal_scheme.py)
|
|
17
18
|
key_points — 异常指标清单
|
|
18
19
|
"""
|
|
19
20
|
from __future__ import annotations
|
|
@@ -154,10 +155,10 @@ def _analyze_energy(
|
|
|
154
155
|
|
|
155
156
|
def _energy_signal(check: Dict) -> str:
|
|
156
157
|
n = check.get("anomaly_count", 0)
|
|
157
|
-
if n == 0: return "
|
|
158
|
-
if n == 1: return "
|
|
159
|
-
if n == 2: return "
|
|
160
|
-
return "
|
|
158
|
+
if n == 0: return "GOOD"
|
|
159
|
+
if n == 1: return "WATCH"
|
|
160
|
+
if n == 2: return "CONCERN"
|
|
161
|
+
return "SEVERE"
|
|
161
162
|
|
|
162
163
|
|
|
163
164
|
def _energy_confidence(check: Dict) -> float:
|
|
@@ -11,7 +11,8 @@ agents/realty/exit_settlement.py — 退出清算 Agent
|
|
|
11
11
|
|
|
12
12
|
输出:
|
|
13
13
|
analysis — 清算方案草案
|
|
14
|
-
signal —
|
|
14
|
+
signal — GOOD=清算顺利无纠纷 / WATCH=有待确认项 / CONCERN=存在较大争议
|
|
15
|
+
(地产健康度尺度,见 signal_scheme.py)
|
|
15
16
|
key_points — 各方清算金额摘要
|
|
16
17
|
data_used — 包含 settlement_result(结构化清算数据)
|
|
17
18
|
"""
|
|
@@ -145,12 +146,12 @@ def _calculate_settlement(
|
|
|
145
146
|
|
|
146
147
|
def _settlement_signal(s: Dict, reason: str) -> str:
|
|
147
148
|
if s["net_settlement"] > 0 and not s["is_breach"]:
|
|
148
|
-
return "
|
|
149
|
+
return "WATCH" # 经营方有欠款但无违约,需催收
|
|
149
150
|
if s["is_breach"] and s["net_settlement"] > 0:
|
|
150
|
-
return "
|
|
151
|
+
return "CONCERN" # 违约且有欠款
|
|
151
152
|
if s["operator_owes"] == 0 and s["platform_owes"] == 0:
|
|
152
|
-
return "
|
|
153
|
-
return "
|
|
153
|
+
return "GOOD" # 干净退出
|
|
154
|
+
return "WATCH"
|
|
154
155
|
|
|
155
156
|
|
|
156
157
|
def _settlement_confidence(fin: Dict) -> float:
|
|
@@ -12,7 +12,8 @@ agents/realty/fulfillment_risk.py — 履约风控 Agent
|
|
|
12
12
|
|
|
13
13
|
输出:
|
|
14
14
|
analysis — 风险报告
|
|
15
|
-
signal —
|
|
15
|
+
signal — GOOD=低风险 / WATCH=中等风险 / CONCERN=高风险 / SEVERE=极高风险
|
|
16
|
+
(地产健康度尺度,见 signal_scheme.py)
|
|
16
17
|
key_points — 风险事项清单(按级别)
|
|
17
18
|
"""
|
|
18
19
|
from __future__ import annotations
|
|
@@ -134,7 +135,7 @@ def _assess_risk(
|
|
|
134
135
|
|
|
135
136
|
# 5. 流水核验异常
|
|
136
137
|
cf_signal = cf.get("signal", "")
|
|
137
|
-
if cf_signal in ("
|
|
138
|
+
if cf_signal in ("CONCERN", "SEVERE"):
|
|
138
139
|
risk_items.append({"level": "高",
|
|
139
140
|
"desc": f"流水核验异常({cf.get('anomaly_summary','')}),需稽查"})
|
|
140
141
|
|
|
@@ -157,12 +158,12 @@ def _assess_risk(
|
|
|
157
158
|
|
|
158
159
|
|
|
159
160
|
def _risk_signal(risk: Dict) -> str:
|
|
160
|
-
if risk.get("has_extreme_risk"): return "
|
|
161
|
-
if risk.get("has_high_risk"): return "
|
|
161
|
+
if risk.get("has_extreme_risk"): return "SEVERE"
|
|
162
|
+
if risk.get("has_high_risk"): return "CONCERN"
|
|
162
163
|
mid_count = sum(1 for r in risk.get("risk_items", []) if r["level"] == "中")
|
|
163
|
-
if mid_count >= 2: return "
|
|
164
|
-
if mid_count >= 1: return "
|
|
165
|
-
return "
|
|
164
|
+
if mid_count >= 2: return "CONCERN"
|
|
165
|
+
if mid_count >= 1: return "WATCH"
|
|
166
|
+
return "GOOD"
|
|
166
167
|
|
|
167
168
|
|
|
168
169
|
def _risk_confidence(risk: Dict, invoices: List) -> float:
|
|
@@ -11,7 +11,8 @@ agents/realty/ops_optimize.py — 运营提升 Agent
|
|
|
11
11
|
|
|
12
12
|
输出:
|
|
13
13
|
analysis — 运营优化建议
|
|
14
|
-
signal —
|
|
14
|
+
signal — GOOD=经营健康/高潜力 / WATCH=有改善空间 / CONCERN=经营不佳 / SEVERE=急需干预
|
|
15
|
+
(地产健康度尺度,见 signal_scheme.py)
|
|
15
16
|
key_points — Top3 优化建议
|
|
16
17
|
"""
|
|
17
18
|
from __future__ import annotations
|
|
@@ -101,12 +102,12 @@ def _calc_metrics(project: Dict, perf: Dict, marketing: Dict, bench: Dict) -> Di
|
|
|
101
102
|
def _ops_signal(metrics: Dict, bench: Dict) -> str:
|
|
102
103
|
psm = metrics.get("revenue_per_sqm", 0)
|
|
103
104
|
bench_psm = metrics.get("bench_psm", 300)
|
|
104
|
-
if bench_psm <= 0: return "
|
|
105
|
+
if bench_psm <= 0: return "WATCH"
|
|
105
106
|
ratio = psm / bench_psm
|
|
106
|
-
if ratio >= 1.2: return "
|
|
107
|
-
if ratio >= 0.8: return "
|
|
108
|
-
if ratio >= 0.5: return "
|
|
109
|
-
return "
|
|
107
|
+
if ratio >= 1.2: return "GOOD"
|
|
108
|
+
if ratio >= 0.8: return "WATCH"
|
|
109
|
+
if ratio >= 0.5: return "CONCERN"
|
|
110
|
+
return "SEVERE"
|
|
110
111
|
|
|
111
112
|
|
|
112
113
|
def _ops_confidence(perf: Dict, marketing: Dict) -> float:
|
|
@@ -10,7 +10,8 @@ agents/realty/revenue_share.py — 分账规则 Agent
|
|
|
10
10
|
|
|
11
11
|
输出:
|
|
12
12
|
analysis — 分账计算说明文本
|
|
13
|
-
signal —
|
|
13
|
+
signal — GOOD=分账正常 / WATCH=有补足情况 / CONCERN=流水勉强覆盖 / SEVERE=流水严重不足
|
|
14
|
+
(地产健康度尺度,见 signal_scheme.py)
|
|
14
15
|
key_points — 各方金额摘要
|
|
15
16
|
data_used — 包含 split_result(可直接入库)
|
|
16
17
|
"""
|
|
@@ -159,12 +160,12 @@ def _split_signal(split: Dict) -> str:
|
|
|
159
160
|
guaranteed = split.get("guaranteed", 0)
|
|
160
161
|
op_net = split.get("operator_net", 0)
|
|
161
162
|
|
|
162
|
-
if guaranteed <= 0: return "
|
|
163
|
+
if guaranteed <= 0: return "WATCH"
|
|
163
164
|
coverage = net / guaranteed if guaranteed else 0
|
|
164
|
-
if coverage >= 2.0 and op_net > 0: return "
|
|
165
|
-
if coverage >= 1.0 and op_net > 0: return "
|
|
166
|
-
if op_net > 0 and coverage >= 0.5: return "
|
|
167
|
-
return "
|
|
165
|
+
if coverage >= 2.0 and op_net > 0: return "GOOD"
|
|
166
|
+
if coverage >= 1.0 and op_net > 0: return "WATCH"
|
|
167
|
+
if op_net > 0 and coverage >= 0.5: return "CONCERN" # 经营方能勉强覆盖
|
|
168
|
+
return "SEVERE" # 经营方净收入为负或流水极低
|
|
168
169
|
|
|
169
170
|
|
|
170
171
|
def _split_status(split: Dict) -> str:
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""
|
|
2
|
+
agents/signal_scheme.py — 领域可插拔的信号词汇表
|
|
3
|
+
====================================================
|
|
4
|
+
team.py 里的表决(_vote_signal)、辩论触发(_needs_debate)原本硬编码了金融的
|
|
5
|
+
BUY/HOLD/SELL/STRONG_BUY/STRONG_SELL 五级词汇。realty 的 9 个 agent 长期以来
|
|
6
|
+
借用同一套词汇表达完全不同的含义(BUY=推荐共创、流水真实、条款清晰、低风险……
|
|
7
|
+
每个文件的 BUY 意思都不一样,只在各自 docstring 里注明),靠 aria_cli.py 里
|
|
8
|
+
一张 _SIGNAL_LABELS 翻译表在展示层补救。这意味着一旦有人把多个 realty agent
|
|
9
|
+
接进 AgentTeam 做 vote/debate(cashflow_verify 的 SELL=疑似造假 和
|
|
10
|
+
ops_optimize 的 SELL=经营不佳需干预 完全不是同一个维度),_vote_signal 会把
|
|
11
|
+
它们当同一根多空轴数值平均,产出一个语义上没有意义的"共识"。
|
|
12
|
+
|
|
13
|
+
SignalScheme 把这套词汇表和打分/辩论触发规则抽成领域可配置的对象,
|
|
14
|
+
AgentTeam 默认用 FINANCIAL_SCHEME(对现有金融调用方零行为变化),
|
|
15
|
+
其他领域注册自己的词汇表即可复用同一套并行/表决/辩论/synthesis 编排逻辑,
|
|
16
|
+
而不必借用金融的 BUY/SELL 语义或答案词不达意。
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
from dataclasses import dataclass
|
|
22
|
+
from typing import Dict, List, Tuple
|
|
23
|
+
|
|
24
|
+
from .base import AgentResult
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass(frozen=True)
|
|
28
|
+
class SignalScheme:
|
|
29
|
+
"""一套领域信号词汇表:多空打分 + 辩论触发条件。
|
|
30
|
+
|
|
31
|
+
upper_thresholds / lower_thresholds 特意分成两条腿而不是一条单向扫描的
|
|
32
|
+
区间列表——原始金融判定逻辑本身就是两段非对称的边界(上方 >= 含右端点,
|
|
33
|
+
下方 <= 含左端点,中间落空隙才算 neutral_default),一条单向 >= 扫描的
|
|
34
|
+
区间列表没法同时正确表达"上方含端点"和"下方也含端点"这两种边界方向,
|
|
35
|
+
会把 avg_score=0 这种中性分数错误地吃进最负的那个区间(已在 fuzz 测试里
|
|
36
|
+
实测过这个 bug:单向列表版本对 avg_score=0 的输入返回了 STRONG_SELL)。
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
name: str
|
|
40
|
+
# 信号 → 打分(用于表决时按置信度加权平均);分数越高越"正面"。
|
|
41
|
+
scores: Dict[str, int]
|
|
42
|
+
# 从高到低排列;第一个满足 avg_score >= threshold 的胜出。
|
|
43
|
+
upper_thresholds: List[Tuple[float, str]]
|
|
44
|
+
# 按"最极端优先"排列(比如先检查 <=-1.5 再检查 <=-0.5);
|
|
45
|
+
# 第一个满足 avg_score <= threshold 的胜出。
|
|
46
|
+
lower_thresholds: List[Tuple[float, str]]
|
|
47
|
+
# 触发 debate 的两组信号(出现其一 + 另一组其一即触发,比如金融的"多"与"空")
|
|
48
|
+
positive_signals: frozenset
|
|
49
|
+
negative_signals: frozenset
|
|
50
|
+
neutral_default: str = "HOLD"
|
|
51
|
+
|
|
52
|
+
def vote(self, results: List[AgentResult]) -> Tuple[str, float]:
|
|
53
|
+
valid = [r for r in results if r.success and r.signal in self.scores]
|
|
54
|
+
if not valid:
|
|
55
|
+
return self.neutral_default, 0.0
|
|
56
|
+
avg_score = sum(self.scores[r.signal] * r.confidence for r in valid) / len(valid)
|
|
57
|
+
avg_conf = sum(r.confidence for r in valid) / len(valid)
|
|
58
|
+
for threshold, label in self.upper_thresholds:
|
|
59
|
+
if avg_score >= threshold:
|
|
60
|
+
return label, avg_conf
|
|
61
|
+
for threshold, label in self.lower_thresholds:
|
|
62
|
+
if avg_score <= threshold:
|
|
63
|
+
return label, avg_conf
|
|
64
|
+
return self.neutral_default, avg_conf
|
|
65
|
+
|
|
66
|
+
def needs_debate(self, results: List[AgentResult]) -> bool:
|
|
67
|
+
signals = [r.signal for r in results if r.success and r.signal]
|
|
68
|
+
has_positive = any(s in self.positive_signals for s in signals)
|
|
69
|
+
has_negative = any(s in self.negative_signals for s in signals)
|
|
70
|
+
return has_positive and has_negative
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
# ── 金融:既有行为,原样保留(upper/lower 拆分精确复刻原 if/elif 分支)────────
|
|
74
|
+
FINANCIAL_SCHEME = SignalScheme(
|
|
75
|
+
name="financial",
|
|
76
|
+
scores={"STRONG_BUY": 2, "BUY": 1, "HOLD": 0, "SELL": -1, "STRONG_SELL": -2},
|
|
77
|
+
upper_thresholds=[(1.5, "STRONG_BUY"), (0.5, "BUY")],
|
|
78
|
+
lower_thresholds=[(-1.5, "STRONG_SELL"), (-0.5, "SELL")],
|
|
79
|
+
positive_signals=frozenset({"BUY", "STRONG_BUY"}),
|
|
80
|
+
negative_signals=frozenset({"SELL", "STRONG_SELL"}),
|
|
81
|
+
neutral_default="HOLD",
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
# ── 地产资管:健康度评估,不是交易动作 ──────────────────────────────────────
|
|
85
|
+
# GOOD/WATCH/CONCERN/SEVERE —— 这条轴描述"这个维度是否健康",不是"要不要买"。
|
|
86
|
+
# 9 个 realty agent 各自评估不同维度(流水真实性、合同风险、能耗异常、履约风险
|
|
87
|
+
# 等),但共享同一个"健康 → 需关注 → 有问题 → 严重"的四级尺度,用领域自己的
|
|
88
|
+
# 词汇表述比借用股票的 BUY/SELL 更准确,也让 vote/debate 的语义站得住脚。
|
|
89
|
+
REALTY_SCHEME = SignalScheme(
|
|
90
|
+
name="realty",
|
|
91
|
+
scores={"GOOD": 2, "WATCH": 0, "CONCERN": -1, "SEVERE": -2},
|
|
92
|
+
upper_thresholds=[(1.0, "GOOD")],
|
|
93
|
+
lower_thresholds=[(-1.5, "SEVERE"), (-0.5, "CONCERN")],
|
|
94
|
+
positive_signals=frozenset({"GOOD"}),
|
|
95
|
+
negative_signals=frozenset({"CONCERN", "SEVERE"}),
|
|
96
|
+
neutral_default="WATCH",
|
|
97
|
+
)
|
|
@@ -1,7 +1,23 @@
|
|
|
1
1
|
"""
|
|
2
2
|
agents/sports/football_agent.py — Football Analysis Agent
|
|
3
3
|
===========================================================
|
|
4
|
-
LLM-powered football match analysis using
|
|
4
|
+
LLM-powered football match analysis using Elo + Dixon-Coles prediction + form data.
|
|
5
|
+
|
|
6
|
+
Prediction comes from packages.quant_engine.sports.predictor (Elo ratings,
|
|
7
|
+
Dixon-Coles with negative-binomial tail for lopsided matches, dynamic
|
|
8
|
+
Elo/DC mixing weights, recency-form and head-to-head adjustments, and
|
|
9
|
+
self-calibration), not football_data_client.predict_match — that function
|
|
10
|
+
is a much simpler independent-Poisson model over a static, hand-maintained
|
|
11
|
+
attack/defense lookup table with a flat home-advantage constant, no
|
|
12
|
+
Dixon-Coles low-score correlation correction, and no Elo. Verified the two
|
|
13
|
+
disagree by double digits on some matchups (13.1pp on a real fixture) rather
|
|
14
|
+
than assuming the richer model is worth switching to on faith.
|
|
15
|
+
|
|
16
|
+
football_data_client itself is left untouched — aria_feishu_bot.py calls
|
|
17
|
+
predict_match directly and has its own tested formatting/localization
|
|
18
|
+
pinned to that function's exact output, which is out of scope here. Only
|
|
19
|
+
get_team_stats() (recent-form text, not part of either prediction model)
|
|
20
|
+
is still sourced from football_data_client.
|
|
5
21
|
"""
|
|
6
22
|
|
|
7
23
|
from __future__ import annotations
|
|
@@ -61,10 +77,19 @@ class FootballAgent:
|
|
|
61
77
|
away_team: str,
|
|
62
78
|
league: str = "pl",
|
|
63
79
|
with_llm: bool = True,
|
|
80
|
+
neutral_venue: bool = False,
|
|
64
81
|
) -> MatchPrediction:
|
|
65
|
-
from football_data_client import
|
|
66
|
-
|
|
67
|
-
|
|
82
|
+
from football_data_client import get_team_stats
|
|
83
|
+
from packages.quant_engine.sports.predictor import quick_predict
|
|
84
|
+
|
|
85
|
+
# neutral_venue defaults False: club leagues (pl/bl1/sa/pd/fl1, the
|
|
86
|
+
# default `league="pl"`) really do have a home team playing at home.
|
|
87
|
+
# Pass True for a genuinely neutral-site fixture (e.g. a World Cup
|
|
88
|
+
# group match at a third country's stadium).
|
|
89
|
+
raw = quick_predict(home_team, away_team, league, neutral_venue=neutral_venue)
|
|
90
|
+
raw["most_likely_score"] = (
|
|
91
|
+
raw["top_scorelines"][0]["score"] if raw.get("top_scorelines") else "0-0"
|
|
92
|
+
)
|
|
68
93
|
h_stats = get_team_stats(league, home_team)
|
|
69
94
|
a_stats = get_team_stats(league, away_team)
|
|
70
95
|
|
|
@@ -73,7 +98,10 @@ class FootballAgent:
|
|
|
73
98
|
key_factors.append(f"{home_team} 近5场: {h_stats['form']} (场均进球 {h_stats['avg_gf']})")
|
|
74
99
|
if a_stats:
|
|
75
100
|
key_factors.append(f"{away_team} 近5场: {a_stats['form']} (场均进球 {a_stats['avg_gf']})")
|
|
76
|
-
key_factors.append(
|
|
101
|
+
key_factors.append(
|
|
102
|
+
f"模型: {raw['model']} Elo差: {raw['elo_diff']:+.0f}"
|
|
103
|
+
f" (DC权重{raw['w_dc']:.0%}/Elo权重{raw['w_elo']:.0%})"
|
|
104
|
+
)
|
|
77
105
|
|
|
78
106
|
analysis = ""
|
|
79
107
|
if with_llm and self._llm:
|