Files
group_fqcd_jr/docs/12-基金行情数据底座接入开发计划.md
lzf_0626 36c7a9d8d2 文档:审查报告入库 + 全量校对补注
## 新入库(`docs/演示用/`)

- `代码库全面审查报告-2026-09-14.md`
- `代码修改方案-2026-09-14.md`
- `记忆系统排查报告-2026-09-14.md`
- `记忆系统修复文档-2026-09-14.md`
- `文档一致性审计报告-2026-09-14.md`
- `多Worker接入方案-2026-09-14.md`

## 全量校对(32 个既有文档 + `AGENTS.md`)

跨 39 个文件、**1125 insertions / 148 deletions**。

⚠️ **这批改动同样不是本次会话写的**。我抽样核对过性质:是**实质内容补充**而不是
格式/换行转换。例如 `docs/44-演示流程.md` 新增两条"2026-09-14 补注":

- `启动金融Agent平台.bat` 只在**桌面**上,仓库里只有 `启动平台.bat` 这一份
  (两份由同一个 `tools/make_launcher_bat.py` 产出,改完 `start.ps1` 重跑它一起更新);
- `advisor_t`(9020) 与 `offsite_t`(9006) **不在 `tools/seed_test_rbac.py` 的演示用户里**
  (那里只有 `cust_t`/`risk_t`/`admin_t`/`review_t` 四个),由 `grant_*.py` 系列创建,
  **重跑种子不会重建它们** —— 换机器时这两个账号登录失败,要先查 `sys_user` 有没有这两行,
  而不是查密码。

这两条都是对的地方,与我这一路踩到的现象一致(我确实用到了 `advisor_t`/`offsite_t`)。

**我没有逐字审阅全部 39 个文件**,只抽样确认了改动性质与规模。若其中有需要复核的段落,
请指明文件,我逐处核对。
2026-09-14 20:36:00 +08:00

11 KiB
Raw Permalink Blame History

基金行情数据底座接入开发计划

⚠️ MVP 完成标准已过期。 文中「F0-F4 全部通过」为当时快照;实际 F0-F6 已完成。另有部分「当前实现」的描述已随底座演进而变化。

(此批注由 2026-09-11 只读审计加入;原文未改动。详见 docs/superpowers/ARCHIVE-2026-09-11-文档清理归档.md §3)


⚠️ 2026-09-14 补充:本文完全没写的两件运行期事实(重要)

1. 行情有效期只有 15 分钟 —— 这是演示/验收最容易翻的一环。 app/service/trade_service.py 的 MAX_QUOTE_AGE = timedelta(minutes=15)(L79)。 超时后所有委托一律 503 FUND_QUOTE_UNAVAILABLE(app/core/errors.py:260-264), 且没有自动刷新。症状看起来像"行情源坏了",实际只是数据放久了。 补刷命令(立即生效、无需重启服务):

.\.venv\Scripts\python.exe tools\sync_market_prices.py

2. 两个行情/净值同步脚本未被本文登记:

  • tools/sync_market_prices.py —— 刷实时行情(上条)。
  • tools/sync_nav_history.py —— 刷历史净值(访客端 GET /api/v1/products/{product_code}/nav-history 用它)。

3. 工具超时的依据:query_fund_quote 的工具超时是 15 秒(app/service/agent/bootstrap.py:278)。 理由(代码内注释):EastmoneyAdapterFactory 单码最坏预算 = 4.0s + 0.2s(退避) + 4.0s(重试) = 8.2s, 15s ≈ 8.2 × 1.8。旧的 5 秒会在适配器自己的重试预算之前就撞工具超时,永远拿不到结果。

启动链:启动金融Agent平台.bat(桌面)/ 启动平台.bat(仓库)会按序做:找解释器 → 检查 MySQL/Redis/Milvus → 刷新行情 → 起 API 与 Agent Worker → 等 API 应答 → 开浏览器。 解释器门槛是「版本 ≥ 3.11 且能 import fastapi, sqlalchemy, asyncmy, pydantic」, 不能只看 --version(曾因此选中 3.10 环境,报错却出现在行情刷新那步,看着像行情源坏了)。

版本:v1.0
目标:将外部基金行情能力接入公共 MVC+S 底座,供客服、投顾、风控 Agent 统一只读使用。
当前范围:场内基金模拟交易相关行情;场外运营数据不纳入本计划。

一、建设目标

将外部行情脚本改造成公共底座能力:

东方财富 Adapter
→ FundQuoteService
→ ToolRegistry / ToolExecutor
→ 客服、投顾、风控 Agent

业务组员只调用统一工具,不直接访问东方财富接口、HTTP 客户端、缓存或数据库。

二、明确不做的事情

  • 第一阶段不修改已有数据库表、字段和交易流程;
  • 不把行情快照写入场内交易表;
  • 不实现代客下单、成交确认或持仓修改;
  • 不让 Agent 直接调用外部行情接口;
  • 不在本阶段创建可运行示例 Agent;
  • 不把场外基金运营数据混入本行情服务。

三、现有脚本拆分映射

原 hq.py 能力 新底座位置 处理要求
东方财富 HTTP 调用 app/infrastructure/fund_market_adapter.py 改为异步、超时、重试、响应校验
交易时段判断 FundQuoteService 固定北京时间并可测试注入时钟
基金名称缓存 行情缓存适配器 允许 Redis,不使用进程全局作为唯一缓存
历史净值和收益率合并 app/service/fund_quote_service.py 统一 DTO、Decimal、降级标识
中文字典输出 Controller/Agent 展示层 内部 DTO 使用英文稳定字段
固定南方基金代码 配置或代码白名单 先保留白名单,后续配置中心化

四、阶段计划

F0:基线和契约冻结

目标:确认接入不会破坏现有底座和数据库规则。

任务:

  • 对照 AGENTS.md、00 基线和 02 建表设计;
  • 确认本阶段只新增 Python 模块、工具注册和测试;
  • 定义 FundQuoteQuery、FundQuote、FundQuoteSource DTO;
  • 定义错误分类:外部行情不可用返回可识别的降级结果,不泄露供应商异常;
  • 确认行情工具权限码为 fund:quote:read。

验收:

  • DTO 字段、类型和空值规则确定;
  • 没有数据库迁移;
  • 没有修改既有表和字段;
  • 接口契约可被 Service、ToolExecutor 和测试共同引用。

F1:外部行情 Adapter

目标:把 hq.py 的外部请求改造成底座 Infrastructure 适配器。

新增文件:

app/infrastructure/fund_market_adapter.py
app/core/fund_contracts.py
tests/unit/infrastructure/test_fund_market_adapter.py

任务:

  • 使用 httpx.AsyncClient,禁止同步网络调用阻塞 Worker;
  • 封装名称、实时行情、历史净值、区间收益率四类请求;
  • 统一请求超时、有限重试和指数退避;
  • 校验外部 JSON 结构和基金代码;
  • 将 HTTP、JSON、字段缺失转换为 RecoverableAgentError 或降级结果;
  • 供应商日志只记录接口类别、基金数量和异常类型,不记录完整响应正文;
  • 使用 Decimal 保存净值和收益率;
  • 所有时间统一使用 Asia/Shanghai 语义。

验收:

  • 外部接口成功、超时、HTTP 错误、非法 JSON、字段缺失均有测试;
  • 测试不依赖真实东方财富网络,使用 httpx.MockTransport;
  • Adapter 不导入 Agent、Controller 或数据库 Session。

F2:FundQuoteService

目标:将多个外部接口结果合并成稳定的行情业务结果。

新增文件:

app/service/fund_quote_service.py
tests/unit/service/test_fund_quote_service.py

任务:

  • 实现按基金代码、基金类型、日期和数量查询;
  • 保留场内基金白名单;
  • 合并实时行情和历史净值;
  • 盘中使用实时行情,非盘中使用最新收盘净值;
  • 返回 quote_source、quote_time、is_intraday、degraded;
  • 单个产品失败不得导致全部产品无原因失败;
  • 外部行情不可用时返回结构化降级结果;
  • 不将实时行情解释为成交、委托或持仓结果。

验收:

  • 交易时段和非交易时段测试通过;
  • 基金类型筛选、数量限制、非法日期和未知类型测试通过;
  • 实时失败回退历史、历史失败返回降级结果的测试通过;
  • Service 不直接解析 HTTP 响应细节。

F3:缓存和健康状态

目标:降低外部接口压力,并让组员得到可识别的降级状态。

任务:

  • 基金名称缓存建议 1 天;
  • 收盘净值缓存建议 5-30 分钟;
  • 实时行情缓存建议 30-60 秒;
  • Redis 可用时使用 Redis,不可用时回退无缓存请求或结构化降级;
  • 不将进程级字典作为多 Worker 唯一缓存;
  • 增加行情数据源健康状态,不把供应商故障伪装成正常行情;
  • 记录数据源成功率、延迟、降级次数和最后成功时间。

验收:

  • Redis 正常、Redis 不可用、缓存过期和缓存击穿测试通过;
  • 缓存故障不阻塞主流程;
  • 返回结果能够区分实时、缓存、收盘和降级来源。

F4:注册公共只读工具

目标:让所有业务 Agent 通过统一工具使用行情。

工具契约:

工具名:query_fund_quote
权限码:fund:quote:read
只读:是
允许角色:customer、advisor、operator、risk_operator、admin
超时:5 秒

任务:

  • 定义严格的 Pydantic 输入模型;
  • 在 bootstrap 中注册 ToolDefinition;
  • 由 ToolExecutor 统一检查权限、角色、意图白名单和超时;
  • 结果自动生成工具来源引用和审计记录;
  • AgentDefinition.allowed_tools 只能缩小权限;
  • 业务 Agent 不能绕过工具调用 Adapter。

验收:

  • 正常调用、未授权、未列入意图白名单、参数错误、超时和外部失败均有测试;
  • 工具结果不含供应商原始异常和敏感配置;
  • 来源引用能通过公共合规审查。

F5:配置中心和管理规则

目标:把基金白名单、数据源开关、缓存时间和限流参数逐步纳入配置治理。

第一阶段:

  • 外部接口地址、超时和密钥引用写入 .env 或运行配置;
  • 基金白名单保留在代码常量,避免未经审核扩大产品范围。

后续阶段:

  • 使用 platform_config_item 增加行情配置命名空间;
  • 配置发布、审核、激活、回滚必须经过已有配置中心;
  • 配置变更写审计并通过 Outbox 通知缓存失效;
  • 不通过配置中心扩大 Agent 的工具权限上限。

验收:

  • 配置缺失时失败关闭或使用明确的安全默认值;
  • 密钥只使用 secret_ref,不返回明文;
  • 发布版本可追溯、可回滚。

当前实现:RuntimeConfigService.fund_quote() 读取当前激活版本的 namespace=fund_market、config_key=default;query_fund_quote 工具加载该配置, FundQuoteRuntimeConfig 校验基金白名单和缓存 TTL。配置缺失、类型错误或配置中心异常时使用代码 默认值,不会因配置中心异常导致行情功能整体不可用。

F6:业务组员接入

目标:客服、投顾和风控 Agent 只消费统一行情工具。

组员需要做:

  • 在 AgentDefinition.allowed_tools 声明 query_fund_quote;
  • 在对应意图白名单中声明 fund_quote;
  • 在 handle() 中调用 self.call_tool(...);
  • 对行情缺失、降级和非交易时段给出业务解释;
  • 补充本业务域的权限和边界测试。

组员禁止做:

  • 直接导入 hq.py;
  • 直接调用东方财富 URL;
  • 自己读取行情缓存或解析外部 JSON;
  • 根据行情直接下单或修改交易数据;
  • 把行情数据写入交易表。

F7:是否落行情快照表

判断条件:只有在需要历史回测、监管留痕、行情对账或跨进程长期查询时才进入本阶段。

候选新增表:

fund_quote_snapshot
fund_quote_source_record

前置要求:

  • 先更新 00、02 数据库文档;
  • 证明没有修改任何既有表名和字段定义;
  • 设计唯一键、来源、采集时间、有效时间和幂等策略;
  • 增加 Alembic 迁移、schema fingerprint 和真实 MySQL 验收;
  • 只新增表,不改写场内交易表。

五、建议开发顺序和完成标准

F0 契约冻结
→ F1 Adapter
→ F2 Service
→ F3 缓存/健康
→ F4 公共工具
→ F5 配置治理
→ F6 业务接入
→ F7 可选落库

MVP 完成标准:F0-F4 全部通过;不要求新增数据库表。长期版本再评估 F5-F7。

六、测试命令

python -m pytest tests/unit/infrastructure/test_fund_market_adapter.py tests/unit/service/test_fund_quote_service.py -q -p no:cacheprovider
python -m pytest -q -p no:cacheprovider
python -m ruff check app tests tools alembic
python -m mypy app
python tools/audit_schema.py

任何数据库变更都必须额外执行 schema fingerprint,并在 TODO 中记录基线对比结果。