TradingAgents-CN TTM 计算修复深度解析:从 PE/PS 高估 1.33-4 倍到多数据源统一最近12个月口径
TradingAgents-CN TTM 计算修复深度解析从 PE/PS 高估 1.33-4 倍到多数据源统一最近12个月口径【免费下载链接】TradingAgents-CN基于多智能体LLM的中文金融交易框架 - TradingAgents中文增强版项目地址: https://gitcode.com/GitHub_Trending/tr/TradingAgents-CN导读本文完整还原 TradingAgents-CN 项目中一次严重的数据准确性缺陷——估值指标PE/PS因误用单期财务数据季报/半年报而被系统性高估 1.33-4 倍——从用户报告、根因定位到多数据源Tushare / AKShare / 实时 API修复落地的全过程。读完本文你将掌握A 股财务数据累计值的正确语义、TTM 最近年报 (本期累计 − 去年同期累计)的推导与源码实现、简单年化策略为何对季节性行业失效以及如何通过单元测试、集成测试和真实数据验证保证修复质量。问题概述估值指标为何被高估2025-10-26 的修复记录 docs/bugfix/2025-10-26-ttm-calculation-summary.md 指出系统在PS市销率和 PE市盈率计算中发现严重的数据准确性问题估值计算使用的是单期财务数据季报/半年报而非TTMTrailing Twelve Months最近12个月数据导致估值指标被严重高估。这一问题的本质不是公式写错而是分母的统计口径错误PE 股价 / 每股收益(EPS)若 EPS 只取单季或单期数据PE 会被系统性放大PS 市值 / 营业收入若营业收入只取半年报累计PS 约被高估 2 倍。由于 PE/PS 是基本面分析与投资决策的核心输入这类误差会直接传导到下游的分析师结论中可能误导用户做出错误的投资决策。问题发现过程从用户报告到根因确认1. 用户报告 PS 计算异常用户发现600036招商银行的 PS 为 3.30 倍远高于银行股通常的合理范围由此触发排查。2. 验证发现根本原因排查确认数据库中revenue字段存储的是单期数据例如 Q2 半年报即 1-6 月累计值PS 计算公式为PS 市值 / 营业收入使用半年报数据半年营收作为分母PS 被高估2 倍。3. 扩展检查发现更多问题将检查范围扩大到全部数据源后发现问题并非个例而是全链路普遍存在数据源问题表现MongoDB / AKShare 数据源同步脚本使用单期数据Tushare 数据源同步和实时调用都使用单期数据实时 API 调用AKShare 和 Tushare 实时调用都使用单期数据也就是说无论数据来自数据库同步还是实时拉取估值分母都沿用了错误的单期口径。技术细节为什么 TTM 公式是这样A 股财务数据的累计值语义Tushare 和 AKShare 返回的利润表数据都是年初至今的累计值而非单季度值2025Q1 (20250331)2025 年 1-3 月累计2025Q2 (20250630)2025 年 1-6 月累计2025Q3 (20250930)2025 年 1-9 月累计2025Q4 (20251231)2025 年 1-12 月累计即年报因此不能把某个报告期的数值直接当作该季度的业绩更不能直接当作全年业绩。正确的 TTM 公式TTM 去年同期之后的最近年报 (本期累计 - 去年同期累计)示例以 2025Q3 为最新期TTM 2024年报 (2025Q3累计 - 2024Q3累计) 2024年1-12月 (2025年1-9月 - 2024年1-9月) 2024年10-12月 2025年1-9月 最近12个月 ✅公式的直观含义以最近的完整年报为基准把去年同期之后新发生的业绩增量本期累计减去年同期累计叠加进去恰好构成连续 12 个月的滚动口径。为什么不使用简单年化修复前的代码采用过简单年化降级策略即用当期累计值乘以一个固定倍数外推全年Q1 × 4假设每个季度业绩相同Q2 × 2假设上下半年业绩相同Q3 × 4/3假设前 9 个月和全年比例固定对季节性行业严重不准确电商行业Q4双 11、双 12、春节业绩可能是 Q1 的 3-4 倍零售行业节假日销售占比极高旅游行业淡旺季差异巨大。原文档中保留了用户的真实反馈像电商行业下半年的业绩比上半年好很多。这么估算不准的吧。因此新实现彻底移除了简单年化策略当数据不足以计算 TTM 时直接返回None交由上层降级或标记绝不输出不可靠的估算值。修复 1Tushare 数据源同步修改文件tradingagents/dataflows/providers/china/tushare.py修复内容新增_calculate_ttm_from_tushare()方法实现正确的 TTM 计算公式TTM 基准年报 (本期累计 - 去年同期累计)移除简单年化降级策略Q1×4、Q2×2、Q3×4/3数据不足时返回None。提交b0413c6、5de898e源码级实现解析在 tushare.py 中_calculate_ttm_from_tushare(income_statements, field)的核心算法如下取最新一期latest income_statements[0]读取end_date与指定字段revenue或n_income_attr_p年报直接使用判断end_date的月日部分是否为1231若是年报则直接返回该值month_day 1231分支构造去年同期last_year_same_period str(int(latest_year) - 1) latest_period[4:]在利润表列表中精确查找去年同期记录查找基准年报遍历找到晚于去年同期且period[4:8] 1231的最近年报套用公式ttm_value base_value (latest_value - last_year_value)。关键防御逻辑每一步缺失都返回None并记录 warning 日志缺少去年同期数据 → 返回None去年同期数据值为空 → 返回None找不到基准年报典型场景最新期是 2025Q1而 2024 年报尚未披露→ 返回None基准年报数据值为空 → 返回None任何异常 → 捕获后返回None。调用点在 tushare.pyrevenue_ttm self._calculate_ttm_from_tushare(income_statements, revenue)、net_profit_ttm self._calculate_ttm_from_tushare(income_statements, n_income_attr_p)同步阶段即完成 TTM 营业收入与归母净利润的落库。修复 2AKShare 数据源同步修改文件scripts/sync_financial_data.py修复内容将_calculate_ttm_revenue()重构为通用的_calculate_ttm_metric()支持任意指标新增 TTM 净利润计算PE 计算优先使用 TTM 净利润新增 PS 计算优先使用 TTM 营业收入移除简单年化降级策略更新stock_basic_info集合新增net_profit_ttm、revenue_ttm、ps字段。测试结果来自修复文档✅ TTM 营业收入计算正确1357.81万元 ✅ TTM 净利润计算正确558.68万元 ✅ 数据不足时正确返回 None ✅ 年报数据正确直接使用提交5384339源码级实现解析scripts/sync_financial_data.py 中的_calculate_ttm_metric(df, metric_name)面向 AKShare 返回的 DataFrame包含报告期列与指标列实现校验 DataFrame 非空且包含必要列按报告期升序排序后取最新一期最新期以1231结尾年报→ 直接返回否则构造上一年的1231年报期与去年同期在 DataFrame 中精确匹配两者都存在时执行ttm_value last_annual_value (latest_value - last_same_value)并额外要求结果 0才返回否则返回None任一步骤缺失时打印 warning 日志区分缺少去年同期数据与缺少基准年报后返回None。原函数_calculate_ttm_revenue(df)被保留为兼容包装内部委托给_calculate_ttm_metric(df, 营业收入)避免影响既有调用方。修复 3实时 API 调用修改文件tradingagents/dataflows/optimized_china_data.py3.1 AKShare 实时调用修复原有问题PE 计算使用单期 EPS导致 PE 被高估 1.33-4 倍PS 计算完全缺失返回占位符待计算。修复要点PE 计算从main_indicatorsDataFrame 中提取多期 EPS 数据基本每股收益指标行跨报告期取列调用_calculate_ttm_metric()计算 TTM EPS见 optimized_china_data.py优先使用 TTM EPS降级到单期 EPS并在日志中标注数据类型TTM/单期PS 计算从main_indicators提取多期营业收入数据计算 TTM 营业收入见 optimized_china_data.py使用总股本 × 股价得到市值PS 市值 / TTM 营业收入见 optimized_china_data.py同样标注数据类型。从源码可见实时链路对 TTM 计算失败还有多层兜底当 TTM 值不可用时降级到indicators_dict中的单期值若单期 EPS 存在但 ≤ 0则标记为N/A亏损避免把亏损股算出误导性 PE。3.2 Tushare 实时调用修复原有问题PE/PS 计算使用单期数据虽有警告日志但仍返回错误数据。修复要点从income_statement列表提取多期数据使用_calculate_ttm_metric()计算 TTM 净利润和营业收入见 optimized_china_data.py分别以total_revenue与n_income字段构建 DataFrame优先使用 TTM 数据降级到单期数据移除警告日志改为信息日志标注数据类型。提交8077316验证结果平安银行000001实测修复文档给出了完整的真实数据验证以000001平安银行报告期 20250930 为例报告期: 20250930 营业收入单期: 1006.68 亿元 营业收入TTM: 1357.81 亿元 净利润单期: 383.39 亿元 净利润TTM: 558.68 亿元TTM 计算验证TTM 营业收入 2024年报 (2025Q3 - 2024Q3) 1466.95 (1006.68 - 1115.82) 1357.81 亿元 ✅ TTM 净利润 2024年报 (2025Q3 - 2024Q3) 733.20 (383.39 - 557.91) 558.68 亿元 ✅PS 计算对比PS单期 2243.32 / 1006.68 2.23倍 ❌ 高估 PSTTM 2243.32 / 1357.81 1.65倍 ✅ 正确差异单期口径下的 PS 比 TTM 口径高估 35%。考虑到不同报告期Q1/Q2/Q3和不同行业整体偏差区间达到 1.33-4 倍。影响范围与触发条件触发条件数据库同步所有通过 Tushare/AKShare 同步的财务数据实时查询用户首次查询某只股票数据库无缓存数据时。影响程度严重性PE/PS 被高估 1.33-4 倍用户体验可能导致错误的投资决策数据一致性修复前后数据口径不一致存量数据需要迁移。测试与回归保障修复文档列出的验证体系在仓库中均有对应脚本可复现验证类型脚本说明单元测试scripts/test_ttm_calculation_logic.py使用模拟数据验证 TTM 公式集成测试scripts/test_akshare_ttm_calculation.pyAKShare 真实链路 TTM 测试实际数据验证scripts/verify_ttm_calculation_000001.py平安银行真实数据核对PS 计算验证scripts/test_ps_calculation_verification.pyPS 口径验证单元测试覆盖的 5 个关键场景scripts/test_ttm_calculation_logic.py 直接调用TushareProvider._calculate_ttm_from_tushare()用模拟数据验证边界行为正常情况2025Q2有 2024 年报与 2024Q2TTM 1100 (600 − 500) 1200并与单季度累加法交叉验证2024Q3 2024Q4 2025Q1 2025Q2 四个单季之和最新期是年报2025年报直接返回 1300不做任何外推缺少去年同期数据返回None缺少基准年报2025Q1 时 2024 年报未公布返回None且 2023 年报不能越级充当基准2025Q3 TTMTTM 1100 (900 − 800) 1200同样用单季累加法验证。这 5 个场景精确对应了公式的全部成功与失败分支是宁可返回 None 也不输出错误估算这一原则的可执行化表达。后续工作建议修复文档同时给出了收尾清单1. 数据迁移建议重新同步所有股票的财务数据使用新的 TTM 计算逻辑更新stock_basic_info和stock_financial_data集合。2. 测试验证单元测试scripts/test_ttm_calculation_logic.py集成测试scripts/test_akshare_ttm_calculation.py实际数据验证scripts/verify_ttm_calculation_000001.py批量数据验证多只股票实时 API 调用测试。3. 监控和告警添加 TTM 计算失败的监控当数据不足时记录警告日志定期检查数据质量。相关修复Tushare Token 配置优先级问题在修复 TTM 问题的过程中用户反馈了另一个重要问题详见 docs/bugfix/2025-10-26-tushare-token-priority-issue.md问题用户在 Web 后台修改 Tushare Token 后不生效必须删除数据卷重新部署根本原因.env文件优先级高于数据库配置Tushare Provider 只从环境变量读取 Token修复方案修改配置优先级数据库配置 .env 文件Tushare Provider 每次连接时从数据库读取最新 Token保留 .env 文件作为降级方案。Git 提交75edbc8Git 提交记录汇总提交说明b0413c6fix: Tushare 数据源添加 TTM 营业收入和净利润计算5de898efix: 移除 TTM 计算中不准确的简单年化降级策略5384339fix: 修复 AKShare 数据源的 TTM 计算和估值指标8077316fix: 修复基本面分析实时 API 调用中的 TTM 计算问题75edbc8fix: Tushare Token 配置优先级数据库 .env相关文档与文件修改的文件tradingagents/dataflows/providers/china/tushare.py — Tushare 同步链路 TTM 计算scripts/sync_financial_data.py — AKShare 同步链路 TTM 计算tradingagents/dataflows/optimized_china_data.py — 实时 API 调用链路 TTM 计算新增的文件scripts/test_ttm_calculation_logic.py — TTM 计算逻辑单元测试scripts/test_akshare_ttm_calculation.py — AKShare TTM 集成测试scripts/verify_ttm_calculation_000001.py — 平安银行实际数据验证scripts/test_ps_calculation_verification.py — PS 计算验证docs/bugfix/2025-10-26-ps-calculation-fix.md — PS 修复文档docs/bugfix/2025-10-26-realtime-api-ttm-issues.md — 实时 API 问题文档docs/bugfix/2025-10-26-ttm-calculation-summary.md — 本文档修复总结总结本次修复解决了 TradingAgents-CN 中最严重的数据准确性问题之一。通过正确实现 TTM 计算确保了✅数据准确性PE/PS 不再被高估 1.33-4 倍✅季节性处理对电商、零售、旅游等季节性行业更加准确✅数据一致性数据库同步和实时调用使用相同的计算逻辑同步链路与实时链路均复用同一套 TTM 算法✅可追溯性详细的日志记录标注数据类型TTM/单期并在 AKShare 实时链路中保留多层降级与亏损股判定✅降级策略数据不足时返回None不使用不可靠的简单年化估算。修复文档中记录的用户反馈为宁可缺数据、不可错数据的设计取舍提供了最有力的佐证你的质疑非常正确简单年化对季节性行业完全不适用。现在的实现更加准确和可靠。从数据源角度看本次修复将 TTM 计算统一收敛到基准年报 本期累计 − 去年同期累计这一个公式贯穿 Tushare 同步、AKShare 同步与实时 API 三条链路并通过 5 个边界场景的单元测试固化了公式的行为契约——这正是金融数据系统中口径统一价值的完整实践样本。【免费下载链接】TradingAgents-CN基于多智能体LLM的中文金融交易框架 - TradingAgents中文增强版项目地址: https://gitcode.com/GitHub_Trending/tr/TradingAgents-CN创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考