通达信day文件解析:用Python将二进制K线批量转换为CSV的完整指南

发布时间:2026/9/2 15:50:19
通达信day文件解析:用Python将二进制K线批量转换为CSV的完整指南 简介这是通达信日线数据格式转换工具主要面向需要将上证、深证以及港股day文件批量转为csv的量化研究或数据分析用户。工具针对股票、基金、港股的不同数据字段做了格式适配复制exe到对应lday目录即可运行无需额外环境压缩包内含C源代码方便有二次开发需求的用户自行修改或编译。资源包共2个文件分别为1个C源文件和1个Windows可执行文件整体仅8KB体量轻巧、下载与使用成本极低。目前已超过6200人学习或下载适合有一定C语言基础、需要处理通达信本地数据的投资者与开发者。通过这份资源可以快速完成日线数据格式转换并可直接参考作者对通达信day文件格式的详解文章深入理解不同市场的字段差异与处理逻辑是本地行情数据清洗与入库前的一项实用工具。 用通达信导K线数据这事说简单也简单说折腾也真折腾。软件自带的导出功能一次只能导一只手里几十只股票、基金、港股排着队手动点到手抽筋。而且导出格式固定想接进自己的量化程序还得再清洗一遍。所以很多朋友把目光转向通达信本地留下的day文件它们就静静躺在安装目录的vipdoc文件夹里更新及时、字段齐全但直接打开全是乱码——因为这是紧凑的二进制记录不是文本。这篇文章我把最近倒腾day文件转换的完整过程写出来拆解二进制格式里每一个字节给出一套可以直接抄走的Python解析脚本把A股、港股、场内基金统一处理成标准CSV。适合刚开始搞量化分析、或者被通达信导出功能折磨过的朋友参考。不聊指标公式不谈选股技巧专注解决“怎么把.day文件变成自己能用的数据”这件事。1. 先搞清楚day文件到底存了什么1.1 通达信的本地K线从哪来通达信安装目录下的vipdoc文件夹是行情数据落地的地方。不管你打开软件看的是日K、周K还是分钟K这些数据最终都会以独立文件的形式缓存在本地后缀通常是.day比如sh600000.day、sz000001.day、hk00700.day。这类文件按市场放在不同子目录里更新频率跟着行情走收盘后数据会刷新盘中也持续追加。对做量化的人来说这等于有了一个无需联网、随时可读的本地行情源。这里要区分一个概念.day文件不是通达信“导出的数据文件”而是软件内部使用的二进制数据文件。导出的数据通常带字段名.day文件里只有紧凑记录每个字段靠固定字节数划分。所以想正确读取必须先明白文件的存储规则不能像读文本一样直接打开。1.2 一条记录的32字节怎么拆通达信day文件每条K线记录固定占32字节按日期从早到晚顺序排列文件里没有表头、没有分段标记从头到尾一次性读完就是一个完整的历史序列。32字节里塞下了日期、开盘、最高、最低、收盘、成交额、成交量这些核心字段具体布局如下字节偏移类型含义说明0-3int32日期整数格式如202401154-7int32开盘价实际价格乘以100后的整数8-11int32最高价实际价格乘以100后的整数12-15int32最低价实际价格乘以100后的整数16-19int32收盘价实际价格乘以100后的整数20-23float32成交额单位元浮点数24-27int32成交量单位股28-31int32保留字段通常为0价格为什么要乘100存因为行情撮合的最小报价单位通常精确到0.01元乘100后变成整数记录既能避免浮点误差也让文件更紧凑。比如一只股票收盘价12.35元文件里存的是1235解析时除以100还原。这个细节如果没注意解析出来的价格会整体放大100倍一眼看去还以为股价上了天。字节序方面通达信day文件统一使用小端序也就是低位字节在前。用Python的struct库解析时格式串开头要加一个写成IIIIIfII表示“按小端序依次读5个无符号整数、1个浮点数、2个无符号整数”正好对应表格里的8个字段。千万别漏掉小端序标记否则遇到多字节整数时解析结果会完全错乱。2. 转换前的准备工具、目录、代码2.1 工具选型为什么用Python处理二进制文件的选择其实不少C/C读写最快但开发成本高Excel的二进制导入也能读但逐条解析后还要转置、格式化效率很低。我自己用的方案是Python主要是三个原因。第一struct模块处理固定长度二进制记录非常顺手几个字符就能描述整条记录的字段布局。第二转换完的数据用pandas整理成DataFrame后面不管是输出CSV、写进数据库还是做回测接口都是现成的。第三代码量小、逻辑简单出了问题也好排查。对本地K线转换这种数据清洗任务Python是最平衡的方案。有朋友问过为什么不用现成的第三方行情库。通达信、pytdx这类库主要是通过网络接口获取实时行情和本地vipdoc目录不是一回事。本地文件解析还是得自己读字节与其绕一圈不如直接用struct一把梭。2.2 先找到文件位置开始动手之前先确认通达信安装目录的结构。常见布局是通达信安装目录 ├─ vipdoc │ ├─ sh │ │ └─ lday │ │ ├─ sh600000.day │ │ ├─ sh601318.day │ │ └─ sh510300.day │ ├─ sz │ │ └─ lday │ │ ├─ sz000001.day │ │ ├─ sz000651.day │ │ └─ sz159915.day │ └─ hk │ └─ lday │ ├─ hk00700.day │ ├─ hk03690.day │ └─ hk09988.day看到规律没有文件名的前缀代表市场标识sh是上海市场sz是深圳市场hk是港股后面的代码是证券代码不足位数会补前导零比如腾讯代码是00700文件名就是hk00700.day。基金和股票在同一层目录只不过代码段不同比如上交所ETF是51开头深交所ETF是15开头拿到文件名就能分清。3. 手写转换脚本从二进制到CSV3.1 解析函数的核心逻辑对照前面的字段布局核心解析逻辑其实只有几步打开文件循环读取固定大小的字节块用struct按格式解包把价格字段除以100还原成真实数值再把日期整数转成日期类型。完整代码如下import struct from pathlib import Path import pandas as pd def read_day_file(file_path, divisor100): file_path Path(file_path) records [] with file_path.open(rb) as f: while True: data f.read(32) if len(data) 32: break date, o, h, l, c, amount, volume, _ struct.unpack(IIIIIfII, data) records.append({ date: date, open: o / divisor, high: h / divisor, low: l / divisor, close: c / divisor, amount: amount, volume: volume, }) df pd.DataFrame(records) df[date] pd.to_datetime(df[date].astype(str), format%Y%m%d) return df代码里有个细节while True每次读32字节后判断长度如果不足32字节就退出这样能兼容文件末尾可能出现的残缺字节。struct.unpack(IIIIIfII, data)一次性解出8个字段前5个整数对应日期和4个价格第6个浮点对应成交额最后两个整数对应成交量和保留位。解出来的价格统一除以divisorA股默认100港股场景单独调整。3.2 港股和基金的特殊处理港股和A股虽然都用day文件但细节上有几处区别要处理。第一是价格缩放。A股和场内基金最小报价单位是0.01元所以价格乘100存储解析除以100。部分通达信版本对港股数据存储乘的是1000因为不少港股股价低于0.1港元按0.01精度存会损失太多信息。到底除以多少不能盲目抄网上结论我的经验是先取一只价格明确的股票做对照比如腾讯解析后价格如果是7附近说明少乘了10倍如果是700附近说明应该除以100而不是1000。多试几次就能定下来。第二是目录和代码规则。港股文件在vipdoc\hk\lday下代码是5位A股场内基金和股票共用lday目录不需要单独处理解析逻辑完全一致。基金和股票的成交量大int32无符号整数最大约42.9亿单日成交量超过这个值会溢出不过这种情况极少见遇到异常大数字再单独排查即可。第三是复权问题。day文件记录的是真实成交的原始价格没有经过复权调整。只做价格查看或画K线问题不大但如果拿这些数据做历史回测遇到除权除息日会出现价格跳空K线看起来就像当天凭空砸了个大坑。这时需要结合通达信的除权除息数据做复权我在第四章展开讲。3.3 批量转换与导出单个文件解析没问题后批量转换就只剩遍历目录这一步。比如我想把vipdoc下所有A股、基金、港股都转成CSV可以这样写from pathlib import Path root Path(rD:\tdx\vipdoc) out_dir Path(rD:\tdx_convert) out_dir.mkdir(exist_okTrue) for day_file in root.rglob(*.day): try: df read_day_file(day_file) if df.empty: continue output out_dir / f{day_file.stem}.csv df.to_csv(output, indexFalse, encodingutf-8-sig, date_format%Y-%m-%d) print(f{day_file} - {output}, {len(df)} rows) except Exception as e: print(f{day_file} failed: {e})root.rglob(*.day)会递归遍历所有子目录包括sh、sz、hk下的lday目录一次把全市场数据都捞出来。输出文件名保留原day文件的主文件名比如sh600000.day转成sh600000.csv后续要找哪个标的直接按文件名搜就行。CSV编码用了utf-8-sig这个细节建议直接照抄Excel打开不带BOM的UTF-8文件时中文表头会乱码加上BOM头就不会了。日期列用date_format%Y-%m-%d可以让Excel里直接显示成年月日否则会变成一串数字。4. 转换中的常见坑与排查技巧4.1 价格整体不对单位坑转出来的价格比软件里看到的整体大100倍或小10倍十有八九是价格缩放因子用错了。A股标准做法是除以100但港股部分版本要除以1000判断方法不靠猜找一只价位明确的股票做锚点最靠谱。打开通达信看腾讯最近收盘价再对照自己解析出来的最后一条记录收盘价比例关系一目了然。另外指数文件也在同一个目录里。比如上证指数很多数据文件也命名为sh000001.day但它代表的是指数点位而不是股票价格价格字段本身没有区别仍按除以100处理即可。这里容易让人心生怀疑指数点位明明在三千点附近为什么价格字段除以100后才是三千多因为指数点位本来就被存成300000这样的整数除以100恰好是3000并没有出错。4.2 成交量差100倍手和股的区别有朋友转完数据后发现成交量数字比通达信软件里显示的整整大了100倍以为解析出错。其实没出错day文件里成交量单位是股而通达信界面默认显示的是手1手等于100股。比如某只股票当天成交100万股day文件里存的是1000000软件显示的是10000手。你计算换手率、流动性指标时记得统一单位别把股和手混着用。这里可以多提一句成交额字段单位是元是float32单精度浮点。单日成交额几亿元以内精度足够用但如果某只股票当天成交额特别大小数位可能会丢不过对日常分析影响很小。真遇到精度敏感场景可以改用double精度的字段或直接保留两位小数输出。4.3 想拿复权数据怎么办day文件本身是不复权数据如果想做前复权或后复权得另外读取通达信的股本变迁文件gbbq。位置通常在T0002\hq_cache目录下不同版本路径略有差异记录每只股票的除权除息明细包括送股比例、配股比例、分红金额和除权日期。有了这些信息就可以从最早交易日开始按除权日逐个累乘调整因子得到后复权价格再通过平移得到前复权价格。这里不用自己重复造轮子通达信软件里看K线时默认展示的就是复权后的数据。如果你的策略对复权精度要求高最稳妥的办法是先用day文件拿到日期对应关系再用手动导出一份复权后的对照数据来校验自己的复权算法是否正确。我实际跑下来用gbbq算出的前复权价格和通达信软件展示的误差基本可以忽略但前提是gbbq文件本身解析准确。这个文件也是二进制格式解析逻辑和day文件类似但字段更多如果后续有需要可以再单独写一篇gbbq的解析说明。4.4 文件读取不完整的排查思路批量转换时偶尔会遇到某只股票文件解析到一半就断掉或者解析结果明显缺了最近几天数据。优先排查这几个地方第一通达信是否正在运行。很多版本在软件运行期间会锁定数据文件读取时读不到完整内容最稳妥做法是先关软件再转换。第二确认文件路径没选错。vipdoc下还有按周线、月线划分的其他目录后缀不同不要拿错。第三检查文件末尾是否有多余内容。day文件理论上是固定32字节一条但个别版本末尾会有填充读取时用长度判断退出即可不要直接按文件大小整除32来算记录数。遇到数据异常时可以写个简单脚本打印目标文件最后几行的字段和通达信界面最近几个交易日做对比。这样能快速把问题定位到“格式解析”还是“数据来源”上不用一遍遍盲调。5. 写在最后一点扩展想法整理本地行情数据时我最大的体会是二进制格式看着吓人但只要把字节布局摸清楚解析代码其实相当简单。day文件的价值在于稳定、离线、覆盖广尤其是港股和场内基金很多第三方数据接口要么收费要么更新慢直接从通达信本地读反而是性价比最高的路子。后来我把这个小脚本扩展成了定时任务收盘后自动把全市场日线刷一遍再配合自己的选股程序做盘后分析用起来相当顺手。如果你也在捣鼓类似需求希望这篇能帮你少走几步弯路特别是那些单位换算和目录结构的坑踩过一次就够够的了。本文还有配套的精品资源点击获取