上个月我想把自己几个EA跑过的账户做个像样的资金曲线图。MT4自带的那个余额图太简陋了,我想要的是那种带月度收益率柱状图、回撤阴影区域的仪表盘。一开始我偷懒,直接在MT4里点“文件——保存为报告”,选CSV格式,心想这不就完事了?
结果导出来的数据只到去年年中就没了。一开始我还以为是账户历史就这么短,后来一查,才发现MT4这个导出功能有64MB的文件大小限制。我那账户跑了三四年,十几个品种,交易记录好几万条,CSV到一半就硬生生截断了。关键是MT4不报错、不给提示,就给你个不完整的数据文件,你要是没发现,拿这个去做分析,结果全是错的。
既然自带功能靠不住,那就自己写脚本。我在MQL4官方文档(docs.mql4.com)的“历史数据访问”章节里找到了
OrdersHistoryTotal() 这个函数,可以遍历账户里所有已平仓订单。文档写得很清楚,每个订单能拿到开仓时间、平仓时间、盈亏、手续费、隔夜利息这些字段。但文档没告诉你的是:OrderOpenTime() 和 OrderCloseTime() 返回的是服务器时间,不是你本地电脑的时间,也不是UTC。我写了个简单的脚本,循环读取所有历史订单,用
FileWrite() 写到CSV文件里。跑了一遍,数据倒是全出来了,没有64MB的限制(因为我自己控制输出格式,只写必要的字段,不加那些HTML标签和格式信息,总共也就20MB不到)。但我把CSV拉到Python里一画图,资金曲线在每天的换日节点上出现了诡异的毛刺。有时候是直线跳空,有时候是负值突然转正。排查了半天,问题出在时区上。我用的那个经纪商,服务器时间设的是GMT+2(夏令时期间),但我本地电脑是GMT+1,而我用来做对比的外部数据源(比如Dukascopy的报价数据)又是标准的UTC。MT4里的
TimeCurrent() 返回的是服务器时间,TimeLocal() 返回的是电脑本地时间,但两者都没法直接给我一个干净的UTC时间戳。真正解决的办法是我自己动手算偏移量。官方文档的“时间函数”那一章提到了
TimeGMTOffset() 可以获取系统当前的GMT偏移,但这个值跟经纪商的服务器偏移还不是一回事。我在终端窗口的右下角看了一眼经纪商显示的服务器时间,跟我电脑时间一对比,差了2个小时。我就直接在脚本开头定义了一个常量 brokerOffset = 2,然后在写入CSV之前,把所有时间戳都减去 brokerOffset 3600 秒,转成UTC时间。``
mql4
// 脚本开头定义偏移量
int brokerOffset = 2; // 经纪商服务器是GMT+2
// 循环处理每个订单时
datetime utcClose = OrderCloseTime() - brokerOffset 3600;
string closeStr = TimeToString(utcClose, TIME_DATE|TIME_MINUTES);
`
这么一改,资金曲线的换日节点就跟外部数据源完美对齐了。每天的收盘时间统一到UTC的21:00(也就是经纪商服务器时间的23:00),再也不会出现那种莫名其妙的跳空。
这里有个独家心得:不同的经纪商,甚至同一个经纪商在冬令时和夏令时,这个偏移量都可能变化。我见过一些交易员在脚本里用 TimeGMTOffset() 自动计算,但有时候这个函数返回的值跟你经纪商的实际服务器偏移不是一回事,因为你的VPS可能设在别的时区。我的做法比较土,但绝对可靠——在脚本开头手动设置一个可调参数,换季的时候手动改一下数值,重新跑一遍导出。你说这是笨办法?但我用了一年多,零失误。
还有一个细节,导出CSV的时候,别用 TIME_SECONDS 格式,不然文件会变得很大,而且对你画日线级别的资金曲线来说,精确到分钟就足够了。我用的是 TIME_DATE|TIME_MINUTES`,既保留了日期的可读性,又保证了换日边界的精确度。拿到干净的CSV之后,我导入到Python里用pandas做处理,再用matplotlib画出来。重点是把每天的结束余额作为一个数据点,这样画出来的就是一条连续的权益曲线。回撤的计算也很简单,用历史最高点减去当前点,再除以历史最高点,就得到了动态回撤百分比。
回头想想,如果当初直接用一个现成的第三方工具导数据,可能就不用折腾这么一圈。但自己写脚本的好处是,你完全控制了数据格式和字段,以后想做任何自定义分析都不用再受限于别人软件的功能边界。
参考来源:
---
本文首发于FXEAR.com,原创内容,未经授权禁止转载