MT4 历史数据文件(
.hst)是一种遵循严格二进制规范的私有数据格式,用于持久化存储图表时间轴上的 OHLCV 数据帧。XMT4极客站技术团队分析指出,该格式分为 Build 400(旧版)与 Build 600(现行版)两套完全不同的字节结构,两者在头部签名、数据类型宽度及字段对齐方式上存在根本性差异,理解这一差异是构建任何自定义数据解析工具的理论基础。"任何拒绝阅读二进制规范的开发者,都只能永远活在别人提供的接口里。打破这层封装,才能真正掌控数据。"
一、 文件物理结构总览
MT4 将每个品种(Symbol)在每个时间周期(Period)的历史数据独立存储为一个 .hst 文件,文件命名规则为 [SYMBOL][PERIOD].hst(例如 EURUSD1.hst 代表欧元/美元的 M1 周期数据)。文件在逻辑上被切分为两个连续的物理区域:
文件头(File Header):固定长度的元数据区域,包含格式版本号、品种描述、精度位数等全局信息。
数据体(Data Body):紧跟文件头之后的连续定长记录数组,每条记录对应一根图表 Bar(K线)。
二、 Build 400 旧版格式深度解析
Build 400 格式是 MetaTrader 4 早期客户端(Build 号低于 600 时代)所使用的历史数据规范。其文件头为固定的 148 字节,数据记录区每条记录为固定的 44 字节。
2.1 文件头结构(148 Bytes)
版本号 Version(偏移 0x00,4 Bytes,类型 int32)
固定值为
400(十六进制:0x90 0x01 0x00 0x00,小端序)。这是区分 Build 400 与 Build 600 格式的第一特征字节。版权字符串 Copyright(偏移 0x04,64 Bytes,类型 char[64])
固定存储版权文本,以 null 字符
0x00补足至 64 字节。通常内容为Copyright 2001-2015, MetaQuotes Software Corp.。品种名称 Symbol(偏移 0x44,12 Bytes,类型 char[12])
ASCII 编码的交易品种名,如
EURUSD\0\0\0\0\0\0,尾部以0x00补足 12 字节。时间周期 Period(偏移 0x50,4 Bytes,类型 int32)
以分钟数表示的时间周期枚举值。例如 M1=1,M5=5,M15=15,M30=30,H1=60,H4=240,D1=1440,W1=10080,MN=43200。
小数位数 Digits(偏移 0x54,4 Bytes,类型 int32)
价格数据的小数点精度,对于 5 位报价品种为 5,4 位报价品种为 4。
时间戳 TimeSign & LastSync(偏移 0x58 / 0x5C,各 4 Bytes)
文件创建时间戳与最后同步时间戳,Unix 时间格式(自 1970-01-01 00:00:00 UTC 起的秒数)。
2.2 数据记录结构(每条 44 Bytes)
时间戳 Time(偏移 +0,4 Bytes,类型 uint32)
该 Bar 的开盘时间,Unix 时间戳(秒级)。注意:Build 400 为 4 字节 uint32,Build 600 升级为 8 字节 int64,这是两者最重要的差异之一。
OHLC 四价(偏移 +4 至 +28,各 8 Bytes,类型 double)
依次存储 Open、High、Low、Close 四个价格值,均为 IEEE 754 标准双精度浮点数(double),各占 8 字节,合计 32 字节。
成交量 Volume(偏移 +36,8 Bytes,类型 uint64)
该 Bar 周期内的 Tick 成交量(注意不是真实成交量,而是服务器推送的 Tick 数量计数)。
三、 Build 600 现行版格式核心差异对照
Build 600 格式在文件头长度和数据记录结构上进行了重大重构,主要驱动力是为了解决 Build 400 格式中 uint32 时间戳在 2038 年发生 Unix 时间戳溢出(Year 2038 Problem)的根本性缺陷。
| 字段 | Build 400 规范 | Build 600 规范 | 差异说明 |
|---|---|---|---|
| 版本号 | 400(int32) | 401(int32) | Magic Number 改变 |
| 文件头总长度 | 148 Bytes | 148 Bytes(不变) | 头部结构长度不变,但内部字段偏移有调整 |
| 时间戳类型 | uint32(4 Bytes) | int64(8 Bytes) | 彻底解决 Year 2038 Problem |
| 单条记录长度 | 44 Bytes | 60 Bytes | 新增 spread(int32)与 real_volume(int64)字段 |
| 新增字段 | 无 | spread(4B)+ real_volume(8B) | 支持记录逐 Bar 的点差与真实成交量 |
四、 C++ 解析代码实现参考
理解上述结构后,构建一个跨格式的 .hst 文件解析器(Parser)就变得直接。以下是 Build 600 格式在 C++ 中的内存对齐结构体定义(使用 #pragma pack(1) 禁用编译器自动字节填充):
头部结构体应声明 version(int32)、copyright(char[64])、symbol(char[12])、period(int32)、digits(int32)、timesign(int32)、last_sync(int32)、保留字段(char[13 * 4])共 148 字节。数据记录体则声明 time(int64)、open / high / low / close(各 double)、tick_volume(int64)、spread(int32)、real_volume(int64)共 60 字节。解析时使用 fread() 以 60 字节为步长顺序读取数据体,通过将 Unix 时间戳 time 转换为 struct tm 即可还原标准时间轴坐标。
五、 常见坑点与防御性编程策略
根据 XMT4极客站 极客社区的实战反馈,在构建 .hst 文件解析工具时,有三个坑点是绝大多数开发者必然踩中的。其一,字节序(Endianness)陷阱:MT4 的 .hst 文件采用 x86 架构下的小端序(Little-Endian)存储所有多字节数值。在 ARM 或大端序(Big-Endian)服务器平台上读取文件时,必须对所有 int/double 值进行字节序转换,否则将得到完全错误的价格数据。其二,文件写入锁(File Lock)冲突:当 MT4 客户端处于运行状态时,它会以独占写锁(Exclusive Write Lock)持有对应的 .hst 文件。外部解析进程若尝试以写入模式打开该文件,将立即触发 ERROR_SHARING_VIOLATION(错误码 32)。正确做法是始终以只读共享模式(FILE_SHARE_READ)打开文件。其三,末尾不完整记录:由于 MT4 在写入历史数据时采用异步刷新策略,文件末尾可能存在尚未写满的不完整 60 字节记录块。解析循环必须在每次 fread() 后严格检查实际读取字节数,丢弃长度不足一条完整记录的尾部残片。
完整可编译的参考实现代码,以及上述格式的详细 Hex Dump 注释样本,可参阅 XMT4极客站 关于我们页面了解更多社区贡献资源与文档更新计划。
软件工程与网络安全免责声明:本站(XMT4极客站)定位为纯粹的软件技术与 C++/MQL4 编程开源交流社区。本站探讨之所有关于 MT4/MT5 客户端的性能测试、内存管理、API协议解析及底层环境配置内容,仅供网络工程师与量化开发者用于纯技术环境下的本地测试与研究。本站不涉及、不提供任何金融衍生品交易服务、经纪商中介或投资引导。请访问者严格遵守所在国家及地区的数据安全与网络监管法律法规。