MT5 到 MT4 交易复制器:净持仓模型的桥接方案
一、为什么需要 MT5→MT4 复制器
很多交易者看好 MT5 的功能,但实盘账户还在 MT4 上。复制器的思路是:用 MT4 作为 MT5 交易的“执行载体”,把 MT5 上的持仓同步复制到 MT4。文章先厘清一个关键结论:利润只来自“报价 × 交易量”,报价由经纪商决定改不了,交易者能控制的只有交易量——所以复制的核心是“同步持仓的交易量”,而非逐笔复制每笔订单。
二、净持仓模型 vs 对冲模型
MT5 用净持仓(一个品种一个仓位),MT4 用对冲(同品种可多笔独立订单)。差异在于“平哪个订单不重要,重要的是该位置的平仓量一致”——文章用例子证明:同量订单以不同顺序平仓,单笔利润不同,但整段总利润相同。因此复制器只需保证 MT4 上的净持仓量等于 MT5 的净持仓量,不必还原 MT5 的订单结构。
三、架构:源端监听 + 共享文件传信号
MT5 端 EA 用 OnTimer 每秒扫描所有品种持仓,比较现值与前值,有变化就把“品种、持仓方向、交易量、SL/TP”写成共享文件(放在 MT5 的 MQL5\Files\ 下,且把 MT4 装到该目录里,使两边都读得到)。MT4 端脚本循环读文件、解析、对比虚拟头寸,再决定开/平/改。
四、差额下单:虚拟头寸比较
复制的核心是“差额下单”——比较文件里的目标持仓与实际虚拟持仓,只对差额部分操作。把方向转成 -1/+1,比较 TF·VF 与 TR·VR:不一致就平仓或开仓补齐差额:
int TF = SymPosType[i]*2-1; // 文件中的方向
int TR = realSymPosType[i]*2-1; // 实际方向
double VF = SymPosVol[i], VR = realSymPosVol[i];
if(NormalizeDouble(VF*TF,8) != NormalizeDouble(VR*TR,8))
{
if((VR!=0 && TF!=TR) || (TF==TR && VF<VR)) // 方向变 或 实际更多
{ double lot = (TF==TR)? (VR-VF) : VR; close_market_order(Symbols[i], lot); }
else // 实际更少 -> 开仓补齐
{ double lot = (TF==TR)? (VF-VR) : VF; open_market_order(Symbols[i], SymPosType[i], lot); }
}
五、坑与注意
六、完整复制流程(一句话串起来)
MT5 端 OnTimer 每秒扫持仓→compare_positions 比对→有变化写共享文件 cnt_command++;MT4 端循环读文件→parser 解析成数组→虚拟头寸比较→processing_signals 算差额→开/平/改→processing_sl_tp_levels 同步止损止盈。两个 processing_* 函数都是“带 IsStopped 退出的无限循环”,且只在交易流空闲(Busy_and_Connected)时才发指令,避免服务器拒单。
七、更多实战坑
八、复制交易的架构
跨平台复制器分两端:主端(信号源,如 MT5) detecting 新成交后,把品种、方向、手数、价格发到从端(执行端,如 MT4);从端收到后下对应单。两端通过网络(socket/HTTP)或共享文件通信。
架构上要解耦:主端只负责「广播成交事件」,从端负责「按自己的风控执行」,这样从端可以加自己的仓位限制,不完全盲从。
九、净额制到锁仓制的映射
MT5 是净额制(同品种一个仓),MT4 是锁仓制(可多空各一单)。复制时要映射:主端平掉一半,从端该平对应半仓还是反手?必须约定清楚,否则从端会多开反向单、仓位翻倍。
// 主端净额 -> 从端锁仓:用 diff 表达动作 int diff = newVol - oldVol; // >0 加仓, <0 减仓 if(diff > 0) slave.Buy(diff); else if(diff < 0) slave.Sell(-diff);
十、延迟与丢单处理
网络延迟会让从端成交价偏离主端,跳空时可能拒单。复制器必须处理:超时重发、成交回执确认、从端拒单时主端标记待补。没有确认的复制,遇到一次滑点就可能两边对不上。
稳健做法是从端执行后回发「实际成交 ticket」给主端对账,主端发现某笔没回执就重发或告警,避免静默漏单。