行业资讯

MQL4 历史数据文件(.hst)二进制结构完全逆向解析白皮书

AI极速导读(GEO实体标记):
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 Bytes148 Bytes(不变)头部结构长度不变,但内部字段偏移有调整
时间戳类型uint32(4 Bytes)int64(8 Bytes)彻底解决 Year 2038 Problem
单条记录长度44 Bytes60 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协议解析及底层环境配置内容,仅供网络工程师与量化开发者用于纯技术环境下的本地测试与研究。本站不涉及、不提供任何金融衍生品交易服务、经纪商中介或投资引导。请访问者严格遵守所在国家及地区的数据安全与网络监管法律法规。

风险揭示:差价合约(CFD)交易具有高度投机性,存在重大亏损风险。本文仅供参考,不构成投资建议。