解析通达信本地数据文件:实战获取沪深股票代码与名称

张开发
2026/4/21 11:27:40 15 分钟阅读

分享文章

解析通达信本地数据文件:实战获取沪深股票代码与名称
1. 通达信本地数据文件解析入门第一次接触通达信本地数据文件时我被它的二进制格式搞得一头雾水。作为一个经常需要处理股票基础数据的开发者我发现直接从本地文件获取信息比依赖网络API稳定得多特别是在网络状况不佳或者需要批量处理大量数据时。通达信的shm.tnf和szm.tnf这两个文件就像是一个宝藏里面存储着沪深两市所有交易品种的基础信息。这两个文件通常位于通达信安装目录下的T0002/hq_cache文件夹中。shm.tnf对应沪市数据szm.tnf对应深市数据。每个文件都采用二进制格式存储包含文件头和数据体两部分。文件头占50个字节主要记录了一些连接信息数据体则由大量314字节的数据块组成每个数据块对应一个交易品种的详细信息。2. 文件结构深度解析2.1 文件头结构详解文件头虽然只有50个字节但包含的信息却很有价值。前40个字节存储的是通达信最后连接的行情主站IP地址不足部分用\x00填充以\x01结尾。接下来的2个字节是端口号采用小端序存储。然后是4个字节的日期信息格式为YYYYMMDD。最后4个字节是时间信息格式为Hmmss。理解文件头结构对验证文件完整性很有帮助。我曾经遇到过文件头损坏的情况导致无法正确解析数据。通过检查文件头各字段的合理性可以快速判断文件是否完整。比如日期字段应该是合理的交易日期时间字段应该在正常交易时间段内。2.2 数据体结构解析数据体才是我们真正关心的部分。每个314字节的数据块对应一个交易品种的信息包括股票、基金、债券等各种类型。关键字段的偏移量和长度如下0-6字节股票代码6个字节ASCII编码23-41字节股票名称18个字节GBK编码276-280字节昨收盘价4个字节浮点数285-293字节股票名称拼音字头8个字节在实际解析时我发现股票名称字段经常会有\x00填充字符需要特别注意处理。另外不同版本的通达信可能在字段偏移量上会有微小差异建议先用小量数据测试确认偏移量。3. 实战代码解析3.1 Python实现方案用Python解析这些二进制文件非常方便。下面是一个完整的解析示例import struct def parse_tdx_file(file_path): stocks [] with open(file_path, rb) as f: # 跳过50字节的文件头 f.seek(50) # 计算记录总数 file_size f.seek(0, 2) record_count (file_size - 50) // 314 f.seek(50) for i in range(record_count): # 读取股票代码 code_bytes f.read(6) stock_code code_bytes.decode(ascii).strip() # 跳过到名称字段 f.seek(17, 1) # 读取股票名称 name_bytes f.read(18) stock_name name_bytes.decode(gbk).strip(\x00) # 跳过到下一个记录 f.seek(314 - 6 - 17 - 18, 1) if stock_code and stock_name: stocks.append((stock_code, stock_name)) return stocks这个函数会返回一个包含股票代码和名称的元组列表。我在实际使用中发现处理深市数据时需要特别注意创业板股票代码以300开头和主板股票代码以000开头的区别。3.2 性能优化技巧当处理大量数据时解析速度就变得很重要。我总结了几个优化点批量读取可以一次读取多个记录减少IO操作使用内存映射对于超大文件可以使用mmap模块并行处理多线程处理不同区间的数据优化后的代码可能长这样import mmap def fast_parse_tdx_file(file_path): stocks [] with open(file_path, rb) as f: with mmap.mmap(f.fileno(), 0, accessmmap.ACCESS_READ) as mm: mm.seek(50) data mm.read() for i in range(0, len(data), 314): record data[i:i314] code record[0:6].decode(ascii).strip() name record[23:41].decode(gbk).strip(\x00) if code and name: stocks.append((code, name)) return stocks4. 常见问题与解决方案4.1 编码问题处理在解析过程中最常见的坑就是编码问题。通达信的数据使用GBK编码存储中文而现代系统多使用UTF-8。如果直接按UTF-8解码遇到特殊字符就会报错。我的经验是始终明确指定编码为gbk使用errorsignore参数跳过非法字符对解析结果进行规范化处理4.2 数据完整性检查另一个常见问题是数据损坏或不完整。我建议在解析前做以下检查验证文件大小是否合理应该是50 314*N字节检查文件头中的日期是否合理抽样检查几个记录的字段是否正常我曾经遇到过因为磁盘空间不足导致文件写入不完整的情况后来加入了这些检查后就再没出过问题。4.3 字段偏移量验证不同版本的通达信可能在字段偏移量上有微小差异。最稳妥的做法是先用少量数据测试确认偏移量编写自动检测偏移量的逻辑记录检测到的偏移量供后续使用下面是一个自动检测股票名称偏移量的示例def detect_name_offset(file_path): with open(file_path, rb) as f: f.seek(50) sample f.read(314*100) # 读取100条记录 for offset in range(20, 50): # 在20-50字节范围内搜索 names set() for i in range(0, len(sample), 314): name sample[ioffset:ioffset18].decode(gbk, errorsignore).strip(\x00) if len(name) 2 and not name.isdigit(): names.add(name) if len(names) 50: # 如果找到大量合理的股票名称 return offset return 23 # 默认值5. 进阶应用场景掌握了基础解析方法后这些数据可以应用在很多场景中。我常用的几个场景包括本地股票数据库建设量化交易系统的数据预处理股票筛选器的开发历史数据分析特别是在开发量化交易系统时本地数据的快速访问能力可以大大提高回测效率。我曾经开发过一个基于这些数据的股票筛选器能够在毫秒级别完成全市场股票的条件筛选。另一个有用的应用是构建股票代码和名称的映射关系。在分析不同数据源时经常需要统一股票标识这时本地存储的映射关系就非常有用。我通常会把这些数据存入SQLite数据库方便快速查询。6. 数据更新与维护虽然本地数据很稳定但也需要定期更新。我总结了几种更新策略定期从通达信客户端导出新数据监控文件修改时间发现变化后自动重新加载设置版本控制保留历史数据快照在实际项目中我建议建立一个数据更新日志记录每次更新的时间和内容变化。这对于追踪问题和数据分析非常有帮助。我曾经通过分析更新日志发现了一些股票更名和退市的规律。维护这些数据时还需要注意特殊情况的处理比如股票更名新股上市股票退市股票代码变更一个好的做法是建立一个完整的数据变更历史记录这对于后续的数据分析非常重要。

更多文章