TradingAgents-CN 实时行情入库服务优化指南:智能频率控制与三源接口轮换实战解析

发布时间:2026/9/11 17:59:54
TradingAgents-CN 实时行情入库服务优化指南:智能频率控制与三源接口轮换实战解析 TradingAgents-CN 实时行情入库服务优化指南智能频率控制与三源接口轮换实战解析【免费下载链接】TradingAgents-CN基于多智能体LLM的中文金融交易框架 - TradingAgents中文增强版项目地址: https://gitcode.com/GitHub_Trending/tr/TradingAgents-CN实时行情入库服务Quotes Ingestion Service是 TradingAgents-CN 中文金融交易框架中负责把全市场近实时行情定时采集并写入 MongoDBmarket_quotes集合的核心模块。本文基于仓库中的 优化总结文档 与 配置指南结合app/services/quotes_ingestion_service.py等源码实现系统讲解本次优化的背景、方案、配置项、工作流程与升级路径。读完本文你将掌握如何按 Tushare 权限等级免费/付费设置采集频率、如何启用 Tushare → AKShare 东方财富 → AKShare 新浪财经的三源轮换、如何用环境变量完成不同场景的落地部署以及如何通过日志验证服务运行状态。优化背景原有方案面临的四大问题优化前的实时行情入库服务存在以下四个直接影响可用性的设计缺陷它们是本次全部改动的出发点默认 30 秒采集频率过高Tushare 免费用户每小时只能调用 2 次rt_k接口而 30 秒采集意味着每小时 120 次调用远超配额上限直接导致免费用户服务不可用。AKShare 只使用单一接口仅调用东方财富接口stock_zh_a_spot_em未使用新浪财经接口stock_zh_a_spot。频繁且集中地请求单一接口容易触发反爬机制被封锁 IP。BaoStock 无实时行情接口BaoStock 本身不提供实时行情能力但旧代码仍尝试调用白白浪费调度资源与等待时间。无智能频率控制免费用户与付费用户共用同一套配置付费用户的高权限得不到利用免费用户则极易超限。优化方案五处核心改动与源码实现1. 调整默认采集频率30 秒 → 360 秒修改位于 app/core/config.py。默认采集间隔由 30 秒调整为 360 秒6 分钟并在配置描述中明确给出不同用户的推荐区间QUOTES_INGEST_INTERVAL_SECONDS: int Field( default360, description实时行情采集间隔秒。默认360秒6分钟免费用户建议300秒付费用户可设置5-60秒 )效果每小时采集 10 次其中 Tushare 最多被调用 2 次不超限免费用户可正常使用且 6 分钟粒度已能满足大多数行情展示与分析场景。2. 为 AKShare 适配层添加新浪财经接口修改位于 app/services/data_sources/akshare_adapter.py。get_realtime_quotes方法新增source参数支持在东方财富与新浪财经之间切换def get_realtime_quotes(self, source: str eastmoney): 获取全市场实时快照 Args: source: eastmoney东方财富或 sina新浪财经 if source sina: df ak.stock_zh_a_spot() # 新浪财经接口 else: df ak.stock_zh_a_spot_em() # 东方财富接口源码中值得注意的细节是列名兼容层两个接口返回的 DataFrame 列名并不一致如代码列可能是代码/code/symbol/股票代码价格列可能是最新价/现价/price等适配层通过候选列名依次探测的方式完成归一化例如code_col next((c for c in [代码, code, symbol, 股票代码] if c in df.columns), None) price_col next((c for c in [最新价, 现价, 最新价(元), price, 最新, trade] if c in df.columns), None)效果支持两个 AKShare 接口轮换使用降低被封 IP 的风险提高服务可靠性。3. 实现三种接口轮换机制修改位于 app/services/quotes_ingestion_service.py。服务内部维护轮换源列表与索引_get_next_source每次调用返回下一个数据源轮换顺序Tusharert_kAKShare 东方财富AKShare 新浪财经def _get_next_source(self) - Tuple[str, Optional[str]]: 获取下一个数据源轮换机制 if not settings.QUOTES_ROTATION_ENABLED: # 未启用轮换使用默认优先级 return tushare, None # 轮换逻辑0Tushare, 1AKShare东方财富, 2AKShare新浪财经 current_source self._rotation_sources[self._rotation_index] self._rotation_index (self._rotation_index 1) % len(self._rotation_sources) if current_source tushare: return tushare, None elif current_source akshare_eastmoney: return akshare, eastmoney else: # akshare_sina return akshare, sina当QUOTES_ROTATION_ENABLEDfalse时则回退到默认优先级Tushare 优先的取数策略。效果三种接口轮流使用避免单一接口被限流提高整体稳定性。4. 添加 Tushare 调用次数限制滑动时间窗口对应实现为 quotes_ingestion_service.py 中的_can_call_tushare。免费用户通过一个基于 deque 的滑动窗口记录最近一小时的调用时间戳超过_tushare_hourly_limit默认 2则跳过本次 Tushare 调用def _can_call_tushare(self) - bool: 判断是否可以调用 Tushare rt_k 接口 if self._tushare_has_premium: return True # 付费用户不限制 # 免费用户检查每小时调用次数 now datetime.now(self.tz) one_hour_ago now - timedelta(hours1) # 清理1小时前的记录 while self._tushare_call_times and self._tushare_call_times[0] one_hour_ago: self._tushare_call_times.popleft() # 检查是否超过限制 if len(self._tushare_call_times) self._tushare_hourly_limit: logger.warning(⚠️ Tushare rt_k 接口已达到每小时调用限制跳过本次调用) return False return True每次 Tushare 调用成功后通过_record_tushare_call将调用时间追加进队列def _record_tushare_call(self) - None: 记录 Tushare 调用时间 self._tushare_call_times.append(datetime.now(self.tz))效果免费用户每小时最多调用 2 次超过限制自动跳过并降级到 AKShare不影响服务正常运行。5. 自动检测 Tushare 付费权限对应实现为 quotes_ingestion_service.py 中的_check_tushare_permission。服务首次运行时会通过TushareAdapter尝试调用rt_k(ts_code000001.SZ)探测权限def _check_tushare_permission(self) - bool: 检测 Tushare rt_k 接口权限 try: adapter TushareAdapter() df adapter._provider.api.rt_k(ts_code000001.SZ) if df is not None and not getattr(df, empty, True): logger.info(✅ 检测到 Tushare rt_k 接口权限付费用户) self._tushare_has_premium True else: logger.info(⚠️ Tushare rt_k 接口无权限免费用户) self._tushare_has_premium False except Exception as e: if 权限 in str(e) or permission in str(e): self._tushare_has_premium False return self._tushare_has_premium值得说明的是源码中还处理了两种边界情况当 Tushare 适配器整体不可用adapter.is_available()返回 False例如未配置 Token时直接跳过检测当异常信息中包含权限/permission/没有访问等关键词时判定为免费用户否则按一般性失败降级处理。检测结果只会执行一次_tushare_permission_checked标记并在run_once中输出对应建议日志付费用户提示可将QUOTES_INGEST_INTERVAL_SECONDS设置为 5-60 秒以充分利用权限免费用户提示当前每小时最多 2 次调用及当前采集间隔。新增配置项全览本次优化在 app/core/config.py 中新增/调整了 7 个核心配置项以下为.env写法括号内为默认值与说明# # 实时行情入库服务配置 # # 是否启用实时行情入库服务 QUOTES_INGEST_ENABLEDtrue # 采集间隔秒 # - 免费用户建议: 300-600 秒5-10分钟 # - 付费用户建议: 5-60 秒 # - 默认: 360 秒6分钟 QUOTES_INGEST_INTERVAL_SECONDS360 # 休市期/启动兜底补数 QUOTES_BACKFILL_ON_STARTUPtrue QUOTES_BACKFILL_ON_OFFHOURStrue # # 接口轮换和限流配置 # # 启用接口轮换机制 # - true: 轮流使用 Tushare/AKShare东方财富/AKShare新浪财经 # - false: 按默认优先级使用Tushare AKShare QUOTES_ROTATION_ENABLEDtrue # Tushare rt_k 接口每小时调用次数限制 # - 免费用户: 2 次Tushare 官方限制 # - 付费用户: 可设置更高如 1000 QUOTES_TUSHARE_HOURLY_LIMIT2 # 自动检测 Tushare rt_k 接口权限 # - true: 首次运行自动检测付费用户会收到提示 # - false: 不检测按配置运行 QUOTES_AUTO_DETECT_TUSHARE_PERMISSIONtrue对应的 Pydantic 定义含类型与约束位于 app/core/config.py其中QUOTES_INGEST_INTERVAL_SECONDSint默认360描述中明确免费用户建议 300 秒付费用户可设置 5-60 秒QUOTES_ROTATION_ENABLEDbool默认TrueQUOTES_TUSHARE_HOURLY_LIMITint默认2QUOTES_AUTO_DETECT_TUSHARE_PERMISSIONbool默认True。另外Tushare 基础配置TUSHARE_TOKEN、TUSHARE_ENABLED、TUSHARE_TIER与行情服务联动TUSHARE_TOKEN留空或QUOTES_TUSHARE_HOURLY_LIMIT0时即可实现纯 AKShare模式。工作流程免费用户与付费用户的时间轴免费用户6 分钟采集一次默认配置时间轴每6分钟 00:00 → Tushare rt_k第1次调用 06:00 → AKShare 东方财富 12:00 → AKShare 新浪财经 18:00 → Tushare rt_k第2次调用 24:00 → AKShare 东方财富 30:00 → AKShare 新浪财经 36:00 → Tushare rt_k第3次调用但超过限制跳过 36:00 → AKShare 东方财富自动降级 42:00 → AKShare 新浪财经 48:00 → Tushare rt_k第4次调用但超过限制跳过 48:00 → AKShare 东方财富自动降级 54:00 → AKShare 新浪财经 60:00 → 新的一小时开始Tushare 限制重置说明每小时 10 次采集Tushare 最多调用 2 次不超限其余 8 次使用 AKShare自动降级不影响服务。付费用户30 秒采集一次# 修改配置 QUOTES_INGEST_INTERVAL_SECONDS30 QUOTES_TUSHARE_HOURLY_LIMIT1000时间轴每30秒 00:00 → Tushare rt_k 00:30 → AKShare 东方财富 01:00 → AKShare 新浪财经 01:30 → Tushare rt_k 02:00 → AKShare 东方财富 02:30 → AKShare 新浪财经 ...说明每小时 120 次采集Tushare 调用 40 次不超限充分利用付费权限的同时仍保持轮换以提高可靠性。交易时段判断与兜底补数源码中_is_trading_timequotes_ingestion_service.py负责判断是否处于可采集时段仅工作日周一至周五的 9:30-11:30 与 13:00-15:30收盘后含 30 分钟缓冲期确保拿到收盘价才执行采集。非交易时段则根据QUOTES_BACKFILL_ON_OFFHOURS决定是否执行兜底补数backfill_last_close_snapshot_if_needed应用启动时QUOTES_BACKFILL_ON_STARTUPtrue也会在 app/main.py 的启动流程中先创建索引并补数# 启动期若需要在休市时补充上一交易日收盘快照 if settings.QUOTES_BACKFILL_ON_STARTUP: qi QuotesIngestionService() await qi.ensure_indexes() await qi.backfill_last_close_snapshot_if_needed()补数逻辑分两条路径quotes_ingestion_service.pymarket_quotes集合为空时从stock_daily_quotes历史数据集合导入最新交易日收盘数据集合非空但trade_date落后于最新交易日时则通过DataSourceManager.get_realtime_quotes_with_fallback()app/services/data_sources/manager.py拉取近实时快照填充。入库细节字段与批量写入采集到的行情通过_bulk_upsertquotes_ingestion_service.py以pymongo.UpdateOne批量 upsert 写入market_quotes集合字段包括code6 位、symbol、close、pct_chg、amount、volume、open、high、low、pre_close、trade_date、updated_at。代码统一经过_normalize_stock_code标准化处理sz000001/sh600036等前缀与不足 6 位的补零并在集合上建立code唯一索引与updated_at索引ensure_indexes。每次执行还会把同步状态成功与否、数据源、记录数、间隔等写入quotes_ingestion_status集合可通过get_sync_status查询。性能对比优化前后优化前指标免费用户付费用户采集频率30秒30秒每小时采集次数120次120次Tushare 调用次数120次超限120次服务可用性❌ 不可用✅ 可用被封IP风险⚠️ 高⚠️ 中优化后指标免费用户付费用户采集频率6分钟30秒可配置每小时采集次数10次120次Tushare 调用次数2次不超限40次不超限服务可用性✅ 可用✅ 可用被封IP风险✅ 低✅ 低分场景配置方案场景 1免费用户推荐配置# 6分钟采集一次每小时10次 QUOTES_INGEST_ENABLEDtrue QUOTES_INGEST_INTERVAL_SECONDS360 QUOTES_ROTATION_ENABLEDtrue QUOTES_TUSHARE_HOURLY_LIMIT2 QUOTES_AUTO_DETECT_TUSHARE_PERMISSIONtrue说明每小时采集 10 次Tushare 最多调用 2 次不超限其余 8 次使用 AKShare避免被限流或封 IP。场景 2Tushare 付费用户高频采集# 30秒采集一次每小时120次 QUOTES_INGEST_ENABLEDtrue QUOTES_INGEST_INTERVAL_SECONDS30 QUOTES_ROTATION_ENABLEDtrue QUOTES_TUSHARE_HOURLY_LIMIT1000 # 付费用户限制更高 QUOTES_AUTO_DETECT_TUSHARE_PERMISSIONtrue说明充分利用付费权限30 秒更新一次接近实时仍启用轮换提高可靠性。场景 3只使用 AKShare无 Tushare Token# 5分钟采集一次只使用 AKShare QUOTES_INGEST_ENABLEDtrue QUOTES_INGEST_INTERVAL_SECONDS300 QUOTES_ROTATION_ENABLEDtrue QUOTES_TUSHARE_HOURLY_LIMIT0 # 禁用 Tushare QUOTES_AUTO_DETECT_TUSHARE_PERMISSIONfalse # 不配置 Tushare Token TUSHARE_TOKEN说明完全依赖 AKShare免费东方财富与新浪财经接口轮换避免 Tushare 相关错误。场景 4极简配置使用默认值# 只需启用服务其他使用默认值 QUOTES_INGEST_ENABLEDtrue说明默认 6 分钟采集一次自动检测 Tushare 权限自动轮换接口。运行监控与日志解读查看任务状态前端系统配置 → 定时任务管理 → 实时行情入库服务后端日志# 查看实时日志 tail -f logs/app.log | grep 行情入库 # 查看轮换日志 tail -f logs/app.log | grep 使用.*接口获取实时行情关键日志示例成功采集Tushare 使用 Tushare rt_k 接口获取实时行情 ✅ 行情入库完成 sourcetushare, matched5440, modified5440接口轮换AKShare 东方财富 使用 AKShare eastmoney 接口获取实时行情 ✅ AKShare eastmoney 获取到 5440 只股票的实时行情 ✅ 行情入库完成 sourceakshare_eastmoney, matched5440, modified5440Tushare 限流自动降级⚠️ Tushare rt_k 接口已达到每小时调用限制 (2次)跳过本次调用使用 AKShare 备用接口 使用 AKShare sina 接口获取实时行情 ✅ 行情入库完成 sourceakshare_sina, matched5440, modified5440首次运行权限检测付费用户 首次运行检测 Tushare rt_k 接口权限... ✅ 检测到 Tushare rt_k 接口权限付费用户 ✅ 检测到 Tushare 付费权限建议将 QUOTES_INGEST_INTERVAL_SECONDS 设置为 5-60 秒以充分利用权限首次运行权限检测免费用户 首次运行检测 Tushare rt_k 接口权限... ⚠️ Tushare rt_k 接口无权限免费用户 ℹ️ Tushare 免费用户每小时最多调用 2 次 rt_k 接口。当前采集间隔: 360 秒升级步骤与验证从旧版本升级到包含本次优化的版本可参考以下流程完整细节见 配置指南步骤 1更新代码到包含优化版本的分支。步骤 2更新.env配置新配置项均可选不写则使用默认值QUOTES_INGEST_INTERVAL_SECONDS360 QUOTES_ROTATION_ENABLEDtrue QUOTES_TUSHARE_HOURLY_LIMIT2 QUOTES_AUTO_DETECT_TUSHARE_PERMISSIONtrue步骤 3重启后端服务uvicorn app.main:app --reload --host 0.0.0.0 --port 8000步骤 4验证——查看后端日志确认权限检测与接口轮换正常访问前端任务管理页面查看任务状态。常见问题FAQQ1为什么默认是 6 分钟不是 30 秒Tushare 免费用户每小时只能调用 2 次rt_k接口30 秒采集会立即超限导致服务不可用6 分钟是平衡实时性与配额限制的最佳选择。Q2我是付费用户如何设置高频采集修改.env文件设置QUOTES_INGEST_INTERVAL_SECONDS30与QUOTES_TUSHARE_HOURLY_LIMIT1000然后重启后端服务。Q3如何禁用 Tushare只使用 AKShare不配置TUSHARE_TOKEN留空或设置QUOTES_TUSHARE_HOURLY_LIMIT0。Q4接口轮换是什么意思第 1 次采集用 Tushare第 2 次用 AKShare 东方财富第 3 次用 AKShare 新浪财经第 4 次回到 Tushare循环往复。Q5如何查看当前使用的是哪个接口查看后端日志搜索使用.*接口获取实时行情。Q6AKShare 会被封 IP 吗6 分钟采集一次被封概率很低启用轮换机制后东方财富与新浪财经交替使用进一步降低风险即使被封也会自动切换到另一个接口。Q7如何手动触发采集前端系统配置 → 定时任务管理 → 实时行情入库服务 → 立即执行APIPOST /api/scheduler/jobs/quotes_ingestion_service/trigger。影响范围与总结本次优化涉及 app/core/config.py、app/services/data_sources/akshare_adapter.py、app/services/quotes_ingestion_service.py 三个源码文件影响所有依赖实时行情的功能前端股票行情展示、自选股列表与 AI 分析报告。核心改进默认 6 分钟采集免费用户友好三种接口轮换避免限流与封 IP自动检测 Tushare 权限智能调整调用策略付费用户可配置 5-60 秒高频采集接近实时行情。升级建议免费用户直接使用默认配置付费用户设置 30-60 秒高频采集仅依赖 AKShare 的用户禁用 Tushare 即可。日常运维建议定期查看后端日志关注接口轮换与限流日志并根据实际行情时效需求动态调整QUOTES_INGEST_INTERVAL_SECONDS。【免费下载链接】TradingAgents-CN基于多智能体LLM的中文金融交易框架 - TradingAgents中文增强版项目地址: https://gitcode.com/GitHub_Trending/tr/TradingAgents-CN创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考