普通网友 2025-10-15 21:20 采纳率: 98.8%
浏览 57
已采纳

如何解析通达信szs.tnf文件中的股票代码与名称映射?

如何解析通达信szs.tnf文件中的股票代码与名称映射?该文件为通达信软件存储深市股票列表的专有格式,通常采用二进制结构,包含股票代码、名称、上市状态等信息。常见问题是:文件无公开文档说明,结构不透明,直接用文本编辑器打开显示乱码;且不同版本通达信可能格式略有差异,导致解析结果不一致。开发者常尝试通过逆向分析或参考社区经验提取字段偏移与编码方式(如GBK编码的股票名称),但面临字段对齐、校验机制和版本兼容性难题。如何稳定、准确地从szs.tnf中提取完整的股票代码与名称映射表,成为量化系统或自研行情平台对接时的关键技术挑战。
  • 写回答

1条回答 默认 最新

  • 杨良枝 2025-10-15 21:20
    关注

    如何解析通达信szs.tnf文件中的股票代码与名称映射

    在构建量化交易系统或自研行情平台时,对接本地数据源是常见需求。通达信作为国内主流的行情软件之一,其本地数据文件(如szs.tnf)存储了深市股票的基础信息,包括股票代码、名称、上市状态等关键字段。由于该文件为专有二进制格式,缺乏官方文档说明,直接解析面临诸多挑战。本文将从基础认知到深度实现,系统性地剖析szs.tnf文件的结构解析方法。

    1. 文件背景与基本特征

    • 文件路径:通常位于通达信安装目录下的T0002\hq_cache\vipdoc\sz\lday\等子目录中。
    • 文件作用szs.tnf用于缓存深市证券列表,供软件快速加载股票池。
    • 编码特性:股票名称采用GBK编码,非UTF-8,需注意解码错误。
    • 二进制结构:文件由多个固定长度记录组成,每条记录代表一只股票。
    • 版本差异:不同版本通达信(如经典版、金融终端)可能使用不同记录长度(常见为77字节或84字节)。

    2. 解析流程设计

    graph TD A[打开 szs.tnf 文件] --> B{判断文件大小} B --> C[计算记录数量 = 文件大小 / 单条记录长度] C --> D[尝试常用长度: 77, 84, 92] D --> E[逐条读取二进制记录] E --> F[按偏移提取字段] F --> G[GBK解码股票名称] G --> H[校验股票代码格式] H --> I[输出映射表 {代码: 名称}]

    3. 字段结构逆向分析

    通过Hex编辑器观察多个版本的szs.tnf,可归纳出典型结构如下表所示(以77字节为例):

    偏移(十进制)长度(字节)字段名数据类型说明
    06股票代码ASCII字符串左对齐,空格填充
    61分隔符byte通常为0x00
    718股票名称GBK编码字符串定长,不足补空格
    251市场类型byte0x01表示主板,0x02创业板等
    264未知字段Aint32可能为内部标识
    301上市状态byte0x01正常,0x02停牌,0x03退市
    3146保留字段/扩展区bytes内容随版本变化

    4. Python 实现示例

    以下为稳定解析szs.tnf的核心代码片段:

    import struct
    import codecs
    
    def parse_szs_tnf(filepath):
        with open(filepath, 'rb') as f:
            data = f.read()
        
        record_length_candidates = [77, 84, 92]
        records = []
        
        for rec_len in record_length_candidates:
            if len(data) % rec_len != 0:
                continue
            
            num_records = len(data) // rec_len
            print(f"尝试记录长度: {rec_len}, 记录数: {num_records}")
            
            valid_count = 0
            for i in range(num_records):
                offset = i * rec_len
                record = data[offset:offset + rec_len]
                
                try:
                    # 提取股票代码 (6字节 ASCII)
                    code_bytes = record[0:6].strip(b'\x00 ')
                    code = code_bytes.decode('ascii')
                    
                    # 提取股票名称 (18字节 GBK)
                    name_bytes = record[7:25].strip(b'\x00 ')
                    name = codecs.decode(name_bytes, 'gbk', errors='ignore')
                    
                    # 校验代码格式
                    if not (code.startswith('0') or code.startswith('3') or code.startswith('2')):
                        continue
                    
                    records.append({'code': code, 'name': name})
                    valid_count += 1
                    
                except Exception as e:
                    continue
            
            # 若有效记录超过一定比例,认为此长度正确
            if valid_count > num_records * 0.8:
                return records
        
        return []
    
    # 使用示例
    stock_list = parse_szs_tnf('T0002/hq_cache/szs.tnf')
    for item in stock_list[:10]:
        print(f"{item['code']} - {item['name']}")
    

    5. 兼容性与健壮性优化

    为应对不同版本通达信的格式差异,建议采取以下策略:

    1. 多长度试探:预设多种可能的记录长度,通过校验股票代码前缀(如0/3开头)判断解析是否合理。
    2. 动态偏移探测:对名称区域进行GBK解码测试,若连续出现乱码则跳过该长度假设。
    3. 校验和辅助:部分版本在文件末尾包含CRC32校验,可用于验证完整性。
    4. 缓存结构指纹:记录成功解析的文件大小与长度组合,建立版本指纹库。
    5. 结合其他文件交叉验证:参考ldbgz.datblocknew.cfg中的股票列表进行比对。
    6. 异常处理机制:对解码失败、长度不匹配等情况进行日志记录与降级处理。
    7. 支持内存映射:对于大文件,使用mmap提高读取效率。
    8. 自动化测试集:收集多个版本的szs.tnf样本,构建回归测试用例。
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 已采纳回答 10月23日
  • 创建了问题 10月15日