一、升级概览
2025 年 10 月 26 日,TradingAgents-CN 完成了一次全面的 系统优化。
本次更新通过 36 个提交,围绕 用户偏好设置系统重构、财务指标计算优化、WebSocket 连接修复、UI 体验改进 等方向展开,显著提升了系统的 数据准确性、用户体验和稳定性。
核心改进
- 用户偏好设置系统重构:解决设置刷新后丢失的问题。
- 分析偏好自动应用:单股分析和批量分析优先读取用户偏好。
- TTM 计算修复:正确处理财报累计值和基准期选择。
- PS/PE 指标优化:市销率和动态市盈率使用 TTM 数据计算。
- Tushare Token 配置优化:数据库配置优先于环境变量,支持 Web 后台修改生效。
- WebSocket 连接修复:统一开发环境和生产环境连接逻辑。
- UI 体验改进:添加数据源注册引导,修复深色主题下白色背景问题。
- 关于页面完善:补充原项目介绍和致谢。
二、用户偏好设置系统重构
2.1 问题背景
相关提交:
41ca79f:修复所有设置保存到 localStorage 的问题。6283a5c:修复所有个人设置保存问题,包括外观、分析偏好和通知设置。e2fef6b:修复通用设置中邮箱地址保存后刷新恢复原值的问题。e56c571:修复主题设置保存后刷新不生效的问题。
此前用户在前端修改个人设置后,刷新页面会恢复到旧值。
受影响的设置包括:
- 主题设置:深色 / 浅色不生效。
- 分析偏好设置:模型、分析师选择不生效。
- 通知设置:刷新后丢失。
- 邮箱地址:保存后刷新恢复原值。
2.2 根本原因
问题主要来自 前后端设置存储不一致。
前端和后端存储不同步
前端将设置保存到 localStorage,后端则使用 MongoDB 的 users 集合存储用户信息。
两者没有同步机制。
页面刷新时后端数据覆盖前端设置
authStore 初始化时,会从后端 /api/auth/me 获取用户信息,并覆盖本地 localStorage 中的设置。
后端没有返回用户偏好字段
/api/auth/me 接口没有返回 preferences 字段,导致前端无法拿到完整用户偏好。
2.3 解决方案
后端返回用户偏好设置
@router.get("/me")
async def get_current_user(current_user: dict = Depends(get_current_user_from_db)):
"""获取当前用户信息"""
return {
"id": str(user.id),
"username": user.username,
"email": user.email,
"name": user.username,
"is_admin": user.is_admin,
"roles": ["admin"] if user.is_admin else ["user"],
"preferences": user.preferences.model_dump() if user.preferences else {}
}
前端同步用户偏好到 appStore
setAuthInfo(token: string, refreshToken: string, user: User) {
this.token = token
this.refreshToken = refreshToken
this.user = user
this.syncUserPreferencesToAppStore()
}
syncUserPreferencesToAppStore() {
const appStore = useAppStore()
if (this.user?.preferences) {
if (this.user.preferences.theme) {
appStore.theme = this.user.preferences.theme
appStore.applyTheme()
}
if (this.user.preferences.analysis) {
appStore.analysisPreferences = this.user.preferences.analysis
}
if (this.user.preferences.notifications) {
appStore.notificationSettings = this.user.preferences.notifications
}
}
}
添加用户偏好迁移脚本
新增迁移脚本:
scripts/migrate_user_preferences.py
用于给旧用户补充默认 preferences 字段。
默认偏好包括:
themeanalysis.default_modelanalysis.default_analystsnotifications.email_enablednotifications.browser_enabled
2.4 优化效果
- 用户设置保存到数据库。
- 刷新页面后设置不再丢失。
- 前后端偏好数据保持同步。
- 支持多设备同步用户偏好。
三、分析偏好设置优化
3.1 问题背景
相关提交:
767ac03:修正分析偏好默认值,与单股分析模块保持一致。25de33c:单股分析和批量分析优先读取用户偏好设置。
此前存在两个问题:
默认值不一致
个人设置页面默认模型为 gpt-4o-mini,但单股分析页面默认模型为 gpt-4o,用户容易困惑。
分析页面不读取用户偏好
每次打开分析页面时,系统都会使用硬编码默认值,用户需要重新选择模型和分析师。
3.2 解决方案
单股分析页面初始化时优先读取 appStore.analysisPreferences。
onMounted(async () => {
const appStore = useAppStore()
if (appStore.analysisPreferences) {
analysisForm.model =
appStore.analysisPreferences.default_model || 'gpt-4o-mini'
analysisForm.analysts =
appStore.analysisPreferences.default_analysts ||
['market', 'fundamentals', 'news', 'social']
}
})
3.3 优化效果
- 默认模型统一为 gpt-4o-mini。
- 单股分析和批量分析自动读取用户偏好。
- 用户不需要每次重复选择模型和分析师。
- 分析流程更加顺手。
四、财务指标计算优化
4.1 修复 TTM 计算问题
相关提交:
9c11d98:重构 TTM 计算逻辑,正确处理累计值和基准期选择。5de898e:移除 TTM 计算中不准确的简单年化降级策略。b0413c6:Tushare 数据源添加 TTM 营业收入和净利润计算。5384339:修复 AKShare 数据源的 TTM 计算和估值指标。8077316:修复基本面分析实时 API 调用中的 TTM 计算问题。
TTM,也就是 Trailing Twelve Months,是计算 PE_TTM 和 PS_TTM 的关键指标。
此前 TTM 计算存在严重问题。
4.1.1 累计值处理错误
财报中的季度数据通常是累计值。
例如:
- Q1 是第一季度累计。
- Q2 是上半年累计。
- Q3 是前三季度累计。
如果直接将 Q1、Q2、Q3 相加,就会重复计算。
错误示例:
Q1 + Q2 + Q3 = 前三季度数据被重复计算
4.1.2 基准期选择不合理
此前使用 Q4 作为基准期,但 Q4 年报通常发布时间较晚,导致 TTM 数据不够及时。
4.1.3 简单年化策略不准确
当没有完整四个季度数据时,旧逻辑可能使用:
Q1 × 4
这种简单年化方式会忽略季节性因素,导致估值指标失真。
4.2 正确的 TTM 公式
新的 TTM 计算公式为:
TTM = 最新年报 + (最新季报 - 去年同期季报)
例如当前最新财报为 2024Q3,则:
TTM_营业收入 = 2023年报营业收入 + (2024Q3营业收入 - 2023Q3营业收入)
TTM_净利润 = 2023年报净利润 + (2024Q3净利润 - 2023Q3净利润)
4.3 实现逻辑
def _calculate_ttm_metrics(self, reports: List[Dict]) -> Optional[Dict]:
"""计算 TTM 指标,正确处理累计值"""
annual_reports = [
r for r in reports if r["report_type"] == "年报"
]
if not annual_reports:
return None
latest_annual = annual_reports[0]
quarterly_reports = [
r for r in reports
if r["report_type"] in ["一季报", "中报", "三季报"]
]
if not quarterly_reports:
return {
"revenue_ttm": latest_annual.get("revenue"),
"net_profit_ttm": latest_annual.get("net_profit")
}
latest_quarterly = quarterly_reports[0]
latest_quarter = latest_quarterly["report_type"]
latest_year = int(latest_quarterly["end_date"][:4])
last_year = latest_year - 1
last_year_same_quarter = None
for report in reports:
if (
report["report_type"] == latest_quarter and
int(report["end_date"][:4]) == last_year
):
last_year_same_quarter = report
break
if not last_year_same_quarter:
return {
"revenue_ttm": latest_annual.get("revenue"),
"net_profit_ttm": latest_annual.get("net_profit")
}
revenue_ttm = (
latest_annual.get("revenue", 0) +
latest_quarterly.get("revenue", 0) -
last_year_same_quarter.get("revenue", 0)
)
net_profit_ttm = (
latest_annual.get("net_profit", 0) +
latest_quarterly.get("net_profit", 0) -
last_year_same_quarter.get("net_profit", 0)
)
return {
"revenue_ttm": revenue_ttm if revenue_ttm > 0 else None,
"net_profit_ttm": net_profit_ttm if net_profit_ttm != 0 else None
}
4.4 优化效果
- TTM 计算更准确。
- 正确处理累计财报数据。
- 基准期选择更合理。
- 移除不准确的简单年化策略。
- PE_TTM 和 PS_TTM 更可信。
五、市销率 PS 与动态市盈率 PE_TTM 修复
5.1 问题背景
相关提交:
f333020:修复市销率 PS 使用季度 / 半年报数据的 bug。c522523:标记 Tushare 和实时行情数据源的 PS/PE 计算问题。ad69c71:修复 Tushare 数据源市值计算,并删除未使用的估算函数。
此前 市销率 PS 使用季度或半年报数据计算,导致明显失真。
错误计算:
PS = 市值 / Q3营业收入
正确计算:
PS = 市值 / TTM营业收入
例如:
市值:100 亿
2024Q3 营业收入:60 亿
TTM 营业收入:80 亿
错误 PS = 100 / 60 = 1.67
正确 PS = 100 / 80 = 1.25
5.2 解决方案
基本面数据中统一先计算 TTM 指标,再用 TTM 指标计算估值。
reports = self._get_financial_reports(code)
ttm_metrics = self._calculate_ttm_metrics(reports)
quote = self.get_realtime_quote(code)
market_cap = quote.get("market_cap")
if ttm_metrics and market_cap:
ps = (
market_cap / ttm_metrics["revenue_ttm"]
if ttm_metrics["revenue_ttm"]
else None
)
pe_ttm = (
market_cap / ttm_metrics["net_profit_ttm"]
if ttm_metrics["net_profit_ttm"]
else None
)
5.3 优化效果
- PS 使用 TTM 营业收入计算。
- PE_TTM 使用 TTM 净利润计算。
- 避免季度数据带来的季节性失真。
- 基本面估值指标更可靠。
六、Tushare Token 配置优先级优化
6.1 问题背景
相关提交:
75edbc8:修复 Tushare Token 配置优先级问题,支持 Web 后台修改立即生效。da3406b:修复数据源优先级读取时的异步 / 同步冲突问题。
此前用户在 Web 后台修改 Tushare Token 后,系统仍可能使用环境变量中的旧 Token。
主要原因:
- 环境变量优先级高于数据库配置。
- 用户在 Web 后台修改后无法立即生效。
- 配置读取存在异步 / 同步上下文冲突。
6.2 解决方案
调整配置优先级:数据库配置优先,环境变量作为降级方案。
async def get_data_source_config(self, source_name: str) -> Optional[Dict]:
"""获取数据源配置,数据库优先"""
db_config = await self._get_from_database(source_name)
if db_config and db_config.get("api_key"):
return db_config
env_key = f"{source_name.upper()}_TOKEN"
env_value = os.getenv(env_key)
if env_value:
return {"api_key": env_value}
return None
同时,将 Tushare 初始化拆成同步初始化和异步初始化。
class TushareAdapter:
def __init__(self):
self.token = os.getenv("TUSHARE_TOKEN")
self._provider = None
async def initialize(self):
"""异步初始化,从数据库读取配置"""
config_service = ConfigService()
config = await config_service.get_data_source_config("tushare")
if config and config.get("api_key"):
self.token = config["api_key"]
if self.token:
self._provider = ts.pro_api(self.token)
6.3 优化效果
- Web 后台修改 Tushare Token 后可立即生效。
- 数据库配置优先级高于环境变量。
- 修复异步 / 同步冲突。
- 数据源配置管理更符合用户预期。
七、WebSocket 连接优化
7.1 问题背景
相关提交:
d0512fc:修复 Docker 部署时 WebSocket 连接失败的问题。f176a10:优化 WebSocket 连接逻辑,支持开发和生产环境。
Docker 部署时,前端错误地尝试连接:
ws://localhost:8000
但生产环境中应该连接服务器实际地址。
7.2 解决方案
启用 Vite WebSocket 代理
export default defineConfig({
server: {
proxy: {
'/api': {
target: 'http://localhost:8000',
changeOrigin: true,
secure: false,
ws: true
}
}
}
})
前端统一使用当前访问地址
const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
const host = window.location.host
const wsUrl = `${wsProtocol}//${host}/api/ws/notifications?token=${token}`
ws = new WebSocket(wsUrl)
7.3 适配效果
| 环境 | 访问地址 | WebSocket 连接 | 代理方式 |
|---|---|---|---|
| 开发 | http://localhost:3000 | ws://localhost:3000/api/ws/... | Vite 代理到后端 |
| 生产 | http://服务器IP | ws://服务器IP/api/ws/... | Nginx 代理到后端 |
| HTTPS | https://域名 | wss://域名/api/ws/... | Nginx 代理到后端 |
7.4 优化效果
- 无需为不同环境修改代码。
- 自动适配
ws://和wss://。 - 自动使用当前访问地址。
- Docker 部署下 WebSocket 连接更稳定。
八、UI 体验改进
8.1 添加数据源注册引导
相关提交:
f7e4546:添加厂家注册引导功能。0ad8489:调整注册引导提示字体大小。9a57973:为数据源添加注册引导功能。d58484e:修复 TypeScript 类型错误,添加缺失类型定义。
在数据源配置页面中,如果用户尚未填写 API Key,系统会显示注册引导。
<el-alert
v-if="!form.api_key && providerInfo.register_url"
type="info"
:closable="false"
>
<template #title>
<div>
<span>还没有 API Key?</span>
<el-link
:href="providerInfo.register_url"
target="_blank"
type="primary"
:underline="false"
>
点击注册 {{ providerInfo.display_name }}
</el-link>
</div>
</template>
</el-alert>
优化效果:
- 用户可快速跳转到数据源注册页面。
- 新用户更容易完成 API Key 配置。
- 减少配置错误。
8.2 修复深色主题白色背景问题
相关提交:
f1fe1d0:修复深色主题下分析页面的白色背景问题。
优化样式:
html.dark {
.page-container {
background-color: var(--el-bg-color) !important;
}
.el-card {
background-color: var(--el-bg-color) !important;
color: var(--el-text-color-primary) !important;
}
.el-form {
background-color: transparent !important;
}
}
优化效果:
- 深色主题下背景更加统一。
- 页面可读性提升。
- 用户体验更一致。
8.3 关于页面添加原项目介绍和致谢
相关提交:
70b1971:在关于页面添加原项目介绍和致谢。
新增内容包括:
- 原项目链接:TradingAgents by virattt。
- 项目来源说明。
- 对原作者开源贡献的致谢。
优化效果:
- 尊重原作者贡献。
- 项目来源更透明。
- 用户更容易理解项目背景。
九、技术亮点
9.1 正确的 TTM 计算公式
TTM = 最新年报 + (最新季报 - 去年同期季报)
这个公式能正确处理累计值,避免重复计算。
9.2 数据库优先的配置策略
db_config = await self._get_from_database(source_name)
if db_config and db_config.get("api_key"):
return db_config
数据库配置优先于环境变量,支持 Web 后台修改立即生效。
9.3 WebSocket 自动适配
const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
const host = window.location.host
const wsUrl = `${wsProtocol}//${host}/api/ws/notifications?token=${token}`
开发和生产环境共用同一套连接逻辑。
9.4 用户偏好同步机制
syncUserPreferencesToAppStore() {
const appStore = useAppStore()
if (this.user?.preferences) {
appStore.theme = this.user.preferences.theme
appStore.analysisPreferences = this.user.preferences.analysis
appStore.notificationSettings = this.user.preferences.notifications
}
}
用户偏好前后端同步,并支持多设备一致体验。
十、统计数据
10.1 提交统计
| 指标 | 数量 |
|---|---|
| 提交数 | 36 |
| 修改文件 | 120+ |
| 新增代码 | 4000+ 行 |
| 删除代码 | 1500+ 行 |
10.2 核心价值
| 方向 | 价值 |
|---|---|
| 用户体验 | 设置保存不丢失,分析页面自动应用偏好 |
| 数据准确性 | TTM、PS、PE_TTM 计算更准确 |
| 系统稳定性 | WebSocket 更稳定,配置读取冲突减少 |
| 开发体验 | 开发和生产环境连接逻辑统一 |
十一、总结
本次更新通过 36 个提交,围绕 用户设置、财务指标、WebSocket 和 UI 体验 做了一次全面优化。
主要成果包括:
- 用户偏好设置系统重构:设置保存到数据库,刷新页面不再丢失。
- 分析偏好自动应用:单股分析和批量分析优先读取用户配置。
- TTM 计算修复:正确处理财报累计值,使用合理公式计算近 12 个月指标。
- PS/PE_TTM 优化:使用 TTM 营业收入和 TTM 净利润计算估值指标。
- Tushare Token 配置优化:数据库配置优先,Web 后台修改可立即生效。
- WebSocket 连接优化:开发、生产、HTTPS 环境自动适配。
- UI 体验改进:数据源注册引导、深色主题修复、关于页面致谢完善。
这些改进显著提升了 TradingAgents-CN 的 用户体验、财务数据准确性、系统稳定性和配置管理能力,也让系统更适合在长期使用、多设备访问和 Docker 部署场景中运行。
✅ 官方唯一渠道:📦 GitHub 仓库:https://github.com/hsliuping/TradingAgents-CN
Aekor AI-API 中转站,让全球顶尖 AI 大模型“触手可及”!你是否曾为这些烦恼头疼?
🔹 人在国内,却总被海外官网 API 的高延迟、掉线、甚至无法访问困扰?
🔹 想用最强的 GPT、Claude 等模型,却卡在海外信用卡、支付审核等重重阻碍?
🔹 官方 API 太贵?Aekor 为你打通“网络-支付-成本”的任督二脉!
💡 Aekor 核心价值:好用、便宜、快 💡
🚀 高速稳定,告别掉线国内专线加速,API 响应低延迟,告别「转圈圈」的焦虑,开发效率瞬间拉满!
🧠 顶尖模型,随需而调涵盖 GPT 系列、Claude 系列等全球主流大厂模型,一次接入,轻松调用!
🎁 免费白嫖,诚意拉满!
注册即送 20 美元体验额度,够你狠狠测试一轮模型质量与线路稳定性了!
⚠️ 温馨提示:API 中转市场虽多但良莠不齐(甚至有些会偷工减料换小模型糊弄事儿)。Aekor 坚持提供正版稳定的服务,但还是建议:先用免费的 20 刀测试是否契合自身需求,满意了再小额充值上车,理性消费不盲目。
文章评论