使用面向对象的方法来编写EA的模式(基础篇)
📘

使用面向对象的方法来编写EA的模式(基础篇)

第 1/3 篇

「用类封装把EA骨架搭起来」

在 MT5 里写 EA,最怕把所有逻辑塞进 OnTick 一个函数里,改一处崩一片。把订单管理、信号判断、风控分别封装成类,能让策略模块各自独立,后期调参或换信号源都只用动对应类。 MQL5 自 2010 年随 MetaTrader 5 发布就完整支持面向对象,类、继承、多态都能用。下面这段骨架演示了如何用一个 CTrade 派生类接管下单动作,比直接调 OrderSend 更不容易写出脏代码。 实盘里类封装不会直接提升胜率,但能显著降低因逻辑耦合导致的误操作概率;外汇与贵金属杠杆高,任何下单路径的隐藏 bug 都可能放大亏损,隔离职责是基本功而非花活。

MQL5 / C++
class MyTrade : class="kw">public CTrade {
class="kw">public:
   class="type">bool OpenBuy(class="type">class="kw">double lot, class="type">class="kw">string sym) {
      class="kw">return Buy(lot, sym);
   }
};

◍ EA开发阶段与运行模式的分工

做 MT5 的 EA,先把开发拆成几个阶段看会更顺:需求定义、逻辑原型、运行模式选型、类结构实现。不同阶段用不同编程模式去落地,效率比一把梭写到底要高。 MetaTrader 5 里 EA 的运行模式不止一种,每种都有自己的实现路径和适用场景,后面会逐一拆开。把模式想清楚再写代码,能少走很多弯路,尤其在涉及外汇、贵金属这类高杠杆品种时,逻辑清晰才有办法控制风险。 本文会先理清 EA 开发的阶段组成,再讲 MT5 中 EA 的运行模式及辅助用法,最后用分层类实现把前面的想法落到代码上。你可以边读边开 MT5 的 MetaEditor 对照建工程。

EA 开发不是写段代码就完事

做一套 MT5 自动交易系统,真正吃重的是算法实现与回测验证,而不是界面或参数面板。原文把流程拆成多阶段,其中第五阶段才叫“算法交易”,需要开发者、程序员、分析师协作;若一个人包揽全部角色,才可能走通这条路径,这类人通常就是程序化交易者。 这套流程本身是可迭代的:每一轮开发周期都能对 EA 做修正和扩展,这比一次性写死逻辑更重要。外汇与贵金属品种波动受消息面冲击大,EA 在实盘前必须意识到高风险,任何阶段结论都只是“可能盈利”而非确定。 各阶段要用的工具与知识并不重叠,原文给出一个变量矩阵说明开发者常面对的简化选择维度。只有用高质量代码把已验证盈利的逻辑落地,才够得上第五阶段的标准;低质量实现即便碰巧赚钱,也难称算法交易。

「EA在MT5里的七种运行身份」

MT5 里的 EA 并非只有「挂上图表跑实盘」这一种状态。按程序文件分,有需要源文件+ex5 的调试/分析类,也有仅吃 ex5 的发布类;按数据分,策略测试器里的 6 种全跑历史数据,只有发布模式直面真实报价。成型的可交易程序(*.ex5)应在发布模式运行,其余模式留给测试与开发。 具体拆开看,MQL5 定义了 7 种执行模式:发布(0)、调试(1)、分析(2)、测试(3)、优化(4)、可视化(5)、时间框架集结(6)。除发布外,调试可用 IS_DEBUG_MODE 宏或 MQL_DEBUG 标识,分析用 IS_PROFILE_MODE 或 MQL_PROFILER,测试/优化/可视化/帧模式都没有宏,只能靠 MQLInfoInteger() 配合对应标识符判断。 一个容易踩的坑:优化模式开启时测试模式默认也开;可视化选中时日志会同时标出标准测试。时间框架集结模式更特殊,若在 OnInit() 里查,标识为 0,必须放进 OnTesterInit() / OnTesterPass() / OnTesterDeinit() 才能被 MQL_FRAME_MODE 抓到——我本地代理日志路径是 %Program Files\MetaTrader5\tester\Agent-127.0.0.1-3000\logs,可供你对照。 别把正态当圣经 发布模式下其他所有模式标识均为 0,所以函数里先排除调试/分析再判测试,顺序错了就会把优化误报成纯测试。写 CheckMqlModes() 塞进 OnInit() 跑一遍,日志打印的 yes/no 就是你当前 EA 的真实身份。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| MQL 模式                                                                 |
class=class="str">"cmt">//+------------------------------------------------------------------+
enum ENUM_MQL_MODE
  {
  MQL_MODE_RELEASE=class="num">0,       class=class="str">"cmt">// 发布
  MQL_MODE_DEBUG=class="num">1,         class=class="str">"cmt">// 调试
  MQL_MODE_PROFILER=class="num">2,      class=class="str">"cmt">// 分析 
  MQL_MODE_TESTER=class="num">3,        class=class="str">"cmt">// 测试
  MQL_MODE_OPTIMIZATION=class="num">4,  class=class="str">"cmt">// 优化
  MQL_MODE_VISUAL=class="num">5,        class=class="str">"cmt">// 可视化测试 
  MQL_MODE_FRAME=class="num">6,         class=class="str">"cmt">// 时间框架集结
  };
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| 检验所有MQL程序模式                                                    |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void CheckMqlModes(class="type">void)
  {
class=class="str">"cmt">//--- 如果是调试模式
   if(MQLInfoInteger(MQL_DEBUG))
      Print("Debug mode: yes");
   else
      Print("Debug mode: no");
class=class="str">"cmt">//--- 如果是分析模式
   if(MQLInfoInteger(MQL_PROFILER))
      Print("Profile mode: yes");
   else
      Print("Profile mode: no");
class=class="str">"cmt">//--- 如果是测试模式
   if(MQLInfoInteger(MQL_TESTER))
      Print("Tester mode: yes");
   else
      Print("Tester mode: no");
class=class="str">"cmt">//--- 如果是优化模式
   if(MQLInfoInteger(MQL_OPTIMIZATION))
      Print("Optimization mode: yes");
   else
      Print("Optimization mode: no");
class=class="str">"cmt">//--- 如果是可视化测试模式

◍ 用 MQLInfoInteger 区分 EA 运行环境

EA 在 MT5 里跑,不一定是你以为的那个环境。发布版、调试版、性能剖析版,以及是否在回测器、优化器、可视化模式下,行为可能完全不同,靠肉眼看图表判断容易误事。 下面这段直接在 OnStart 里调用 MQLInfoInteger 探环境,能打印当前到底是哪种模式: if(MQLInfoInteger(MQL_VISUAL_MODE)) Print("Visual mode: yes"); else Print("Visual mode: no"); //--- 如果是时间框架聚集的优化结果模式 if(MQLInfoInteger(MQL_FRAME_MODE)) Print("Frame mode: yes"); else Print("Frame mode: no"); 逐行拆:第1行用 MQL_VISUAL_MODE 查是否带可视化(图表上肉眼可见 K 线走动);第3行否就打印 no。第6行 MQL_FRAME_MODE 查是否处于多周期框架聚合的优化结果模式;第8行对应打印。 实跑日志里能看到明确分界:17:20:38 那次 Current mode 是 MQL_MODE_RELEASE,Debug/Profile/Tester/Optimization/Visual/Frame 全为 no;切到 17:27:47 变成 MQL_MODE_DEBUG,仅 Debug mode 翻成 yes,其余仍 no。外汇与贵金属杠杆高,环境误判可能导致实盘逻辑和回测不一致,开 MT5 把这段贴进脚本跑一遍,确认你本地当前是哪一种。

MQL5 / C++
if(MQLInfoInteger(MQL_VISUAL_MODE))
   Print("Visual mode: yes");
else
   Print("Visual mode: no");
class=class="str">"cmt">//--- 如果是时间框架聚集的优化结果模式
if(MQLInfoInteger(MQL_FRAME_MODE))
   Print("Frame mode: yes");
else
   Print("Frame mode: no");

常见问题

用类把下单、风控、信号各自封装成独立模块,主流程只调用方法,后续改策略不用动骨架。
回测、实盘、优化是不同运行身份,用环境判断区分逻辑,比如实盘才发通知,回测跳过。
小布可以读你的EA结构描述或片段,标出类职责不清的地方,并给拆分建议,省去自己排查。
至少分设计骨架、实现策略、环境适配、测试校验四步,缺了环境适配实盘容易崩。
调用运行环境识别函数拿到整数标志,比对对应常量即可分支处理,避免误发订单或弹窗。