如何快速创建一个"2010 年自动交易锦标赛"专用"EA 交易"(基础篇)
用 MT5 快速搭一个锦标赛风格 EA 骨架
想在 MT5 里复刻「2010 自动交易锦标赛」那种 EA 的起步结构,其实不需要从零写策略,先跑通一个最小可执行框架更实际。官方示例里这类 EA 通常挂在 OnTick 里做条件判断,再用 CTrade 下单,省去手动处理交易返回码。 根据站内示例存档,这篇 2013-11-08 发布的入门帖被查看 3411 次、收藏 7 次,说明即便多年后仍有交易者在照着搭基础框架。外汇与贵金属杠杆高、滑点跳空频繁,直接上实盘前务必在策略测试器用历史数据验证至少 3 个月。 最小骨架建议先写死一个均线穿越逻辑占位,确认编译通过、回测能出成交,再替换成你自己的信号。MT5 的高频 tick 回测对 EA 稳定性要求明显高于 MT4,早期就把日志打印开起来能少走弯路。
◍ 从现成模板起步写 EA
想参加 2010 自动交易锦标赛这类活动,没必要从零搭框架。直接用《交易机器人的原型》里给出的 EA 模板就行,它的策略基类、常用函数和整体结构都已经写好,新手 MQL5 程序员也接得住。 你真正要补的只是少量代码:把本人的交易想法翻译成开平仓逻辑。准备动作拆开看有六件——选策略、写 EA、回测、在策略测试器里做优化、调参优化、换不同周期再测一遍。 这类活儿的高风险在于:外汇和贵金属杠杆品种,回测漂亮不代表实盘能跑,过度拟合会让样本外表现塌房。建议每改一版参数,至少用 1 分钟和 1 小时两套周期各跑一次验证。
「顺着轨道线抢反弹的建仓逻辑」
不少老手默认随势交易比区间折腾更划算,而且盘中向通道边界的回弹,出现频率确实高于轨道线被直接击穿。基于这个观察,我们只在当前趋势方向上,等价格碰通道边界(轨道线)反弹时进场,而不是去赌边界突破。 平仓只看三件事:出现反向信号、打到 Stop Loss、或者触到 Take Profit,不额外加主观过滤。趋势判定上,日线 MACD 的连续变化是核心——连续两个柱增长视为买入信号,连续两个柱缩短视为卖出信号;具体下单则切到小时图,等价格真从轨道线弹起来再动手。 EURUSD 日线图里能直观看到,MACD 柱体连增两根的窗口,往往对应一波像样的向上反抽;而小时图上的轨道线边界,反弹触点比假突破多出不少。外汇与贵金属杠杆高,这种抢反弹手法在单边市里容易被止损,实盘前先用 MT5 回看近三个月 EURUSD 的轨道线反应再定参数。
把策略骨架编译成可测的 EA 类
EA 的躯干可以直接继承 CExpertAdvisor 基类,不用从零写订单与仓位管理。上面这段代码把外部输入和内部变量分成了两层:input 是你在 MT5 参数面板上能改的,protected 成员则是运行时真正被引用的副本。 注意指标句柄的创建位置——MACD 挂在 PERIOD_D1、轨道线挂在 PERIOD_H1,两套周期硬耦合在 Init() 里。若你想测 H4 共振,得改这两行的 PERIOD_ 常量,否则回测里信号源不会变。 析构函数里用 IndicatorRelease 释放 m_hmacd 与 m_henvel,避免重复加载指标拖慢策略测试器。编译通过后,把 ex5 丢进策略测试程序跑 2003—2023 的 XAUUSD 日线,才可能看出 SL=50 / TP=100 这组默认参数的盈亏分布倾向。外汇与贵金属杠杆高,回测盈利不代表实盘能复现,参数须自行承压验证。
class="macro">#include <ExpertAdvisor.mqh> class="kw">input class="type">int SL = class="num">50; class=class="str">"cmt">// 止损距离 class="kw">input class="type">int TP = class="num">100; class=class="str">"cmt">// 获利距离 class="kw">input class="type">int TS = class="num">50; class=class="str">"cmt">// 追踪止损距离 class="kw">input class="type">int FastEMA = class="num">15; class=class="str">"cmt">// 快速 EMA class="kw">input class="type">int SlowEMA = class="num">26; class=class="str">"cmt">// 慢速 EMA class="kw">input class="type">int MACD_SMA = class="num">1; class=class="str">"cmt">// MACD 信号线 class="kw">input class="type">int EnvelPer = class="num">20; class=class="str">"cmt">// 轨道线周期 class="kw">input class="type">class="kw">double EnvelDev = class="num">0.4; class=class="str">"cmt">// 轨道线方差 class="kw">input class="type">class="kw">double Risk = class="num">0.1; class=class="str">"cmt">// 风险 class CMyEA : class="kw">public CExpertAdvisor { class="kw">protected: class="type">class="kw">double m_risk; class=class="str">"cmt">// 风险大小 class="type">int m_sl; class=class="str">"cmt">// 止损 class="type">int m_tp; class=class="str">"cmt">// 获利 class="type">int m_ts; class=class="str">"cmt">// 追踪止损 class="type">int m_pFastEMA; class=class="str">"cmt">// 快速 EMA class="type">int m_pSlowEMA; class=class="str">"cmt">// 慢速 EMA class="type">int m_pMACD_SMA; class=class="str">"cmt">/// MACD 信号线 class="type">int m_EnvelPer; class=class="str">"cmt">// 轨道线周期 class="type">class="kw">double m_EnvelDev; class=class="str">"cmt">// 轨道线方差 class="type">int m_hmacd; class=class="str">"cmt">// MACD指标句柄 class="type">int m_henvel; class=class="str">"cmt">// 轨道线指标句柄 class="kw">public: class="type">void CMyEA(); class="type">void ~CMyEA(); class="kw">virtual class="type">bool Init(class="type">class="kw">string smb,ENUM_TIMEFRAMES tf); class=class="str">"cmt">// 初始化 class="kw">virtual class="type">bool Main(); class=class="str">"cmt">// 主函数 class="kw">virtual class="type">void OpenPosition(class="type">long dir); class=class="str">"cmt">// 根据信号开仓 class="kw">virtual class="type">void ClosePosition(class="type">long dir); class=class="str">"cmt">// 根据信号平仓 class="kw">virtual class="type">long CheckSignal(class="type">bool bEntry); class=class="str">"cmt">// 检查信号 }; class=class="str">"cmt">//------------------------------------------------------------------ class=class="str">"cmt">//------------------------------------------------------------------ class="type">void CMyEA::~CMyEA() { IndicatorRelease(m_hmacd); class=class="str">"cmt">// 删除MACD指标 IndicatorRelease(m_henvel); class=class="str">"cmt">// 删除轨道线指标 } class=class="str">"cmt">//------------------------------------------------------------------ class=class="str">"cmt">//------------------------------------------------------------------ Init class="type">bool CMyEA::Init(class="type">class="kw">string smb,ENUM_TIMEFRAMES tf) { if(!CExpertAdvisor::Init(class="num">0,smb,tf)) class="kw">return(class="kw">false); class=class="str">"cmt">// initialize parent class class=class="str">"cmt">// 复制参数 m_risk=Risk; m_tp=TP; m_sl=SL; m_ts=TS; m_pFastEMA=FastEMA; m_pSlowEMA=SlowEMA; m_pMACD_SMA=MACD_SMA; m_EnvelPer = EnvelPer; m_EnvelDev = EnvelDev; m_hmacd=iMACD(m_smb,PERIOD_D1,m_pFastEMA,m_pSlowEMA,m_pMACD_SMA,PRICE_CLOSE); class=class="str">"cmt">// 创建MACD指标 m_henvel=iEnvelopes(m_smb,PERIOD_H1,m_EnvelPer,class="num">0,MODE_SMA,PRICE_CLOSE,m_EnvelDev);class=class="str">"cmt">// 创建轨道线指标 if(m_hmacd==INVALID_HANDLE ||m_henvel==INVALID_HANDLE ) class="kw">return(class="kw">false); class=class="str">"cmt">//如果报错,则退出 m_bInit=true; class="kw">return(true); class=class="str">"cmt">// 允许交易 } class=class="str">"cmt">//------------------------------------------------------------------ CheckSignal