TradingAgents-CN 股票代码格式验证与标准化:A股、美股、港股三市场前端校验与后端快速失败实现
【免费下载链接】TradingAgents-CN基于多智能体LLM的中文金融交易框架 - TradingAgents中文增强版项目地址: https://gitcode.com/GitHub_Trending/tr/TradingAgents-CN
本指南完整梳理 TradingAgents-CN 项目中股票代码验证体系的落地实现,覆盖单股分析页面前端的三市场(A股、美股、港股)格式校验、自动市场识别与代码标准化,以及分析任务启动前的后端预获取验证与快速失败机制。读者将掌握stockValidator.ts与stock_validator.py的核心校验规则、港股代码格式化陷阱的修复方案,以及如何将验证结果接入分析任务状态机,避免无效请求浪费 LLM 与数据源资源。
背景:为什么需要两层股票代码验证
TradingAgents-CN 是基于多智能体 LLM 的中文金融交易框架,用户可在单股分析页面输入任意股票代码发起多智能体深度分析。此前系统存在两个突出问题:
- 前端无校验:输入框对任意文本放行,
1234567、50xxxx这类非法代码会直接被提交,用户直到分析失败才看到错误。 - 后端不验证即分析:用户反馈输入港股
00700(腾讯控股)后,后端未识别股票不存在或格式错误,而是继续执行分析,浪费时间和资源;且港股代码格式化逻辑有误(00700→00700.HK而非正确的0700.HK)。
解决方案采用前端格式校验 + 后端数据预获取验证的双层架构:前端负责格式、市场识别与标准化(用户体验层),后端负责"代码是否存在、数据是否可获取"的快速失败(资源保护层)。相关设计与修复记录见 docs/integration/data-sources/stock_code_validation.md 与 docs/integration/data-sources/stock_code_validation_backend.md。
支持的市场代码格式规则
系统支持 A股、美股、港股三种市场的代码格式校验与自动识别,规则如下。
A股:6位数字,前缀白名单
| 前缀 | 板块 | 示例 |
|---|---|---|
60xxxx | 上海主板 | 600519 贵州茅台 |
68xxxx | 科创板 | 688981 中芯国际 |
00xxxx | 深圳主板 | 000001 平安银行 |
30xxxx | 创业板 | 300750 宁德时代 |
43xxxx/83xxxx/87xxxx | 北交所 | — |
- ✅ 通过:
000001(平安银行)、600519(贵州茅台)、000858(五粮液)、300750(宁德时代) - ✗ 失败:
00001(仅5位)、1234567(超过6位)、50xxxx(前缀不在白名单)
美股:1-5个大写字母,可选单点号
- 大小写不敏感,自动转为大写(
aapl→AAPL) - 支持带点号的类别股代码,如
BRK.B(伯克希尔B股) - ✅ 通过:
AAPL、MSFT、GOOGL、TSLA、BRK.B - ✗ 失败:
ABCDEF(超过5个字母)、123(纯数字)、A.B.C(多个点号)
港股:1-5位数字,自动补齐前导0
- 自动将不足5位的代码补齐前导0至5位(
700→00700) - ✅ 通过:
00700(腾讯控股)、09988(阿里巴巴)、01810(小米集团)、03690(美团),以及不带前导0的700、9988 - ✗ 失败:
123456(超过5位)、0(无效代码)
前端实现:单股分析页面的实时校验
核心工具函数 stockValidator.ts
前端校验逻辑全部收敛在 frontend/src/utils/stockValidator.ts,返回统一的StockValidationResult结构(valid、market、message、normalizedCode),便于组件层与后续扩展复用。
A股校验:先剥离非数字字符,再用^\d{6}$校验位数,最后检查前两位前缀是否在白名单['60', '68', '00', '30', '43', '83', '87']内:
export function validateAStock(code: string): StockValidationResult { const cleanCode = code.trim().replace(/[^0-9]/g, '') if (!/^\d{6}$/.test(cleanCode)) { return { valid: false, message: 'A股代码必须是6位数字' } } const prefix = cleanCode.substring(0, 2) const validPrefixes = ['60', '68', '00', '30', '43', '83', '87'] if (!validPrefixes.includes(prefix)) { return { valid: false, message: 'A股代码前缀不正确(支持:60/68/00/30/43/83/87开头)' } } return { valid: true, market: 'A股', normalizedCode: cleanCode } }美股校验:正则^[A-Z]{1,5}(\.[A-Z])?$同时约束字母数量(1-5)与点号数量(最多1个、点号后仅1个字母),并额外防御"全是点号"的空代码场景:
export function validateUSStock(code: string): StockValidationResult { const cleanCode = code.trim().toUpperCase().replace(/[^A-Z.]/g, '') if (!/^[A-Z]{1,5}(\.[A-Z])?$/.test(cleanCode)) { return { valid: false, message: '美股代码格式不正确(1-5个字母,如:AAPL、BRK.B)' } } if (cleanCode.replace(/\./g, '').length === 0) { return { valid: false, message: '美股代码不能为空' } } return { valid: true, market: '美股', normalizedCode: cleanCode } }港股校验:位数限制^\d{1,5}$,通过后用padStart(5, '0')补齐前导0,实现代码标准化:
export function validateHKStock(code: string): StockValidationResult { const cleanCode = code.trim().replace(/[^0-9]/g, '') if (!/^\d{1,5}$/.test(cleanCode)) { return { valid: false, message: '港股代码必须是1-5位数字' } } const normalizedCode = cleanCode.padStart(5, '0') return { valid: true, market: '港股', normalizedCode: normalizedCode } }自动识别入口validateStockCode(code, marketHint?):若调用方提供了marketHint(当前选中的市场),则按该市场强校验;否则按规则自动识别——纯数字且6位 → A股,纯数字且1-5位 → 港股,含字母 → 美股,其余返回"无法识别的股票代码格式"。工具模块还提供了getStockCodeFormatHelp、getStockCodeExamples、formatStockCode等辅助函数,用于输入框提示语、示例展示与显示格式化。
Vue 组件集成 SingleAnalysis.vue
frontend/src/views/Analysis/SingleAnalysis.vue 中完成了三处接线(文件内行号可定位,如导入见L718):
- 响应式状态(
L816附近):stockCodeError与stockCodeHelp两个ref<string>分别承载错误信息与帮助提示。 - 输入与失焦事件:
@input时清空错误并展示当前市场的格式帮助;@blur触发validateStockCodeInput()执行真实校验。 - 市场切换重新验证:
onMarketChange中若已有输入代码,立即按新市场重新验证,保证代码与市场类型始终匹配。
validateStockCodeInput的完整逻辑如下(见 SingleAnalysis.vueL853附近):
const validateStockCodeInput = () => { const code = analysisForm.stockCode.trim() if (!code) { stockCodeError.value = '' stockCodeHelp.value = '' return } const validation = validateStockCode(code, analysisForm.market) if (!validation.valid) { stockCodeError.value = validation.message || '股票代码格式不正确' stockCodeHelp.value = '' } else { stockCodeError.value = '' stockCodeHelp.value = `✓ ${validation.market}代码格式正确` // 自动更新市场类型 if (validation.market && validation.market !== analysisForm.market) { analysisForm.market = validation.market ElMessage.success(`已自动识别为${validation.market}`) } // 标准化代码 if (validation.normalizedCode) { analysisForm.stockCode = validation.normalizedCode } } }值得一提的细节:校验通过后若识别出的市场与用户当前选择不一致,组件会自动切换市场选择器并弹出已自动识别为X市场的成功提示,同时用normalizedCode回写输入框(如aapl→AAPL、700→00700),实现了"输入即标准化"。
输入框与提示样式
输入框使用 Element Plus 的el-input,带TrendCharts前缀图标、clearable可清空、失焦校验与错误态样式绑定;下方错误/成功提示区域分别用WarningFilled(红色#f56c6c)与InfoFilled(绿色#67c23a)图标渲染。市场选择器el-select的三个el-option在标签旁附灰色小字说明格式(A股:6位数字;美股:1-5个字母;港股:1-5位数字)。SCSS 中通过:deep()覆写el-input__inner的font-weight: 600与text-transform: uppercase,并在.is-error时高亮边框为红色。完整样式见 frontend/src/views/Analysis/SingleAnalysis.vue。
后端实现:分析开始前的快速失败验证
仅有前端格式校验并不足够——格式合法的代码仍可能指向不存在的股票。为此后端在分析任务真正启动前,通过 tradingagents/utils/stock_validator.py 完成"代码是否存在 + 数据能否获取"的预获取验证。
数据准备器与结果对象
模块核心是StockDataPreparer类,其prepare_stock_data(stock_code, market_type="auto", period_days=30, analysis_date=None)按三步执行:
_validate_format:基本格式验证(见下文);_detect_market_type:market_type="auto"时按正则自动判定市场(6位数字 → A股;\d{4,5}.HK或纯4-5位数字 → 港股;1-5位字母 → 美股);_prepare_data_by_market:按市场分发到_prepare_china_stock_data/_prepare_hk_stock_data/_prepare_us_stock_data。
验证结果统一封装为StockDataPreparationResult(is_valid、stock_code、market_type、stock_name、error_message、suggestion、has_historical_data、has_basic_info、data_period_days、cache_status),并提供to_dict()便于日志与状态持久化。为保持向后兼容,模块同时导出StockValidator、get_stock_validator、validate_stock_exists等别名,并针对 FastAPI 异步上下文提供prepare_stock_data_async(避免事件循环冲突,通过asyncio.to_thread或异步内部方法执行)。
格式验证规则(后端视角)
# A股:必须是6位数字 + 前缀白名单 if not re.match(r'^\d{6}$', stock_code): return error("A股代码格式错误,应为6位数字") prefix = stock_code[:2] valid_prefixes = ['60', '68', '00', '30', '43', '83', '87'] if prefix not in valid_prefixes: return error("A股代码前缀不正确") # 港股:4-5位数字.HK 或 纯4-5位数字 hk_format = re.match(r'^\d{4,5}\.HK$', stock_code.upper()) digit_format = re.match(r'^\d{4,5}$', stock_code) if not (hk_format or digit_format): return error("港股代码格式错误") # 美股:1-5位字母 if not re.match(r'^[A-Z]{1,5}$', stock_code.upper()): return error("美股代码格式错误,应为1-5位字母")与前端略有差异:后端港股要求4-5位数字(前端为1-5位并自动补齐),因为后端面对的是补齐后的标准代码;同时_validate_format还会拦截空代码与超过10字符的超长输入。
港股代码格式化修复:00700 → 0700.HK
这是整个修复中最关键的 Bug。旧逻辑f"{stock_code.zfill(4)}.HK"对00700直接输出00700.HK(错误,腾讯港股标准代码为0700.HK)。新逻辑先移除前导0,再补齐到4位:
clean_code = stock_code.lstrip('0') or '0' # 如果全是0,保留一个0 formatted_code = f"{clean_code.zfill(4)}.HK"| 输入 | 处理步骤 | 输出 |
|---|---|---|
700 | 700→0700 | 0700.HK✅ |
00700 | 00700→700→0700 | 0700.HK✅ |
9988 | 9988→9988 | 9988.HK✅ |
09988 | 09988→9988→9988 | 9988.HK✅ |
1810 | 1810→1810 | 1810.HK✅ |
01810 | 01810→1810→1810 | 1810.HK✅ |
数据预获取验证:三层证据链
格式通过后,各市场按"基本信息 → 股票名称 → 历史数据"顺序验证代码真实存在:
- A股:
get_china_stock_info_unified获取基本信息,解析"股票名称:"字段,若名称为"未知"或以股票{code}开头则判定不存在;随后get_china_stock_data_unified拉取历史数据,要求长度 > 50 且包含价格/成交量等关键字段。值得注意的是,A股分支还会先检查 MongoDB 缓存中的数据是否完整、是否为最新交易日,不完整时自动触发同步(_trigger_data_sync_async按数据库配置的数据源优先级依次尝试 tushare / akshare,同步历史数据、财务数据与实时行情),见 tradingagents/utils/stock_validator.py。 - 港股:先标准化为
0700.HK格式,再get_hk_stock_info_unified获取信息并借助_extract_hk_stock_name从字典字段、"公司名称:"、Yahoo Finance 日志格式、公司关键词等多来源解析股票名称;若命中网络限制特征(如 "Too Many Requests"、"Rate limited"、超时),返回专门的网络限制建议(等待5-10分钟重试、检查网络等),与"代码不存在"区分处理。 - 美股:直接通过
OptimizedUSDataProvider(或兼容旧路径get_us_stock_data_cached)获取历史数据来验证存在性,数据有效即视为验证通过(美股通常不单独拉取基本信息)。
接入分析任务:快速失败
验证入口接入 app/services/simple_analysis_service.py 的execute_analysis_background方法(相关调用见L808、L832-L872):后台任务启动时调用prepare_stock_data_async,若validation_result.is_valid为假,则同时更新内存任务状态与 MongoDB 任务状态为AnalysisStatus.FAILED(progress=0),携带error_message与suggestion,并立即返回——不消耗任何 LLM 调用与后续分析资源:
validation_result = await prepare_stock_data_async( stock_code=request.stock_code, market_type=market_type, period_days=30, analysis_date=analysis_date, ) if not validation_result.is_valid: error_msg = f"❌ 股票代码验证失败: {validation_result.error_message}" logger.error(error_msg) logger.error(f"💡 建议: {validation_result.suggestion}") await self.memory_manager.update_task_status( task_id=task_id, status=AnalysisStatus.FAILED, progress=0, error_message=validation_result.error_message, ) await self._update_task_status( task_id, AnalysisStatus.FAILED, 0, error_message=validation_result.error_message, ) return验证通过后,日志会记录股票名称、市场类型、历史数据与基本信息的有无,且验证过程中获取的基本信息与历史数据会缓存在 Redis,供后续分析阶段直接复用,避免重复拉取。
错误信息结构
验证失败返回结构化错误,包含市场类型、错误信息与可操作建议:
{ "is_valid": false, "stock_code": "000999", "market_type": "A股", "error_message": "股票代码 000999 不存在或信息无效", "suggestion": "请检查股票代码是否正确,或确认该股票是否已上市" }港股示例:"error_message": "港股代码 0700.HK 不存在或信息无效",建议给出0700.HK格式参考;美股示例建议列出AAPL、MSFT等正确格式。
端到端验证流程
前端与后端配合后的完整用户旅程:输入时显示格式提示 → 失焦即时验证 → 提交时再次验证(SingleAnalysis.vue 提交逻辑中同样调用validateStockCode,格式错误则阻止提交)→ 后端预获取验证兜底 → 验证通过后使用标准化代码发起分析。
测试用例一览
前端格式校验
| 市场 | 输入 | 预期 | 标准化后 | 说明 |
|---|---|---|---|---|
| A股 | 000001/600519 | ✓ | 000001/600519 | 平安银行 / 贵州茅台 |
| A股 | 00001/1234567/500001 | ✗ | - | 5位 / 超6位 / 前缀错误 |
| 美股 | aapl/MSFT/brk.b | ✓ | AAPL/MSFT/BRK.B | 大小写归一、点号支持 |
| 美股 | ABCDEF/123 | ✗ | - | 超5字母 / 纯数字 |
| 港股 | 700/00700/9988 | ✓ | 00700/00700/09988 | 前导0补齐 |
| 港股 | 123456 | ✗ | - | 超过5位 |
后端存在性验证
| 市场 | 输入 | 预期 |
|---|---|---|
| A股 | 000001/600519 | ✅ 通过(存在) |
| A股 | 000999/999999/00001 | ❌ 失败(不存在或格式错误) |
| 港股 | 700/00700→0700.HK,9988/09988→9988.HK | ✅ 通过 |
| 港股 | 99999(→99999.HK) | ❌ 失败(不存在) |
| 美股 | AAPL/MSFT/GOOGL | ✅ 通过 |
| 美股 | ABCDE/ZZZZZ | ❌ 失败(不存在) |
另外,scripts/stock_code_validator.py 提供了一套"内容后置修正"思路:针对 LLM 输出中可能出现的代码混淆(如将002027错写为002021/002026/002028),用错误映射表在分析结果内容中做替换修正,可作为验证体系的补充环节。
性能与健壮性设计
- 数据缓存:验证过程中获取的基本信息与历史数据会写入 Redis 缓存,分析阶段直接复用,避免重复请求数据源(见 tradingagents/utils/stock_validator.py 中
cache_status的记录链路)。 - 超时控制:
StockDataPreparer内置self.timeout_seconds = 15,15 秒内无法获取数据即判定验证失败,防止单只股票阻塞整个任务队列。 - 异步友好:
prepare_stock_data_async针对 FastAPI 事件循环设计;同步上下文则通过asyncio.to_thread包装(如文档中execute_analysis_background的调用方式),同步包装器_trigger_data_sync_sync还会检测运行中的事件循环并创建新 loop,规避 "attached to a different loop" 错误。 - A股数据自动同步:数据库数据缺失或过期时自动按配置的数据源优先级触发同步,兼顾数据新鲜度与验证成功率。
总结
修复前后对比:修复前输入00700会直接进入分析、中途才发现数据获取失败,浪费 LLM Token 与数据源配额;修复后,前端即时拦截格式错误并自动标准化(00700→00700、aapl→AAPL),后端在分析启动前完成"格式 → 存在性 → 数据可用性"三级校验,失败即快速终止任务并返回结构化错误与建议。
该设计的核心收益可归纳为:提前验证(分析开始前拦截无效代码)、快速失败(无效请求零成本返回)、清晰提示(错误信息附带修复建议)、数据复用(验证期缓存供分析期使用)、格式标准化(港股前导0、美股大写自动修正)。从源码结构看,后续可扩展的方向包括:股票代码白名单/黑名单、批量代码验证、验证结果缓存(避免重复验证同一股票)、以及新加坡、日本等更多市场的规则接入——工具函数与数据准备器的分层设计已为这些扩展预留了清晰接口。
修复前: 00700 → 开始分析(无验证) → 中途失败 → 浪费资源 ❌ 修复后: 00700 → 格式验证✓ → 标准化 0700.HK → 获取信息✓ → 获取数据✓ → 验证通过开始分析 ✅【免费下载链接】TradingAgents-CN基于多智能体LLM的中文金融交易框架 - TradingAgents中文增强版项目地址: https://gitcode.com/GitHub_Trending/tr/TradingAgents-CN
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考