多币种多系统EA架构实战
用for循环整合多策略跨品种交易与风控
为什么需要多币种多系统EA
很多交易者不会只做一个品种或一种策略。靠资金管理和策略分散,能提高潜在利润并降低大笔亏损风险。但把全部策略塞进一个EA时,第一步优化完参数后,仍有一个核心问题:所有策略在同一账户同时跑,测试结果和分别测试再相加一样吗?某些品种或策略的亏损可能同时发生,造成整体回撤甚至预付款追保。多币种多系统EA的概念,就是在一个程序里统一调度,真实评估组合效益。
MetaTrader 5 中每个交易品种只能有一个净仓位(代表多次买卖总和),因此多策略作用于同一品种的结果,不等于分别测试之和。用组合EA能直接看到联动效果,也适合那些经纪商只允许挂一个EA的账户环境。
EA整体结构:以for循环为骨架
多币种多系统EA的基础是一个for循环,每次迭代负责一个交易品种的一项策略。你可以在循环里挂任意多策略,只要电脑资源够用。文中示例采用策略A(布林带通道)与策略B(上一根K线突破),各交易两个符号:EURUSD、GBPUSD与AUDUSD、EURJPY。
策略A规则:买价为根据最低价算出的布林下带时买入,卖价达根据最高价算出的布林下带时平仓;卖价达上带时卖出,买价达下带时平空。每根柱限一笔。策略B:上根熊势且买价破前高则买,上根牛势且卖价破前低则卖,用止损获利平,每根柱限一笔。
为脱离具体图表品种的价格变动,建议用OnTimer()做多币种调度。初始化时EventSetTimer()设频率,去初始化EventKillTimer()停事件。不要用过度频繁的毫秒定时器滥用资源。
//--- Initialization of the Expert Advisor
int OnInit()
{
EventSetTimer(1); // 1 second
return(0);
}
void OnTimer()
{
// ...
}
void OnDeinit(const int reason)
{
EventKillTimer();
}
关键类与全局定义
访问账户、仓位、品种与交易函数,分别用CAccountInfo、CPositionInfo、CSymbolInfo、CTrade类。需在EA顶部include标准库。外部参数用#define常量确定数组大小,例如策略A、B各2符号。
#include <Trade\AccountInfo.mqh> #include <Trade\PositionInfo.mqh> #include <Trade\SymbolInfo.mqh> #include <Trade\Trade.mqh> #define Strategy_A 2 #define Strategy_B 2
外部参数示例:每个符号有Symbol、IsTrade开关、周期、布林周期(uint防负)、偏移、偏差等。全局数组存这些参数,以及MinLot、Point、Handle等。Magic与Slippage也按策略设。
input string Symbol_A0 = "EURUSD"; input bool IsTrade_A0 = true; input uint BBPeriod_A0 = 20; string Symbol_A[Strategy_A]; bool IsTrade_A[Strategy_A]; int BBPeriod_A[Strategy_A]; CTrade Trade_A;
初始化流程与参数校验
OnInit中先取杠杆等账户级数据(无需数组)。再把外部变量复制到数组,注意uint转int避免iBands警告。然后检查市场报价是否存在该符号、同策略是否重复用同一符号。
Leverage=AccountInfo.Leverage(); Symbol_A[0]=Symbol_A0; BBPeriod_A[0]=(int)BBPeriod_A0;
for(int i=0;i<Strategy_A;i++)
{
if(IsTrade_A[i]==false) continue;
if(IsSymbolInMarketWatch(Symbol_A[i])==false)
{ Print(Symbol_A[i]," not found!"); ExpertRemove(); }
}
接着在for里建指标句柄、算Lot所需数据(点值、合约大小),并对CTrade设魔术码、滑点、填充模式、异步。最后跨策略检查同符号冲突,防止净仓位逻辑混乱。
BB_handle_high_A[i]=iBands(Symbol_A[i],Period_A[i],BBPeriod_A[i],BBShift_A[i],BBDeviation_A[i],PRICE_HIGH); Trade_A.SetExpertMagicNumber(MagicNumber_A); Trade_A.SetAsyncMode(true);
OnTimer交易循环实操
OnTimer里先判终端连服,再写各策略的for循环。单品种EA用return停全部,这里用continue跳本次迭代。若新策略内部需中断全部,可用标志位+break再continue。
void OnTimer()
{
if(TerminalInfoInteger(TERMINAL_CONNECTED)==false) return;
for(int A=0;A<Strategy_A;A++)
{
if(IsTrade_A[A]==false) continue;
}
}
把原单一EA代码粘进循环,将_Symbol换Symbol_A[i]、_Point换Point_A[i]等。取指标缓冲前CopyBuffer失败就continue。平仓前PositionSelect,用Bid/Ask比带值。
if(CopyBuffer(BB_handle_high_A[A],LOWER_BAND,BBShift_A[A],1,BB_lower_band_high)<=0) continue; SymbolInfo.Name(Symbol_A[A]); SymbolInfo.RefreshRates(); double Ask_price=SymbolInfo.Ask();
回测对比与组合效益
分别测策略A(EURUSD、GBPUSD)、策略B(AUDUSD、EURJPY)后,再开全部品种同跑。图2-7显示分开与组合的权益差异。组合EA能暴露相关性亏损,这是分别测试加总看不到的。
实践上,若账户只允许一个EA,此类结构直接满足;且便于统一魔法码分段、总权益风控。文末提供2multi_en.mq5源码供学。
与其他方案对比及总结
对比多图表多EA:组合EA省终端实例、易统管;对比信号跟单:自主逻辑、零延迟。缺点为代码复杂度高、需自管资源。总体结构简便,可放几乎所有策略,是进阶MQL5必会模式。
- 单EA多策略:易风控、省资源,但需for调度
- 多EA:隔离好,但占实例、难统观
- 信号跟单:省事,但依赖他人与网络