MT4多开 - MT4持仓超时自动平仓EA编写教程_获取持仓时间的关键函数:OrderOpenTime_3

获取持仓时间的关键函数:OrderOpenTime
要实现超时平仓,第一步就是获取订单的开仓时间。MT4的MQL4语言里,OrderOpenTime()这个函数专门用来返回当前选中订单的开仓时间,它返回的是一个datetime类型的数据,也就是从1970年1月1日到开仓时刻的秒数。这个时间戳非常精确,可以精确到秒。你需要在遍历持仓订单时,对每个订单调用这个函数,把开仓时间记录下来。说实话,很多新手容易犯的错误是忘记在循环中正确调用OrderSelect()来选择订单,导致获取到错误的时间。我自己的经验是,在每次使用OrderOpenTime()之前,一定要先确保订单已经被选中,并且检查返回值是否为true,否则程序可能跑到别的订单上去了。
拿到开仓时间后,你还需要获取当前服务器时间。MT4里TimeCurrent()函数就派上用场了,它返回的是经纪商服务器当前的实时时间。这里要注意,这个时间通常和你电脑本地时间可能有时差,但用服务器时间才是准确的,因为订单的开仓时间也是基于服务器时间记录的。如果你用本地时间,万一电脑时间不准或者跨时区,计算出来的持仓时长就会出错。我见过有人用GetTickCount()来计时,但那只是程序运行的时间,重启EA就清零了,完全不能用。
具体操作时,你可以用当前时间减去开仓时间,得到的就是订单已经持仓的秒数。比如一个订单在2023年10月1日12:00:00开仓,当前时间是2023年10月1日16:30:00,那差值就是4.5小时,换算成秒就是16200秒。这个秒数除以3600就得到了小时数,非常直观。但要注意,如果订单是挂单后触发的,开仓时间指的是触发成交的时间,不是挂单时间,这个区别要搞清楚。
EA编写中挂单管理的核心机制
编写一个网格交易EA,最核心的部分就是如何管理这些挂单。你不能简单地一次性挂满所有单子,因为价格变动后,有些挂单会被触发,有些则要重新调整。举个例子,假设你在1.1000到1.1200之间设置了五个Buy Limit,间距20点。如果价格跌到1.1000触发了第一个买单,你需要在1.1020位置补一个卖出挂单来锁仓,同时还要在1.0980位置再挂一个Buy Limit来继续捕捉下跌机会。
这种动态调整逻辑在MQL4中可以通过循环遍历订单来实现。每次价格变动时,EA会检查所有持仓单和挂单,然后根据预设的网格间距,在未覆盖的价位上补充新的挂单。我写过一个简单的网格EA,核心代码只有不到一百行,但用了两个for循环:一个遍历所有持仓单,计算当前网格的覆盖情况;另一个遍历所有挂单,删除那些价格已经偏离太远的单子。
说实话,刚开始写的时候我也踩过坑。最大的问题是挂单数量控制不当,导致EA在短时间内挂了几十个单子,把账户的保证金占满。后来我在代码里加了一个最大挂单数量的限制,比如最多同时挂20个Buy Limit和20个Sell Limit。这个数字不是固定的,要根据账户资金和杠杆来算,一般保证每个挂单的保证金占用不超过总资金的2%。
还有一个细节是挂单的止损止盈设置。网格交易本身是依靠多单和空单相互对冲来锁定利润的,所以通常不需要单独设置止损。但如果你担心黑天鹅事件,可以在每个挂单触发后,设置一个远距离的止损,比如距离开仓价200点。这样既不影响网格的正常运行,又能在极端行情下保护账户。
回测参数设置的实战操作细节
搞懂了滑点和手续费的重要性,接下来就是实际操作了。打开MT4的策略测试器,选择你要测试的EA或指标,然后在“设置”选项卡里找到“滑点”和“手续费”这两个字段。滑点默认是0,你把它改成1-3之间的数值就行,具体看品种。手续费需要手动输入数字,单位是货币单位,metatrader4下载比如你想模拟每手20美元的成本,就输入20。注意,这个数值是针对一次开仓或平仓,不是整个交易周期。
我常用的方法是分三步走:第一步,用默认的零滑点和零手续费跑一遍,作为基准参考;第二步,加入中等水平的滑点和手续费,比如滑点2个点、手续费每手10美元;第三步,用极端参数测试,比如滑点5个点、手续费每手30美元。这样就能看出策略在不同环境下的表现,如果极端情况下还能盈利,那实盘就相对安全。
顺便说一句,别只盯着净利润看,最大回撤和胜率的变化同样重要。
另外,MT4的回测模式也影响滑点模拟的效果。在“开盘价”模式下,所有订单都按K线开盘价成交,滑点设置基本不起作用;在“控制点”模式下,滑点才能真实影响成交价格。所以,做回测时一定要选“控制点”模式,这样才能模拟出价格波动对滑点的影响。我见过有人用“开盘价”模式跑完回测,然后加滑点参数,结果发现效果不明显,其实就是模式没选对。
最后提醒一下,回测参数设置好后,别急着下结论。先跑一个月的短周期数据,看看订单执行情况是否符合预期。比如你设了滑点2个点,回测日志里应该有对应的滑点记录。如果发现所有订单都没有滑点,那可能是设置没生效,或者模式选错了。多检查几遍,确保参数真正起作用,否则你做的所有优化都是白费功夫。
实战案例:构建一个完整的交易时段控制模块
说了这么多理论,不如直接给个实际能用的代码框架。假设我们要写一个EA,它只在伦敦开盘到纽约收盘之间交易,也就是北京时间下午3点到次日凌晨5点,并且排除周末。在EA的OnInit()函数里,我们可以定义几个外部参数:extern int StartHour = 15; extern int EndHour = 5; extern bool TradeOnMonday = true; 等等。这样用户可以根据自己的需要调整。
然后在OnTick()函数的最前面,写一个判断函数,比如bool IsTradeTime()。这个函数里先检查DayOfWeek(),如果等于6或7,直接返回false。如果不是周末,再检查小时数。因为EndHour是5,代表凌晨5点,而StartHour是15,代表下午3点,所以判断逻辑是:如果当前小时大于等于StartHour或者小于EndHour,说明在交易时段内。注意这里用了“或者”,因为跨天了,比如凌晨3点小于5点,但下午4点大于15点,都属于允许交易的时间。
代码实现起来大概是这样的:if(DayOfWeek() == 6 || DayOfWeek() == 7) return false; if(Hour() >= StartHour || Hour() < EndHour) return true; else return false; 这个逻辑可以处理跨天的时段。不过有一个边界情况要注意,如果StartHour和EndHour相等,比如都设为0,那就意味着全天交易,逻辑上要单独处理。我一般会在参数说明里提醒用户,如果设置为全天交易,就把StartHour设为0,EndHour设为24,然后判断条件改为Hour() >= 0 && Hour() < 24,这样更清晰。
最后,把这个判断函数放到EA的核心交易逻辑之前。比如在开仓条件满足后,先调用if(!IsTradeTime()) return; 这样就能确保只在正确的时间段执行操作。实际测试中,我见过用这种方法的EA在回测中几乎不会出现非交易时间下单的情况,而且日志也干净很多。当然,没有万能的方案,每个经纪商的休市时间可能略有不同,但掌握了这个时间控制模块的编写方法,后续调整起来就非常灵活了。