ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

TradingAgents-CN 多市场支持与异步事件循环优化实战解析

TradingAgents-CN 多市场支持与异步事件循环优化实战解析 TradingAgents-CN 多市场支持与异步事件循环优化实战解析【免费下载链接】TradingAgents-CN基于多智能体LLM的中文金融交易框架 - TradingAgents中文增强版项目地址: https://gitcode.com/GitHub_Trending/tr/TradingAgents-CN本文基于 TradingAgents-CN 2025-11-12 发布的多市场支持与异步优化更新共 18 个提交系统讲解港股/美股/A股三大市场支持的完整实现、港股 1-5 位代码识别规则、多市场模拟交易、港股数据源优先级与缓存机制以及困扰 FastAPI 异步架构的attached to a different loop事件循环冲突的根本解法。读者将掌握多市场代码识别、数据源降级策略与纯异步数据准备链路的落地模式并能在自己的项目中直接复用这些方案。 更新概述2025年11月12日TradingAgents-CN 完成了多市场支持和异步事件循环优化的集中交付。通过18 个提交实现了多市场支持完整支持 A股、港股、美股三大市场模拟交易增强支持多市场模拟交易和持仓管理港股代码识别支持 1-5 位数字的港股代码格式异步优化修复事件循环冲突确保数据同步稳定性数据源优化港股数据源优先级支持和缓存机制Bug修复修复多个关键问题提升系统稳定性按类别统计多市场支持 3 个提交、模拟交易 4 个、港股优化 5 个、异步优化 4 个、数据准备 1 个、Bug 修复 1 个共修改 25 个文件、新增 5 个文件净增代码 1700 行。 核心改进1. 多市场支持功能1.1 港股和美股全面支持提交记录126e7b9- 实现港股和美股支持功能6ac64a0- 实现港股数据源优先级支持参考美股模式8543cab- feat: 优化港股数据获取添加财务指标和缓存机制功能特性港股支持✅ 港股代码识别1-5位数字✅ 港股行情数据获取AKShare✅ 港股财务指标PE、PB、PS、ROE、负债率✅ 港股基本信息查询✅ 港股数据缓存机制美股支持✅ 美股代码识别字母代码✅ 美股行情数据获取Finnhub✅ 美股基本信息查询✅ 美股数据源优先级数据源优先级港股数据源采用与美股一致的多级降级策略优先使用 AKShare依次回退到 Finnhub 与 yfinance# 港股数据源优先级 HK_DATA_SOURCE_PRIORITY [ akshare, # 优先使用AKShare finnhub, # 备用Finnhub yfinance # 最后使用yfinance ]这种主源 备源 兜底源的结构保证单一日源不可用时仍能返回数据。从源码结构看该策略参考了 foreign_stock_service.py 中美股多数据源Finnhub 等的成功模式并将港股接入同一套统一接口体系。1.2 港股代码识别优化提交记录f8ef8b8- feat: 支持1-5位数字的港股代码识别问题描述系统原本只识别 4 位数字的港股代码但港股实际使用 1-5 位数字1位数字1、22位数字01、883位数字700腾讯、3884位数字1810小米、9988阿里5位数字00700、09988、01810解决方案核心判定逻辑位于 frontend/src/utils/market.ts 的getMarketByStockCode()函数按后缀 → 位数 → 字母的优先级依次判定// frontend/src/utils/market.ts export const getMarketByStockCode (stockCode: string): string { const code String(stockCode ?? ).trim().toUpperCase() // 港股明确带 .HK 后缀 if (code.endsWith(.HK)) { return 港股 } // A股6位数字 if (/^\d{6}$/.test(code)) { return A股 } // 港股1-5位数字3位、4位、5位都是港股 // 例如700(腾讯)、1810(小米)、9988(阿里巴巴) if (/^\d{1,5}$/.test(code)) { return 港股 } // 美股纯字母至少1个字母 if (/^[A-Z]$/.test(code)) { return 美股 } // 默认返回A股 return A股 }从实际源码可以看到判定规则比文档示例更完整除了1-5 位数字判为港股外还优先处理了带.HK后缀的显式标记、6 位数字判为 A 股、纯字母判为美股的边界情况并且把输入统一trim().toUpperCase()后再比较避免大小写与空格干扰。同一文件还提供了两个配套工具函数normalizeMarketForAnalysis()将主板/创业板/科创板/沪市/深市/上交所等中文板块名及CN/SH/SZ/SSE/SZSE、HK/HKEX、US/NASDAQ/NYSE/AMEX等交易所代码统一规范化为A股/港股/美股三值之一exchangeCodeToMarket()将sz/sh/bj、hk、us等交易所代码映射为市场类型。改进内容修改getMarketByStockCode()函数支持1-5位数字识别在 SingleAnalysis.vue 添加 URL 参数自动识别市场类型输入框提示语已更新为如000001、AAPL、700、1810覆盖三大市场示例更新输入框提示文本展示多样化的港股代码格式添加单元测试验证识别逻辑效果✅ 访问localhost:3000/analysis/single?stock01810自动识别为港股✅ 支持700、1810、9988等各种格式的港股代码✅ URL 参数自动切换市场类型2. 模拟交易多市场支持2.1 多市场模拟交易功能提交记录6fa2424- 实现模拟交易多市场支持A股/港股/美股ebffa66- 前端UI增强支持多市场模拟交易显示6c81a91- 修复模拟交易多市场支持的问题ba002c0- 修复模拟交易多市场功能的价格获取和前端过滤功能特性多市场持仓管理✅ 支持 A股、港股、美股持仓✅ 按市场分类显示持仓✅ 多市场盈亏统计✅ 市场切换过滤多市场价格获取价格获取按市场类型分发到各自的行情接口避免用 A 股接口取港股/美股价格导致返回 0# 根据市场类型获取实时价格 if market A股: price get_china_stock_price(symbol) elif market 港股: price get_hk_stock_price(symbol) elif market 美股: price get_us_stock_price(symbol)前端UI增强✅ 市场类型标签显示✅ 市场过滤器✅ 多市场持仓汇总✅ 市场切换动画2.2 修复的问题问题表现解决方案价格获取错误港股/美股价格显示为0根据市场类型调用对应API前端过滤失效市场过滤器不生效修复过滤逻辑持仓显示混乱多市场持仓混在一起按市场分类显示UnboundLocalError重复导入导致错误删除重复的导入语句3. 港股数据优化3.1 港股财务指标增强提交记录8543cab- feat: 优化港股数据获取添加财务指标和缓存机制新增财务指标# app/services/foreign_stock_service.py fundamentals { pe_ratio: pe_ratio, # 市盈率 pb_ratio: pb_ratio, # 市净率 ps_ratio: ps_ratio, # 市销率新增 roe: roe, # 净资产收益率新增 debt_ratio: debt_ratio, # 负债率新增 market_cap: market_cap, # 市值 total_shares: total_shares # 总股本 }数据来源AKShare APIstock_individual_info_em()实时更新无需手动同步在 foreign_stock_service.py 的_format_hk_info()中可以看到这些字段最终如何映射给前端ps_ratio同时输出为ps与ps_ttmroe/debt_ratio直接透传market_cap统一除以1e8换算成亿元单位的total_mv与前端展示约定保持一致。此外港股财务指标的底层获取在 improved_hk.py 的get_financial_indicators()中通过 AKShare 的stock_financial_hk_analysis_indicator_em接口实现返回的指标集远比文档示例丰富包括每股指标eps_basic、eps_diluted、eps_ttm、bps、per_netcash_operate盈利能力roe_avg、roe_yearly、roa、roic_yearly、net_profit_ratio、gross_profit_ratio营收指标operate_income及同比/环比增速、gross_profit、holder_profit偿债能力debt_asset_ratio、current_ratio现金流ocf_sales3.2 港股数据缓存机制提交记录8543cab- feat: 优化港股数据获取添加财务指标和缓存机制缓存策略# tradingagents/dataflows/providers/hk/improved_hk.py # 全局缓存和线程锁 _hk_stock_cache {} _cache_lock threading.Lock() CACHE_EXPIRY 300 # 5分钟缓存 def get_hk_stock_info_cached(symbol: str) - Dict: 带缓存的港股信息获取 with _cache_lock: # 检查缓存 if symbol in _hk_stock_cache: cached_data, timestamp _hk_stock_cache[symbol] if time.time() - timestamp CACHE_EXPIRY: return cached_data # 获取新数据 data fetch_hk_stock_info(symbol) _hk_stock_cache[symbol] (data, time.time()) return data实际源码中的缓存机制比示例更完善是文件持久化缓存 内存全局缓存双层结构文件级缓存_load_cache/_save_cache缓存写入统一数据目录下的hk_stock_cache.jsonTTL 由配置项TA_HK_CACHE_TTL_SECONDS对应ta_hk_cache_ttl_seconds默认 24 小时控制内存级缓存 线程锁_akshare_hk_spot_cache以 10 分钟 TTL 缓存ak.stock_hk_spot()全量快照配合_akshare_hk_spot_lock互斥锁最长等待 60 秒保证多线程并发时只有一个线程调用 AKShare 接口其余线程直接复用缓存结果内置名称映射表内置腾讯、银行、保险、科技等 30 只主流港股的中文名称含0700/00700/0700.HK多种格式命中时零 API 调用请求速率限制_rate_limit()通过TA_HK_RATE_LIMIT_WAIT_SECONDS默认 5 秒控制两次 API 调用的最小间隔。优化效果✅ 减少 AKShare API 调用次数提升响应速度✅ 避免并发请求导致的 API 限流问题✅ 提供更完整的港股财务数据展示3.3 港股行情数据修复提交记录e40183f- 修复港股行情数据获取问题ce071cd- 完善请求去重机制修复并发请求问题修复内容修复港股行情数据获取失败问题完善请求去重机制避免重复请求添加详细的日志记录便于调试和监控在港股历史数据兼容函数get_hk_stock_data_akshare()中还额外实现了pre_close字段回填用前一日close平移、涨跌额/涨跌幅计算、统一技术指标注入add_all_indicators含 MA/MACD/RSI/BOLL以及基于eps_ttm/bps的 PE/PB 动态计算最终以结构化的 Markdown 文本返回给上层分析模块。4. UI/UX 改进4.1 港股和美股详情页优化提交记录d522658- fix: 港股和美股详情页隐藏同步数据按钮改进内容!-- frontend/src/views/Stocks/Detail.vue -- el-button v-ifmarket ! HK market ! US clicksyncData 同步数据 /el-button原因港股和美股数据通过 API 实时获取不需要手动同步避免用户对不可用功能产生困惑该功能仅适用于 A股市场4.2 自选股优化提交记录4832288- 自选股优化优化内容✅ 支持多市场自选股管理✅ 自动识别股票市场类型✅ 优化自选股列表显示✅ 改进自选股添加流程5. 异步事件循环优化核心修复这是本次更新中技术含量最高、也最值得复用的部分——它修复了一个 FastAPI MotorMongoDB 异步驱动架构下的经典陷阱。5.1 问题描述提交记录395f83d- 修复同步阻塞调用导致事件循环卡死的问题27488d6- fix: 修复A股分析时数据同步的事件循环冲突问题048b576- fix: 修复A股数据同步的事件循环冲突问题正确方案9316d4b- fix: 添加完整的异步数据准备方法链错误现象当通过 FastAPI 发起 A 股分析时如果数据库没有数据需要同步系统会报错Task Task pending got Future Future pending attached to a different loop根本原因FastAPI 路由运行在主事件循环中execute_analysis_background()调用await asyncio.to_thread(prepare_stock_data, ...)prepare_stock_data()内部调用_trigger_data_sync_sync()_trigger_data_sync_sync()创建新的事件循环新事件循环中调用_trigger_data_sync_async()使用 MotorMongoDB 异步驱动Motor 连接绑定到主事件循环在新事件循环中调用会冲突5.2 错误的尝试第一次尝试27488d6def _trigger_data_sync_sync(self, ...): try: running_loop asyncio.get_running_loop() # 检测到正在运行的事件循环创建新的事件循环 loop asyncio.new_event_loop() asyncio.set_event_loop(loop) result loop.run_until_complete(self._trigger_data_sync_async(...)) loop.close() except RuntimeError: # 没有运行的事件循环使用原有逻辑 ...为什么失败❌ Motor 连接在主事件循环中创建❌ 在新事件循环中调用 Motor 操作会导致 attached to a different loop 错误值得注意的是_trigger_data_sync_sync()的这个检测正在运行的事件循环 → 新建循环 → run_until_complete → close的包装逻辑至今仍保留在 stock_validator.py 中作为同步上下文的兼容兜底但在 FastAPI 异步请求路径上它被证明会触发 Motor 跨循环错误因此被异步链路取代。5.3 正确的解决方案核心思路不要创建新事件循环直接在主事件循环中运行异步代码。实现步骤创建异步版本的数据准备函数048b576# tradingagents/utils/stock_validator.py async def prepare_stock_data_async(stock_code: str, market_type: str auto, period_days: int None, analysis_date: str None) - StockDataPreparationResult: 异步版本预获取和验证股票数据 专门用于 FastAPI 异步上下文避免事件循环冲突 preparer get_stock_preparer() # 1. 基本格式验证 format_result preparer._validate_format(stock_code, market_type) if not format_result.is_valid: return format_result # 2. 自动检测市场类型 if market_type auto: market_type preparer._detect_market_type(stock_code) # 3. 预获取数据并验证使用异步版本 return await preparer._prepare_data_by_market_async( stock_code, market_type, period_days, analysis_date )创建异步版本的市场分发函数9316d4basync def _prepare_data_by_market_async(self, stock_code: str, market_type: str, period_days: int, analysis_date: str) - StockDataPreparationResult: 根据市场类型预获取数据异步版本 if market_type A股: return await self._prepare_china_stock_data_async( stock_code, period_days, analysis_date ) elif market_type 港股: return self._prepare_hk_stock_data(stock_code, period_days, analysis_date) elif market_type 美股: return self._prepare_us_stock_data(stock_code, period_days, analysis_date)从 stock_validator.py 的现有实现看该函数已完整落地A 股走异步版本港股与美股分支调用同步准备函数这两类市场数据来自实时 API不涉及 Motor 同步因此保持同步实现是安全的。创建异步版本的A股数据准备函数9316d4basync def _prepare_china_stock_data_async(self, stock_code: str, period_days: int, analysis_date: str) - StockDataPreparationResult: 预获取A股数据异步版本包含数据库检查和自动同步 # 检查数据库 db_check_result self._check_database_data(stock_code, start_date, end_date) # 如果需要同步使用异步方法 if not db_check_result[has_data] or not db_check_result[is_latest]: # 直接调用异步方法不创建新的事件循环 sync_result await self._trigger_data_sync_async( stock_code, start_date, end_date ) # 获取数据并返回结果 ...修改服务层调用048b576# app/services/simple_analysis_service.py # 修改前 validation_result await asyncio.to_thread( prepare_stock_data, stock_codestock_code, market_typemarket_type, period_days30, analysis_dateanalysis_date ) # 修改后 from tradingagents.utils.stock_validator import prepare_stock_data_async validation_result await prepare_stock_data_async( stock_codestock_code, market_typemarket_type, period_days30, analysis_dateanalysis_date )在 simple_analysis_service.py 中可以看到该修复的最终形态execute_analysis_background()在异步上下文中直接await prepare_stock_data_async(...)并将analysis_date统一规范化为YYYY-MM-DD字符串后传入。5.4 完整的异步调用链FastAPI (主事件循环) ↓ execute_analysis_background() (async) ↓ await prepare_stock_data_async() (async) ✅ ↓ await _prepare_data_by_market_async() (async) ✅ ↓ await _prepare_china_stock_data_async() (async) ✅ ↓ await _trigger_data_sync_async() (async) ↓ await service.sync_historical_data() (使用 Motor) ↓ ✅ 所有操作在同一事件循环中Motor 正常工作整条链路从入口到 Motor 调用全部使用await贯穿全程不脱离主事件循环。5.5 对比分析方案调用链结果错误方案asyncio.to_thread() → 新事件循环 → Motor❌ 事件循环冲突正确方案直接 await → 同一事件循环 → Motor✅ 正常工作参考实现/api/stock-sync/single接口✅ 直接 await 异步服务5.6 技术要点Motor 的事件循环绑定Motor 连接在创建时绑定到当前事件循环不能在不同的事件循环中使用同一个连接必须在同一事件循环中完成所有异步操作asyncio.to_thread() 的限制在线程池中运行同步函数线程仍然知道主线程有正在运行的事件循环不适合运行需要访问异步资源如 Motor的代码正确的异步模式在异步上下文中直接await不要创建新的事件循环保持整个调用链在同一事件循环中简而言之凡是在 FastAPI 异步请求路径上可能触达 Motor 的代码都要提供完整的 async 版本方法链同步包装器新建事件循环只应保留给真正没有事件循环的同步上下文。6. A股数据准备功能完善提交记录2385be0- 完善A股数据准备功能自动检查和同步数据功能特性自动数据检查✅ 检查数据库中的历史数据是否存在✅ 检查数据是否为最新✅ 检查数据完整性自动数据同步✅ 数据不存在时自动同步✅ 数据过期时自动更新✅ 同步失败时提供友好提示数据验证✅ 验证股票代码格式✅ 验证股票是否存在✅ 验证数据有效性从源码看同步动作由_trigger_data_sync_async()stock_validator.py承担它会按数据库配置的数据源优先级依次同步历史数据、财务数据与实时行情并返回包含success、message、synced_records、data_source的结构化结果_prepare_china_stock_data_async()根据该结果拼接cache_status文案如数据已同步最终汇总为StockDataPreparationResult。 统计数据提交统计类别提交数主要改进多市场支持3港股/美股支持、数据源优先级模拟交易4多市场持仓、价格获取、UI增强港股优化5代码识别、财务指标、缓存机制异步优化4事件循环修复、异步调用链数据准备1A股数据自动检查和同步Bug修复1重复导入、过滤逻辑总计18-代码变更统计指标数量修改文件25新增文件5新增代码2000 行删除代码300 行净增代码1700 行 核心价值1. 市场覆盖范围扩大✅ 支持 A股、港股、美股三大市场✅ 多市场数据源优先级支持✅ 多市场模拟交易功能预期效果来源于开发团队的发布评估市场覆盖范围从 1 个市场扩展到 3 个市场用户可交易标的数量显著提升2. 系统稳定性提升✅ 修复异步事件循环冲突✅ 完善数据同步机制✅ 优化缓存策略预期效果来源于开发团队的发布评估数据同步成功率大幅提升系统崩溃率显著降低3. 用户体验改进✅ 港股代码自动识别✅ URL 参数自动切换市场✅ 多市场持仓分类显示预期效果来源于开发团队的发布评估用户操作便捷性提升用户满意度提升 总结本次更新通过 18 个提交完成了多市场支持和异步事件循环优化的全面工作。主要成果包括多市场支持完整支持 A股、港股、美股三大市场模拟交易增强支持多市场模拟交易和持仓管理港股代码识别支持 1-5 位数字的港股代码格式异步优化修复事件循环冲突确保数据同步稳定性数据源优化港股数据源优先级支持和缓存机制Bug修复修复多个关键问题提升系统稳定性这些改进显著扩大了系统的市场覆盖范围提升了系统稳定性和用户体验为用户提供更全面、更稳定的多市场股票分析平台。 下一步计划添加更多港股财务指标优化美股数据获取性能实现跨市场数据对比分析添加多市场资产配置建议完善多市场回测功能优化多市场数据缓存策略 相关资源港股代码识别规则见本文港股代码识别优化小节核心实现位于 frontend/src/utils/market.ts异步事件循环最佳实践见本文异步事件循环优化小节核心实现位于 tradingagents/utils/stock_validator.py 与 app/services/simple_analysis_service.py多市场数据源配置docs/data/data-sources.md港股数据源与缓存实现tradingagents/dataflows/providers/hk/improved_hk.py港股/美股数据格式化app/services/foreign_stock_service.py模拟交易使用指南多市场持仓管理入口位于前端模拟交易视图后端按市场类型分发价格获取逻辑见本文模拟交易多市场支持小节【免费下载链接】TradingAgents-CN基于多智能体LLM的中文金融交易框架 - TradingAgents中文增强版项目地址: https://gitcode.com/GitHub_Trending/tr/TradingAgents-CN创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表