手把手写MACD Sample智能交易
🤖

手把手写MACD Sample智能交易

从零理解MQL4中经典EA的构建与风控逻辑

MQL5 编程 难度 · 入门 2026-06-12 9 分钟阅读
#MQL4#MACD#智能交易#EA开发

什么是MACD Sample智能交易

MACD Sample是MetaQuotes官方提供的一个经典MQL4智能交易(EA)示例,它以标准MACD指标为基础,展示了如何编写一个具备开仓、平仓、赢利目标与追踪止损功能的简单自动交易系统。这个示例并不追求高收益策略,而是作为教学模板,帮助初学者理解EA的标准程序结构与订单管理逻辑。在MetaTrader 4平台中,几乎所有新手第一个研究的EA都是它。

该EA的核心思想是:利用MACD主线与信号线的交叉,并结合零轴位置与均线趋势过滤,产生买卖信号;同时用固定止盈与动态追踪止损控制风险。原文强调,这个范例展示了赢利水平设定、追踪止损设置等特性,通过开仓和管理仓位来完成交易,是理解MQL4编程原理的最佳起点。

✦ 学习价值
即便你现在使用MQL5,理解MQL4的MACD Sample也能帮你掌握跨平台EA的通用设计模式,如外部参数、订单遍历、止损修改等。

交易逻辑与入场出场规则

在编写代码前,必须明确策略规则。MACD Sample的买卖条件如下:多头(BUY)入场——MACD指标在零轴以下,从下至上穿过信号线,且MACD绝对值大于过滤阈值,同时EMA趋势向上。空头(SELL)入场——MACD在零轴以上,从上至下穿过信号线,且MACD值大于阈值,同时EMA趋势向下。

出场条件分为三类:一是达到固定赢利上限(TakeProfit);二是触发追踪止损(TrailingStop);三是反向交叉信号出现。具体为:多头退出当MACD在零轴上从上向下穿信号线,或赢利/追踪条件满足;空头退出当MACD在零轴下从下向上穿信号线,或对应风控触发。

原文特别提示,要排除MACD指标微不足道的小“山丘”噪音。办法是要求指标变化大小至少达到5*Point(对USDCHF为0.0005,对USDJPY为0.05),即MACDOpenLevel*Point的过滤。这避免了在震荡中频繁假突破开仓。

步骤一:创建EA与描述信息

在MT4导航窗口中右键点击“智能交易系统”,选择“创建新智能交易”。向导会要求填写名称(MACD Sample)、作者、链接与注解。这些信息写入代码头部,便于在策略测试器中识别。虽然看似繁琐,但规范的描述有助于后续在社区分享或调试时定位版本。

创建后,MetaEditor会生成基础框架。我们不需依赖向导生成的冗长注释,而应主动规划程序结构。标准EA结构包括:外部变量声明、初始数据检测、内部变量缓存、终端状态检测、开仓判断、持仓管理循环,最后返回。这种线性流程让逻辑清晰且易维护。

步骤二:程序基本结构与外部变量

MQL4要求所有变量先声明后使用。外部变量(extern)可在EA属性中由用户调整,不需改代码即可灵活配置。MACD Sample声明了TakeProfit、Lots、TrailingStop、MACDOpenLevel、MACDCloseLevel、MATrendPeriod等。其中MATrendPeriod作为趋势过滤均线周期,默认26。

extern double TakeProfit = 50;
extern double Lots = 0.1;
extern double TrailingStop = 30;
extern double MACDOpenLevel=3;
extern double MACDCloseLevel=2;
extern double MATrendPeriod=26;

外部变量提供额外灵活性:例如你将TakeProfit设为120更适合一小时周期,而MACDOpenLevel控制噪音过滤强度。注意原文提醒,Lot尺寸与保证金占用相关,需确保账户自由保证金充足。

初始数据检测与图表校验

几乎所有稳健EA都应在start()开头做环境与参数校验。MACD Sample检测 Bars<100 时拒绝运行,因为指标需要足够历史计算;同时检测 TakeProfit<10 时退出,防止赢利过小无意义。这类防护能避免实盘因数据不足导致异常。

if(Bars<100)
  {
   Print("少于 100柱");
   return(0);  
  }
if(TakeProfit<10)
  {
   Print("赢利少于10");
   return(0);
  }

此段代码虽简单,却是生产级EA的标配。很多新手忽略历史柱数检查,在加载到新图表时因指标返回空值而错单。另外,Point代表当前品种点值,USDJPY的Point为0.01,与USDCHF不同,因此用Point乘阈值可跨品种通用。

指标值缓存与内部变量

为加速与简化,EA将iMACD、iMA返回值存入局部变量。例如MacdCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,0)取当前柱主线值;SignalPrevious取前一柱信号线。同理缓存EMA快慢值。这样后续逻辑直接用变量,避免重复调用消耗资源。

MacdCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,0);
MacdPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,1);
SignalCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,0);
SignalPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,1);
MaCurrent=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,0);
MaPrevious=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,1);

内部变量不仅提升性能,也令条件判断可读性增强。注意iMACD参数依次为:品种、周期、快EMA、慢EMA、信号SMA、价格类型、模式(主线/信号)、偏移。偏移0为当前未闭合柱,1为已闭合上一柱,这是交叉判断的关键。

账户保证金与无持仓开仓

EA先统计OrdersTotal(),若小于1表示无持仓,则进入开仓分支。开仓前必须检测AccountFreeMargin()是否足够:若自由保证金小于1000*Lots,打印“没有资金”并退出。这是基础风控,防止过度杠杆。

total=OrdersTotal();
if(total<1) 
  {
   if(AccountFreeMargin()<(1000*Lots))
     {
      Print("没有资金.自由保证金 = ", AccountFreeMargin());
      return(0);  
     }

随后判断BUY与SELL条件。BUY要求MacdCurrent<0且大于SignalCurrent,且前柱MacdPrevious<SignalPrevious,绝对值超阈值,且MaCurrent>MaPrevious。满足则用OrderSend发市价买,止损0、止盈Ask+TakeProfit*Point,魔法码16384。

if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious<SignalPrevious &&
   MathAbs(MacdCurrent)>(MACDOpenLevel*Point) && MaCurrent>MaPrevious)
  {
   ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,0,Ask+TakeProfit*Point,"macd sample",16384,0,Green);
  }

SELL对称:MacdCurrent>0且下穿信号,前柱也下穿,值超阈值,EMA下降。发卖单止盈Bid-TakeProfit*Point。OrderSend返回ticket>0为成功,否则打印GetLastError()。注意原文代码片段曾遗漏部分运算符,完整版见文末整合。

持仓管理与平仓逻辑

若已有持仓,EA用for循环遍历订单,OrderSelect按位置选单,检验OrderSymbol()==Symbol()避免操作其他品种。对OP_BUY单,若MacdCurrent>0且下穿信号且超CloseLevel,则OrderClose平仓。

if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious &&
   MacdCurrent>(MACDCloseLevel*Point))
  {
   OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet);
   return(0);
  }

空头平仓对称:MacdCurrent<0且上穿信号超阈值,用Ask价平。这部分确保反向信号出现时及时离场,不依赖止盈或追踪。

追踪止损的实现细节

追踪止损仅在盈利超出TrailingStop点后启动。对BUY:若Bid-开仓价>Point*TrailingStop,且原止损更差或零,则用OrderModify将止损移至Bid-Point*TrailingStop。对SELL:若开仓价-Ask>阈值且原止损差,则改至Ask+Point*TrailingStop。

if(TrailingStop>0)  
  {                 
   if(Bid-OrderOpenPrice()>Point*TrailingStop)
     {
      if(OrderStopLoss()<Bid-Point*TrailingStop)
        {
         OrderModify(OrderTicket(),OrderOpenPrice(),Bid-Point*TrailingStop,OrderTakeProfit(),0,Green);
        }
     }
  }

注意原文示例中判断OrderStopLoss()<新止损才修改,避免回退。追踪止损随价格有利移动锁定利润,是趋势EA核心组件。但需考虑点差与成交延迟,实盘中可适度放宽TrailingStop。

完整代码整合与编译设置

在MetaEditor属性菜单指定外部参数:Lots=1、SL=0(不用)、TP=120(一小时适用)、TS=30。按“编写”按钮,无错误则保存。完整MQ4整合了上述所有片段,并包含版权头。用户可从原文ZIP下载MACD_Sample.mq4。

⚠ 编译警告处理
现代编译器要求检查OrderSelect/OrderClose/OrderModify返回值。若报“should be checked”,可用if(!OrderClose(...)) Print(GetLastError());包裹以避免潜在沉默失败。

对比MQL5:MQL5使用CTrade类与position select by ticket,无OrderSend旧式语法,但逻辑等价。学习MQL4样本有助迁移至MQL5信号/跟单系统开发。

常见坑与对比其他方案

坑一:Point在部分券商报价小数位不同,需用MarketInfo(Symbol(),MODE_POINT)或自适应。坑二:跨品种订单未过滤会误平。坑三:未检查返回值导致改单失败不知情。相比直接使用指标画线手动交易,EA消除情绪但需严谨防御编程。

与复杂机器学习EA比,MACD Sample轻量透明,适合验证平台机制。当你在MQL5市场发布类似产品,也需类似结构并通过审核。掌握此范例,便掌握了MT4/MT5自动交易的一半基础。

常见问题

需同时满足:MacdCurrent<0 且 MacdCurrent>SignalCurrent 且 MacdPrevious<SignalPrevious 且 MathAbs(MacdCurrent)>MACDOpenLevel*Point 且 MaCurrent>MaPrevious,即用零轴下金叉加EMA向上过滤。
因为MACD和EMA指标需要足够历史柱计算初始值,Bars不足会导致iMACD返回空或异常,造成错单,所以代码开头用if(Bars<100) return(0)防护。
用if(!OrderClose(...)) Print("平仓失败:",GetLastError());替代直接调用,满足编译器对交易函数返回值的强制检查要求。
对多单,当Bid-开仓价>TrailingStop*Point且新止损价优于原止损时,OrderModify将止损设为Bid-TrailingStop*Point;空单对称用Ask+阈值,仅向盈利方向移动。
它是外部变量,用来过滤MACD微小“山丘”噪音,要求|Macd|必须大于MACDOpenLevel*Point才允许开仓,避免零轴附近假突破频繁交易。