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,135 @@
|
|
|
1
|
+
"""Auditable freight analysis from supplied waybills or an existing local database."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import csv
|
|
6
|
+
import json
|
|
7
|
+
import math
|
|
8
|
+
import pathlib
|
|
9
|
+
import sqlite3
|
|
10
|
+
from collections import defaultdict
|
|
11
|
+
from contextlib import closing
|
|
12
|
+
from typing import Any, Dict, List
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _number(record: dict[str, Any], field: str, row: int, *, required: bool = False) -> float | None:
|
|
16
|
+
value = record.get(field)
|
|
17
|
+
if value is None or value == "":
|
|
18
|
+
if required:
|
|
19
|
+
raise ValueError(f"Row {row}: {field} is required")
|
|
20
|
+
return None
|
|
21
|
+
if isinstance(value, bool):
|
|
22
|
+
raise ValueError(f"Row {row}: {field} must be a number")
|
|
23
|
+
try:
|
|
24
|
+
number = float(value)
|
|
25
|
+
except (TypeError, ValueError) as exc:
|
|
26
|
+
raise ValueError(f"Row {row}: {field} must be a number") from exc
|
|
27
|
+
if not math.isfinite(number) or number < 0:
|
|
28
|
+
raise ValueError(f"Row {row}: {field} must be finite and non-negative")
|
|
29
|
+
return number
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _on_time(value: Any, row: int) -> bool | None:
|
|
33
|
+
if value is None or value == "":
|
|
34
|
+
return None
|
|
35
|
+
if isinstance(value, bool):
|
|
36
|
+
return value
|
|
37
|
+
if value in (0, 1):
|
|
38
|
+
return bool(value)
|
|
39
|
+
if isinstance(value, str):
|
|
40
|
+
normalized = value.strip().lower()
|
|
41
|
+
if normalized in {"true", "yes", "1"}:
|
|
42
|
+
return True
|
|
43
|
+
if normalized in {"false", "no", "0"}:
|
|
44
|
+
return False
|
|
45
|
+
raise ValueError(f"Row {row}: is_on_time must be a boolean")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def tool_analyze_logistics_data(params: Dict[str, Any]) -> Dict[str, Any]:
|
|
49
|
+
"""Analyze actual records. Empty input never produces representative data."""
|
|
50
|
+
try:
|
|
51
|
+
file_path = params.get("file_path")
|
|
52
|
+
records = params.get("waybills")
|
|
53
|
+
if file_path and records is not None:
|
|
54
|
+
raise ValueError("Provide either file_path or waybills, not both")
|
|
55
|
+
if file_path:
|
|
56
|
+
path = pathlib.Path(file_path).expanduser().resolve()
|
|
57
|
+
if path.suffix.lower() == ".json":
|
|
58
|
+
content = json.loads(path.read_text(encoding="utf-8"))
|
|
59
|
+
records = content if isinstance(content, list) else content.get("waybills") if isinstance(content, dict) else None
|
|
60
|
+
elif path.suffix.lower() == ".csv":
|
|
61
|
+
with path.open(encoding="utf-8-sig", newline="") as handle:
|
|
62
|
+
records = list(csv.DictReader(handle))
|
|
63
|
+
else:
|
|
64
|
+
raise ValueError("Only CSV and JSON waybill files are supported")
|
|
65
|
+
source = str(path)
|
|
66
|
+
data_source = f"file:{path.name}"
|
|
67
|
+
elif records is None:
|
|
68
|
+
path = pathlib.Path.home() / ".aria" / "erp_warehouse.db"
|
|
69
|
+
if not path.is_file():
|
|
70
|
+
raise ValueError("No waybills supplied and no local logistics database found")
|
|
71
|
+
with closing(sqlite3.connect(f"{path.as_uri()}?mode=ro", uri=True)) as connection:
|
|
72
|
+
connection.row_factory = sqlite3.Row
|
|
73
|
+
records = [dict(row) for row in connection.execute("SELECT * FROM logistics_waybills")]
|
|
74
|
+
source = str(path)
|
|
75
|
+
data_source = "local logistics database"
|
|
76
|
+
else:
|
|
77
|
+
source = "provided_waybills"
|
|
78
|
+
data_source = "caller-supplied records"
|
|
79
|
+
|
|
80
|
+
if not isinstance(records, list) or not records:
|
|
81
|
+
raise ValueError("No waybill records available for analysis")
|
|
82
|
+
|
|
83
|
+
spend = 0.0
|
|
84
|
+
known_delivery = 0
|
|
85
|
+
on_time = 0
|
|
86
|
+
carriers: dict[str, dict[str, Any]] = defaultdict(lambda: {"count": 0, "total_spend": 0.0, "known_delivery_count": 0, "on_time_count": 0})
|
|
87
|
+
anomalies: list[dict[str, Any]] = []
|
|
88
|
+
for row, record in enumerate(records, 1):
|
|
89
|
+
if not isinstance(record, dict):
|
|
90
|
+
raise ValueError(f"Row {row}: waybill must be an object")
|
|
91
|
+
cost = _number(record, "total_cost", row, required=True)
|
|
92
|
+
assert cost is not None
|
|
93
|
+
actual = _number(record, "actual_weight_kg", row)
|
|
94
|
+
billed = _number(record, "billed_weight_kg", row)
|
|
95
|
+
timely = _on_time(record.get("is_on_time"), row)
|
|
96
|
+
carrier = str(record.get("carrier") or "Unknown")
|
|
97
|
+
spend += cost
|
|
98
|
+
carriers[carrier]["count"] += 1
|
|
99
|
+
carriers[carrier]["total_spend"] += cost
|
|
100
|
+
if timely is not None:
|
|
101
|
+
known_delivery += 1
|
|
102
|
+
on_time += int(timely)
|
|
103
|
+
carriers[carrier]["known_delivery_count"] += 1
|
|
104
|
+
carriers[carrier]["on_time_count"] += int(timely)
|
|
105
|
+
if actual is not None and billed is not None and actual > 0 and billed > actual * 1.2:
|
|
106
|
+
anomalies.append({"waybill_no": record.get("waybill_no"), "carrier": carrier, "actual_weight_kg": actual, "billed_weight_kg": billed, "reason": "Billed weight exceeds actual weight by more than 20%; verify dimensional weight before disputing"})
|
|
107
|
+
|
|
108
|
+
metrics = []
|
|
109
|
+
for carrier, item in sorted(carriers.items()):
|
|
110
|
+
item["total_spend"] = round(item["total_spend"], 2)
|
|
111
|
+
item["on_time_rate"] = round(item["on_time_count"] / item["known_delivery_count"] * 100, 2) if item["known_delivery_count"] else None
|
|
112
|
+
metrics.append({"carrier": carrier, **item})
|
|
113
|
+
rate = round(on_time / known_delivery * 100, 2) if known_delivery else None
|
|
114
|
+
result = {"total_waybills": len(records), "total_freight_spend": round(spend, 2), "overall_on_time_rate": rate, "known_delivery_count": known_delivery, "carrier_metrics": metrics, "billing_anomalies": anomalies, "data_source": data_source}
|
|
115
|
+
rate_label = f"{rate}%" if rate is not None else "不可得(无准时状态记录)"
|
|
116
|
+
return {"success": True, "data": result, "source": source, "summary": f"已审计 {len(records)} 单运单(来源:{data_source}),运费总计 ¥{spend:,.2f},已知准时交付率 {rate_label},发现 {len(anomalies)} 笔需核实的计费重量异常。"}
|
|
117
|
+
except (OSError, sqlite3.Error, ValueError, TypeError, json.JSONDecodeError) as exc:
|
|
118
|
+
return {"success": False, "error": str(exc)}
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def register_logistics_tools(tools_dict: Dict[str, Any], schemas_list: List[Dict[str, Any]]) -> int:
|
|
122
|
+
"""Register the waybill analyzer as a local tool."""
|
|
123
|
+
tools_dict["analyze_logistics_data"] = (tool_analyze_logistics_data, "Analyze supplied freight waybills and billing anomalies")
|
|
124
|
+
schemas_list.append({
|
|
125
|
+
"name": "analyze_logistics_data",
|
|
126
|
+
"description": "Analyze actual waybills from supplied records, a CSV/JSON file, or an existing local database",
|
|
127
|
+
"parameters": {
|
|
128
|
+
"type": "object",
|
|
129
|
+
"properties": {
|
|
130
|
+
"file_path": {"type": "string", "description": "CSV or JSON waybill file path"},
|
|
131
|
+
"waybills": {"type": "array", "description": "Waybill records with total_cost"},
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
})
|
|
135
|
+
return 1
|
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
"""
|
|
2
|
+
macro_tools.py — 宏观经济数据层
|
|
3
|
+
=================================
|
|
4
|
+
来源:
|
|
5
|
+
- FRED (美联储 St. Louis) — GDP, CPI, 联邦基金利率, 失业率, M2
|
|
6
|
+
- AKShare — 中国 CPI/PPI/PMI/GDP/LPR/社融
|
|
7
|
+
- yfinance — 全球央行政策利率(备用)
|
|
8
|
+
|
|
9
|
+
全部函数返回 {"success": bool, "data": [...], ...} 格式,
|
|
10
|
+
与 local_finance_tools 保持一致。
|
|
11
|
+
|
|
12
|
+
依赖安装(可选):
|
|
13
|
+
pip install requests # FRED REST API
|
|
14
|
+
pip install akshare # 中国数据
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import logging
|
|
20
|
+
import os
|
|
21
|
+
from datetime import datetime, timedelta
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
from typing import Any, Dict, List, Optional
|
|
24
|
+
from aria_code.packages.aria_core.paths import aria_home
|
|
25
|
+
|
|
26
|
+
logger = logging.getLogger(__name__)
|
|
27
|
+
|
|
28
|
+
# ── Optional imports ──────────────────────────────────────────────────────────
|
|
29
|
+
|
|
30
|
+
try:
|
|
31
|
+
import requests as _req
|
|
32
|
+
_HAS_REQUESTS = True
|
|
33
|
+
except ImportError:
|
|
34
|
+
_HAS_REQUESTS = False
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
import akshare as ak
|
|
38
|
+
_HAS_AK = True
|
|
39
|
+
except ImportError:
|
|
40
|
+
_HAS_AK = False
|
|
41
|
+
|
|
42
|
+
try:
|
|
43
|
+
import pandas as pd
|
|
44
|
+
_HAS_PD = True
|
|
45
|
+
except ImportError:
|
|
46
|
+
_HAS_PD = False
|
|
47
|
+
|
|
48
|
+
# ── FRED API helper ──────────────────────────────────────────────────────────
|
|
49
|
+
|
|
50
|
+
FRED_BASE = "https://fred.stlouisfed.org/graph/fredgraph.csv"
|
|
51
|
+
FRED_API_BASE = "https://api.stlouisfed.org/fred"
|
|
52
|
+
|
|
53
|
+
def _get_fred_key() -> str:
|
|
54
|
+
"""Read FRED API key from env or ~/.arthera/providers.json."""
|
|
55
|
+
key = os.getenv("FRED_API_KEY", "")
|
|
56
|
+
if not key:
|
|
57
|
+
try:
|
|
58
|
+
import json
|
|
59
|
+
p = aria_home() / "providers.json"
|
|
60
|
+
if p.exists():
|
|
61
|
+
d = json.loads(p.read_text())
|
|
62
|
+
key = d.get("fred", {}).get("api_key", "") or d.get("fred_api_key", "")
|
|
63
|
+
except Exception:
|
|
64
|
+
pass
|
|
65
|
+
return key
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _fred_series(series_id: str, limit: int = 24, units: str = "") -> List[Dict]:
|
|
69
|
+
"""Fetch a FRED data series. Returns list of {date, value} dicts.
|
|
70
|
+
|
|
71
|
+
``units`` maps to FRED's units transformation, e.g. "pc1" = percent change
|
|
72
|
+
from a year ago (used for YoY rates like CPI inflation, so we don't show
|
|
73
|
+
the raw index level mislabelled as a percentage).
|
|
74
|
+
"""
|
|
75
|
+
if not _HAS_REQUESTS:
|
|
76
|
+
return []
|
|
77
|
+
key = _get_fred_key()
|
|
78
|
+
try:
|
|
79
|
+
params: Dict[str, Any] = {
|
|
80
|
+
"series_id": series_id,
|
|
81
|
+
"limit": limit,
|
|
82
|
+
"sort_order": "desc",
|
|
83
|
+
"file_type": "json",
|
|
84
|
+
}
|
|
85
|
+
if units:
|
|
86
|
+
params["units"] = units
|
|
87
|
+
if key:
|
|
88
|
+
params["api_key"] = key
|
|
89
|
+
url = f"{FRED_API_BASE}/series/observations"
|
|
90
|
+
r = _req.get(url, params=params, timeout=8)
|
|
91
|
+
r.raise_for_status()
|
|
92
|
+
obs = r.json().get("observations", [])
|
|
93
|
+
return [
|
|
94
|
+
{"date": o["date"], "value": float(o["value"]) if o["value"] != "." else None}
|
|
95
|
+
for o in reversed(obs)
|
|
96
|
+
]
|
|
97
|
+
else:
|
|
98
|
+
# Public CSV endpoint (no key needed, slower). fredgraph supports
|
|
99
|
+
# transformation codes via the `transformation` query param.
|
|
100
|
+
obs_url = f"https://fred.stlouisfed.org/graph/fredgraph.csv?id={series_id}"
|
|
101
|
+
if units:
|
|
102
|
+
obs_url += f"&transformation={units}"
|
|
103
|
+
r = _req.get(obs_url, timeout=10)
|
|
104
|
+
r.raise_for_status()
|
|
105
|
+
lines = r.text.strip().split("\n")[1:] # skip header
|
|
106
|
+
result = []
|
|
107
|
+
for line in lines[-limit:]:
|
|
108
|
+
parts = line.split(",")
|
|
109
|
+
if len(parts) == 2:
|
|
110
|
+
try:
|
|
111
|
+
result.append({"date": parts[0], "value": float(parts[1])})
|
|
112
|
+
except ValueError:
|
|
113
|
+
pass
|
|
114
|
+
return result
|
|
115
|
+
except Exception as e:
|
|
116
|
+
logger.debug("FRED fetch %s failed: %s", series_id, e)
|
|
117
|
+
return []
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
# ── US Macro ──────────────────────────────────────────────────────────────────
|
|
121
|
+
|
|
122
|
+
_FRED_SERIES_MAP = {
|
|
123
|
+
"gdp": ("GDP", "GDP 实际值 (十亿美元, 季度)", "B"),
|
|
124
|
+
"gdp_growth": ("A191RL1Q225SBEA", "GDP 同比增速 (%)", "%"),
|
|
125
|
+
"cpi": ("CPIAUCSL", "CPI 城市消费者价格指数", "idx"),
|
|
126
|
+
"cpi_yoy": ("CPIAUCSL", "CPI 同比 (%)", "%", "pc1"), # pc1 = YoY %
|
|
127
|
+
"core_cpi_yoy": ("CPILFESL", "核心 CPI 同比 (%)", "%", "pc1"),
|
|
128
|
+
"core_cpi": ("CPILFESL", "核心 CPI (剔除食品能源)", "idx"),
|
|
129
|
+
"pce": ("PCEPI", "PCE 通胀指数", "idx"),
|
|
130
|
+
"fed_rate": ("FEDFUNDS", "联邦基金利率 (%)", "%"),
|
|
131
|
+
"unemployment": ("UNRATE", "美国失业率 (%)", "%"),
|
|
132
|
+
"m2": ("M2SL", "M2 货币供给 (十亿美元)", "B"),
|
|
133
|
+
"10y_yield": ("DGS10", "10年期国债收益率 (%)", "%"),
|
|
134
|
+
"2y_yield": ("DGS2", "2年期国债收益率 (%)", "%"),
|
|
135
|
+
"vix": ("VIXCLS", "VIX 恐慌指数", ""),
|
|
136
|
+
"retail_sales": ("RSAFS", "零售销售额 (百万美元, 季调)", "M"),
|
|
137
|
+
"industrial": ("INDPRO", "工业产出指数", "idx"),
|
|
138
|
+
"housing": ("HOUST", "新屋开工 (千套, 季调年化)", "K"),
|
|
139
|
+
"ppi": ("PPIACO", "PPI 生产者价格指数", "idx"),
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def get_us_macro(indicator: str = "all", periods: int = 12) -> dict:
|
|
144
|
+
"""
|
|
145
|
+
获取美国宏观经济数据。
|
|
146
|
+
|
|
147
|
+
indicator: "gdp" | "cpi" | "fed_rate" | "unemployment" | "m2" |
|
|
148
|
+
"10y_yield" | "retail_sales" | "all"
|
|
149
|
+
periods: 返回最近 N 期数据
|
|
150
|
+
"""
|
|
151
|
+
if indicator == "all":
|
|
152
|
+
keys = ["gdp_growth", "cpi_yoy", "fed_rate", "unemployment", "10y_yield",
|
|
153
|
+
"2y_yield", "m2", "ppi"]
|
|
154
|
+
else:
|
|
155
|
+
keys = [indicator] if indicator in _FRED_SERIES_MAP else []
|
|
156
|
+
if not keys:
|
|
157
|
+
return {"success": False, "error": f"未知指标: {indicator}。可选: {', '.join(_FRED_SERIES_MAP)}"}
|
|
158
|
+
|
|
159
|
+
results = {}
|
|
160
|
+
for key in keys:
|
|
161
|
+
_spec = _FRED_SERIES_MAP[key]
|
|
162
|
+
series_id, label, unit = _spec[0], _spec[1], _spec[2]
|
|
163
|
+
_units = _spec[3] if len(_spec) > 3 else ""
|
|
164
|
+
# pc1 (YoY) needs ~13 months of monthly data to compute the first point
|
|
165
|
+
_lim = max(periods, 14) if _units == "pc1" else periods
|
|
166
|
+
data = _fred_series(series_id, limit=_lim, units=_units)
|
|
167
|
+
if data:
|
|
168
|
+
latest = data[-1]
|
|
169
|
+
prev = data[-2] if len(data) >= 2 else None
|
|
170
|
+
change = None
|
|
171
|
+
if latest["value"] is not None and prev and prev["value"] is not None:
|
|
172
|
+
change = round(latest["value"] - prev["value"], 3)
|
|
173
|
+
results[key] = {
|
|
174
|
+
"label": label,
|
|
175
|
+
"unit": unit,
|
|
176
|
+
"latest": latest,
|
|
177
|
+
"prev": prev,
|
|
178
|
+
"change": change,
|
|
179
|
+
"series": data[-6:], # last 6 periods for sparkline
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if not results:
|
|
183
|
+
return {"success": False, "error": "FRED 数据获取失败(无 API Key 时使用公共 CSV 端点,速度较慢)"}
|
|
184
|
+
|
|
185
|
+
# Yield curve shape
|
|
186
|
+
if "10y_yield" in results and "2y_yield" in results:
|
|
187
|
+
v10 = results["10y_yield"]["latest"]["value"] or 0
|
|
188
|
+
v2 = results["2y_yield"]["latest"]["value"] or 0
|
|
189
|
+
spread = round(v10 - v2, 3)
|
|
190
|
+
results["_yield_curve"] = {
|
|
191
|
+
"spread_10y_2y": spread,
|
|
192
|
+
"shape": "正常" if spread > 0.2 else "倒挂" if spread < 0 else "平坦",
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return {"success": True, "country": "US", "indicator": indicator,
|
|
196
|
+
"data": results, "provider": "FRED"}
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
# ── China Macro ───────────────────────────────────────────────────────────────
|
|
200
|
+
|
|
201
|
+
def get_cn_macro(indicator: str = "all") -> dict:
|
|
202
|
+
"""
|
|
203
|
+
获取中国宏观经济数据 (via akshare)。
|
|
204
|
+
|
|
205
|
+
indicator: "cpi" | "ppi" | "pmi" | "gdp" | "lpr" | "m2" | "all"
|
|
206
|
+
"""
|
|
207
|
+
if not _HAS_AK:
|
|
208
|
+
return {"success": False, "error": "akshare 未安装,请运行: pip install akshare"}
|
|
209
|
+
|
|
210
|
+
results = {}
|
|
211
|
+
|
|
212
|
+
def _fetch(fn, key, label):
|
|
213
|
+
try:
|
|
214
|
+
df = fn()
|
|
215
|
+
if df is None or (hasattr(df, "empty") and df.empty):
|
|
216
|
+
return
|
|
217
|
+
# Keep last 12 rows
|
|
218
|
+
df = df.tail(12)
|
|
219
|
+
records = df.to_dict("records") if _HAS_PD else []
|
|
220
|
+
latest = records[-1] if records else {}
|
|
221
|
+
results[key] = {"label": label, "latest": latest, "series": records}
|
|
222
|
+
except Exception as e:
|
|
223
|
+
logger.debug("akshare %s failed: %s", key, e)
|
|
224
|
+
|
|
225
|
+
if indicator in ("cpi", "all"):
|
|
226
|
+
_fetch(ak.macro_china_cpi_yearly, "cpi", "中国 CPI 同比 (%)")
|
|
227
|
+
|
|
228
|
+
if indicator in ("ppi", "all"):
|
|
229
|
+
_fetch(ak.macro_china_ppi_yearly, "ppi", "中国 PPI 同比 (%)")
|
|
230
|
+
|
|
231
|
+
if indicator in ("pmi", "all"):
|
|
232
|
+
_fetch(ak.macro_china_pmi_yearly, "pmi_manufacturing",
|
|
233
|
+
"制造业 PMI")
|
|
234
|
+
try:
|
|
235
|
+
df_s = ak.macro_china_non_man_pmi()
|
|
236
|
+
if df_s is not None and not df_s.empty:
|
|
237
|
+
records_s = df_s.tail(12).to_dict("records")
|
|
238
|
+
results["pmi_service"] = {
|
|
239
|
+
"label": "非制造业 PMI",
|
|
240
|
+
"latest": records_s[-1] if records_s else {},
|
|
241
|
+
"series": records_s,
|
|
242
|
+
}
|
|
243
|
+
except Exception:
|
|
244
|
+
pass
|
|
245
|
+
|
|
246
|
+
if indicator in ("gdp", "all"):
|
|
247
|
+
_fetch(ak.macro_china_gdp_yearly, "gdp", "中国 GDP 同比增速 (%)")
|
|
248
|
+
|
|
249
|
+
if indicator in ("lpr", "all"):
|
|
250
|
+
try:
|
|
251
|
+
df_lpr = ak.macro_china_lpr()
|
|
252
|
+
if df_lpr is not None and not df_lpr.empty:
|
|
253
|
+
records_l = df_lpr.tail(6).to_dict("records")
|
|
254
|
+
results["lpr"] = {"label": "LPR 利率", "series": records_l,
|
|
255
|
+
"latest": records_l[-1] if records_l else {}}
|
|
256
|
+
except Exception as e:
|
|
257
|
+
logger.debug("LPR fetch failed: %s", e)
|
|
258
|
+
|
|
259
|
+
if indicator in ("m2", "all"):
|
|
260
|
+
_fetch(ak.macro_china_money_supply, "m2", "中国 M2 同比增速 (%)")
|
|
261
|
+
|
|
262
|
+
if not results:
|
|
263
|
+
return {"success": False, "error": "未能获取任何中国宏观数据"}
|
|
264
|
+
|
|
265
|
+
return {"success": True, "country": "CN", "indicator": indicator,
|
|
266
|
+
"data": results, "provider": "akshare"}
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
# ── Economic Calendar ─────────────────────────────────────────────────────────
|
|
270
|
+
|
|
271
|
+
def get_economic_calendar(days_ahead: int = 7) -> dict:
|
|
272
|
+
"""
|
|
273
|
+
获取未来 N 天的重大经济事件日历。
|
|
274
|
+
数据来源:投资道/东方财富 (akshare),备用: Finnhub
|
|
275
|
+
"""
|
|
276
|
+
results = []
|
|
277
|
+
|
|
278
|
+
# Try akshare economic calendar (东方财富)
|
|
279
|
+
if _HAS_AK:
|
|
280
|
+
try:
|
|
281
|
+
df = ak.news_economic_baidu(date=datetime.now().strftime("%Y%m%d"))
|
|
282
|
+
if df is not None and not df.empty:
|
|
283
|
+
cols = [c for c in ["time","event","actual","forecast","previous","importance"]
|
|
284
|
+
if c in df.columns]
|
|
285
|
+
results = df[cols].head(30).to_dict("records") if cols else []
|
|
286
|
+
except Exception as e:
|
|
287
|
+
logger.debug("akshare calendar failed: %s", e)
|
|
288
|
+
|
|
289
|
+
# Fallback: Finnhub economic calendar
|
|
290
|
+
if not results and _HAS_REQUESTS:
|
|
291
|
+
try:
|
|
292
|
+
key = _get_finnhub_key()
|
|
293
|
+
if key:
|
|
294
|
+
from_dt = datetime.now().strftime("%Y-%m-%d")
|
|
295
|
+
to_dt = (datetime.now() + timedelta(days=days_ahead)).strftime("%Y-%m-%d")
|
|
296
|
+
r = _req.get(
|
|
297
|
+
"https://finnhub.io/api/v1/calendar/economic",
|
|
298
|
+
params={"from": from_dt, "to": to_dt, "token": key},
|
|
299
|
+
timeout=8,
|
|
300
|
+
)
|
|
301
|
+
r.raise_for_status()
|
|
302
|
+
results = r.json().get("economicCalendar", [])
|
|
303
|
+
except Exception as e:
|
|
304
|
+
logger.debug("Finnhub calendar failed: %s", e)
|
|
305
|
+
|
|
306
|
+
if not results:
|
|
307
|
+
# Static upcoming FOMC/PBOC dates as fallback
|
|
308
|
+
results = [
|
|
309
|
+
{"event": "FOMC Meeting", "importance": "HIGH",
|
|
310
|
+
"note": "具体日期请查阅 federalreserve.gov/monetarypolicy"},
|
|
311
|
+
{"event": "PBOC LPR Announcement", "importance": "HIGH",
|
|
312
|
+
"note": "每月 20 日前后公布"},
|
|
313
|
+
{"event": "US CPI Release", "importance": "HIGH",
|
|
314
|
+
"note": "每月第二周(周二或周三)"},
|
|
315
|
+
{"event": "China PMI Release", "importance": "MEDIUM",
|
|
316
|
+
"note": "每月最后一天(官方)/ 次月第一工作日(财新)"},
|
|
317
|
+
]
|
|
318
|
+
|
|
319
|
+
return {"success": True, "events": results, "days_ahead": days_ahead,
|
|
320
|
+
"provider": "akshare/finnhub"}
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
def _get_finnhub_key() -> str:
|
|
324
|
+
"""Read Finnhub key from env or providers.json."""
|
|
325
|
+
k = os.getenv("FINNHUB_API_KEY", "")
|
|
326
|
+
if not k:
|
|
327
|
+
try:
|
|
328
|
+
import json
|
|
329
|
+
p = aria_home() / "providers.json"
|
|
330
|
+
if p.exists():
|
|
331
|
+
d = json.loads(p.read_text())
|
|
332
|
+
k = d.get("finnhub", {}).get("api_key", "") or d.get("finnhub_api_key", "")
|
|
333
|
+
except Exception:
|
|
334
|
+
pass
|
|
335
|
+
return k
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
# ── Central Bank Policy Rates ─────────────────────────────────────────────────
|
|
339
|
+
|
|
340
|
+
def get_central_bank_rates() -> dict:
|
|
341
|
+
"""主要央行政策利率快照。"""
|
|
342
|
+
CB_TICKERS = {
|
|
343
|
+
"美联储 (Fed Funds)": "FEDFUNDS",
|
|
344
|
+
"欧央行 (ECB Refi)": "ECBDFR",
|
|
345
|
+
"英央行 (BoE Rate)": "BOERUKM",
|
|
346
|
+
"日央行 (BoJ Rate)": "IRSTCI01JPM156N",
|
|
347
|
+
}
|
|
348
|
+
rates = {}
|
|
349
|
+
for name, series in CB_TICKERS.items():
|
|
350
|
+
data = _fred_series(series, limit=3)
|
|
351
|
+
if data:
|
|
352
|
+
latest = data[-1]
|
|
353
|
+
rates[name] = latest["value"]
|
|
354
|
+
|
|
355
|
+
# PBOC LPR via akshare
|
|
356
|
+
if _HAS_AK:
|
|
357
|
+
try:
|
|
358
|
+
df = ak.macro_china_lpr()
|
|
359
|
+
if df is not None and not df.empty:
|
|
360
|
+
row = df.iloc[-1]
|
|
361
|
+
rates["中国人民银行 LPR 1Y"] = float(row.get("1年期贷款市场报价利率", row.iloc[1]))
|
|
362
|
+
rates["中国人民银行 LPR 5Y"] = float(row.get("5年期贷款市场报价利率", row.iloc[2]))
|
|
363
|
+
except Exception:
|
|
364
|
+
pass
|
|
365
|
+
|
|
366
|
+
if not rates:
|
|
367
|
+
return {"success": False, "error": "无法获取央行利率数据"}
|
|
368
|
+
|
|
369
|
+
return {"success": True, "rates": rates, "provider": "FRED+akshare"}
|