首页学院交易策略EA智能交易文章详细

MT4自带EA:MACD Sample详解与实战分析

外汇网2021-06-17 09:41:06 794
汇外网 - 全球专业的黄金外汇门户导航行情资讯网站

一、MACD Sample 注解

//+------------------------------------------------------------------+

//| MACD Sample.mq4 |

//| Copyright 2005-2014, MetaQuotes Software Corp. |

//| http://www.mql4.com|

//+------------------------------------------------------------------+

#property copyright "2005-2014, MetaQuotes Software Corp."

#property link "http://www.mql4.com"

input double TakeProfit =50; // 盈利目标点数

input double Lots =0.1; // 每单入场的手数

input double TrailingStop =30; // 跟踪止损的点数

input double MACDOpenLevel =3; // MACD开仓的参考位置

input double MACDCloseLevel =2; // MACD平仓的参考位置

input int MATrendPeriod=26; // 交易条件中运用的MA均线的周期数

程序最上面input开始的该数据均为外部变量,也就是在运用者调用的时机可以修改的部分。

这个EA是个常见的技术指标条件入场、条件出场、同期又执行移动止损功能的设置,很适合初学者研究。

先归纳这个程序的策略逻辑,以方便大家对号入座,赶紧理解。

多头开仓条件:MACD位于0轴以下 而且 差于指定的参数MACDOpenLevel*Point同期 MACD信号线上穿基准线(金叉)

而且 MA趋势往上。

多头平仓条件:MACD位于0轴上方 而且 大于指定的参数MACDCloseLevel*Point同期 MACD信号线下穿基准线(死叉)。

空头开仓条件:MACD位于0轴上方 而且 大于指定的参数MACDOpenLevel*Point同期 MACD信号线下穿基准线(死叉)

而且 MA趋势朝下。

空头平仓条件:MACD位于0轴以下 而且 大于指定的参数MACDCloseLevel*Point同期 MACD信号线上穿基准线(金叉)。

有了以上的初步了解,下面开始执行EA程序基本结构的分析:

1、OnTick()函数是最重要的实施部分,每来一个价格,此函数都自动实施一次,所以首要的逻辑结构都在这个函数里面。

2、程序的基本流程均为依照下方步骤执行,我们先牢牢记住这个结构,然后再对号入座去理解程序。

先分析目前本身的仓位状态,由于OnTick函数式循环运行的,所以中间的每个步骤全将运用OnTick函数,所以,当函数开始的时机我们首先要通过MT4的仓位操作函数得到目前的仓位状态,并更深一步依据状态执行不同分支的计算。

void OnTick(void)

{

double MacdCurrent,MacdPrevious;

double SignalCurrent,SignalPrevious;

double MaCurrent,MaPrevious;

int cnt,ticket,total;

//---

// initial data checks

// it is important to make sure that the expert works with a normal

// chart and the user did not make any mistakes setting external

// variables (Lots, StopLoss, TakeProfit,

// TrailingStop) in our case, we check TakeProfit

// on a chart of less than 100 bars

//---

if(Bars<100)

{

Print("bars less than 100");

return;

}

if(TakeProfit<10)

{

Print("TakeProfit less than 10");

return;

}

程序开始的下方两个部分不重要 简单说一下:

if(Bars<100)

{

Print("bars less than 100");

return;

}

上面代码的意思是假使目前图表中的k线少于100根将令在日志信息里输出提示信息而且终结OnTick()函数的实施。return的意思是返回,假使在程序中分析出有错误,下面的代码就不再继续实施了,我们调用return函数让它退出OnTick()函数的实施。 然而该种情形一般不会显现,所以我们自己写程序的时机可以不写这部分。

if(TakeProfit<10)

{

Print("TakeProfit less than 10");

return;

}

上面的代码意思是假使参数里的TakeProfit移动止损点数的设定假使差于10点,也提示一条信息并终结实施。TakeProfit从字面的意思中我们可以知道是止盈的意思,有些平台会制约下单时的止盈点数不得差于某个点,假使差于某值会在下单时报错,为了避免该种错误我们会制约参数中止盈的设定。

其实这里可以调用MarketInfo()函数得到我们目前平台中允许的止盈止损最小值进而依据平台的不同自动计算出最小的止盈点数,详细情形请参阅文档MarketInfo()函数的描述。加入这段代码是为了防止乱设数值,引起后面计算的错误。这部分,假使程序导致我们自己运用,预期不会犯该种低级错误,所以写程序的时机也可以忽视不写。

下面这段:

//--- to simplify the coding and speed up access data are put into internal variables

MacdCurrent=iMACD(NULL,0,12,26,9,PR洲际交易所_CLOSE,MODE_MAIN,0);

MacdPrevious=iMACD(NULL,0,12,26,9,PR洲际交易所_CLOSE,MODE_MAIN,1);

SignalCurrent=iMACD(NULL,0,12,26,9,PR洲际交易所_CLOSE,MODE_SIGNAL,0);

SignalPrevious=iMACD(NULL,0,12,26,9,PR洲际交易所_CLOSE,MODE_SIGNAL,1);

MaCurrent=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PR洲际交易所_CLOSE,0);

MaPrevious=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PR洲际交易所_CLOSE,1);

这部分是变量赋值部分,等于提早计算出为后面用到的目前MACD数值以及MA数值,如此提早写出来在后面直接运用赋值后的变量就很清楚了,这是一个很好的编程习惯。

以上语句调用了MQL的一部分内置指标函数,在MQL语言中,对于常用的指标如MA,MACD,KD等MQL4已经供应给我们现成的函数,我们只要调用这些内置的函数即可得到指标的值。上面的代码,MacdCurrent的值是参数为12,26,9的MACD主线目前的值,MacdPrevious则是MacdCurrent前一根K线MACD主线的值,SignalCurrent和SignalPrevious则是相同参数MACD信号线的目前值和前一根值。 后两个是调用均线指标函数,这里的均线周期参数则是运用了EA的参数变量MATrendPeriod,如此写是个好习惯,把调用指标的参数放到EA参数里,如此可以随时在运行中调整这些参数方便我们更改策略。MaCurrent和MaPrevious是得到26期均线的目前K线值和前一根的值。

再下面开始最首要的程序逻辑部分,首先遇到的就是我们上面说过的通过仓位函数得到目前状态的部分。

total=OrdersTotal();

if(total<1)

{

//--- no opened orders identified

上面的代码分析我们目前能否有单子在做,它调用了OrdersTotal()函数,该函数可以计算目前账户中一共还没有平仓的单子和挂单的个数,假使它差于1,则表明是空仓状态,那么接下去就执行多头和空头的入场条件分析,假使满足条件则执行入场。

if(AccountFreeMargin()<(1000*Lots))

{

Print("We have no money. Free Margin = ",AccountFreeMargin());

return;

}

上面的代码是计算目前的可用预付款能否充足下单,假使不够就输出目前可用预付款只剩多少,然后直接退出,不执行后续入场条件分析。

//--- check for long position (BUY) possibility

if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious

MathAbs(MacdCurrent)>(MACDOpenLevel*Point) && MaCurrent>MaPrevious)

{

ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,0,Ask+TakeProfit*Point,"macd sample",16384,0,Green);

if(ticket>0)

{

if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))

Print("BUY order opened : ",OrderOpenPrice());

}

else

Print("Error opening BUY order : ",GetLastError());

return;

}

上面这段就是多单开仓部分了,条件是如此:假使目前MACD主线在0轴下方,MACD“金叉”,MACD的主线不在0轴附近(这块是EA的参数来指定0轴附近多少点)而且还要目前的均线是上升的。这里最精彩的部分在于如何分析MACD“金叉”,如何分析MACD值不在0轴附近和均线当前是上升的依旧下滑的。“金叉”的分析是EA里用的比较多的,这里我们用了分析大小的方法就能很容易的计算它,首先得到MACD两根线目前的值和上一根K线的MACD值,假使上一根K线的MACD主线大于信号线而且目前的MACD主线差于信号线那就相当于这两根线做了一个“交叉”,所以我们可以觉得MACD“金叉”了。从这里我们也能看出来用计算机的方法来处理我们人类所认知的困难靠的均为该种具体数值的计算,所以计算机依旧比较“死板”的,假使两根线“扭”在了一起那么用计算机程序很难分析出来,这些就是当前计算机程序的缺点。 0轴附近该种分析方法这里利用了一点数学方面的知识,然而不用担忧均为很简单的算法。把MACD值做绝对值运算然后分析能否大于指定的值,由于MACD将是负数做绝对值运算后直接分析能否大于设定的值就行了,这块相当于是简化了分析语句的条件。均线的上升和下滑分析和“金叉”的算法差不多,得到目前均线值和前一根线的均线值,假使前一根均线值差于目前值那就表明均线是上升的。

记得一定要分析进场能否成功,由于很多服务器受于滑点或者服务器价格变动而不能成交,所以,要在分析进场不成功后做出提示。ticket就是定单入场能否成功的标记。if(ticket>0) 大于0则表明进场成功。假使进场不成功,则输出不成功的系统原因。

if(ticket>0)

{

if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))

Print("BUY order opened : ",OrderOpenPrice());

}

else

Print("Error opening BUY order : ",GetLastError());

return;

}

return; 这里为何运用了返回呢。由于一种情形是进场成功,那么直接返回等候下一个价格来临的时机再实施OnTick函数,其他情形是进场不成功,则返回也是等候下一个价格来临的时机在此实施入场操作。

下面是空单进场的分析了,大家自己对照观看即可:

//--- check for short position (SELL) possibility

if(MacdCurrent>0 && MacdCurrentSignalPrevious &&

MacdCurrent>(MACDOpenLevel*Point) && MaCurrent

{

ticket=OrderSend(Symbol(),OP_SELL,Lots,Bid,3,0,Bid-TakeProfit*Point,"macd sample",16384,0,Red);

if(ticket>0)

{

if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))

Print("SELL order opened : ",OrderOpenPrice());

}

else

Print("Error opening SELL order : ",GetLastError());

}

//--- exit from the "no opened orders" block

return;

}

这段代码就是空单的进场条件,和上面多单进场的条件刚好相反。值得表明的是这两个下单代码中会遇到下单失利的情形,由于当用OrderSend()函数下单后会返回一个大于0的整数订单号数值,利用这一点就可以很容易的知道下单能否成功了。

开仓以后接下去的代码是平仓和移动止损部分,这段代码比较难懂,但是却是非常重要的部分,由于在编撰EA中这些操作会经常遇到,让我们来一点一点的拆解开来注解它们的含义。

//--- it is important to enter the market correctly, but it is more important to exit it correctly...

for(cnt=0;cnt

目前存在的订单中我们要分析能否到达平仓的条件,所以第一步我们首先要对所有在下的单子执行一次遍历,一个一个的去分析它们能否高达平仓条件。此代码中利用了一个循环语句从第一单开始一单一单的循环,这里值得注意的是所有单子均为依照下单的先后顺序存放的,第一张单子的编号是0并非是1,这是编程语言中广泛采取的方法,我们在编撰程序的时机一定要注意它的值要从0开始。

OrderSelect(cnt,SELECT_BY_POS,MODE_TRADES);

这段代码是选择订单操作,当循环一次订单后,务必调用OrderSelect()函数来锁定这一订单,如此下面的操作才可以正常运行。这里最容易出错的地方是函数的第二个参数。假使查一下文档我们会发现它有两个选项:SELECT_BY_POS和SELECT_BY_TICKET。第一种方式是依据订单的位置执行选定操作,这个例子中就是运用了该种方式,第二种方式是依据订单号来执行选定操作,由于我们并没有知道所有单子的订单号是多少,所以我们只能运用第一种方式来选择订单。刚才说过订单是依照下单的先后顺序来存放的,所以假使是第一个单子那就是0,假使是第二个单子就是1,最后一个单子是总单子数减1。

if(OrderType()<=OP_SELL && // check for opened position

OrderSymbol()==Symbol())// check for symbol

上面的代码段又运用了一个小技巧,它首先调用了OrderType()函数来得到所选定的订单是多单依旧空单,我们查下这个函数的定义可以发现多单的值是0,空单的值是1,那么假使OrderType()函数差于等于空单的值,就相当于是分析目前订单为市价成交单并非是挂单。第二个条件是分析目前单子的货币对能否和目前图表相同,这个分析是为了防止我们处理订单过程中误操作了其余不是EA所下的单子。

{

//--- long position is opened

if(OrderType()==OP_BUY)

{

//--- should it be closed?

if(MacdCurrent>0 && MacdCurrentSignalPrevious &&

MacdCurrent>(MACDCloseLevel*Point))

{

//--- close order and exit

if(!OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet))

Print("OrderClose error ",GetLastError());

return;

}

多单的平仓部分代码,这里其实就是去掉均线条件的空单下单信号,平仓操作中一定要注意在平仓完成后务必终止这个遍历订单的循环,由于平仓后会打乱所有单子的顺序,产生误操作其余订单。

我们在这里举个例子就能明白为何要这么做:比如目前有三个单子没有平仓,依照顺序排列序号是0、1、2,假使第二个单子平仓后第三个单子序号就会提早,如此现在一次循环实施到OrderSelect()函数后会由于没有这个编号而显现错误。

//--- check for trailing stop

if(TrailingStop>0)

{

if(Bid-OrderOpenPrice()>Point*TrailingStop)

{

if(OrderStopLoss()

{

//--- modify order and exit

if(!OrderModify(OrderTicket(),OrderOpenPrice(),Bid-Point*TrailingStop,OrderTakeProfit(),0,Green))

Print("OrderModify error ",GetLastError());

return;

}

}

}

}

这段代码就是多单的移动止损部分。当参数TrailingStop大于0的时机EA就开启了移动止损功能(默认设定是30,也就是说默认情形下是开启移动止损的),我们就用我们这个例子EA的默认参数30点来看明,当单子的盈利大于30点而且单子的止损点和目前价位相差30点以上时,修改订单的止损到目前价格下方30点位置。

我们在上面的程序里屡次发现作者运用Point变量来计算点位,这个变量是MT4运行环境中自动设定的值,它在MQL语言中叫做预定义变量(有关预定义变量可以参考这里:http://docs.mql4.com/cn/predefined/variables),Point告诉我们目前货币对的单价最小点值是多少,举个例子:欧元对美元的单价总是X.XXXX该种形式,它的Point值就是0.0001,当我们想设定当价格大于30点该种情形时,我们只要用30乘以Point就可以计算这个货币对的事实30点值。然而Point常量在很多平台中不能正确的来达到它自身的功能了,原因是很多平台已经改为小数点后5名,如此Point值变成了0.00001,我们直接用它来乘以点位得到的却是事实点位的十分之一,如此会在EA的运行中显现致命的逻辑错误。所以,假使是小数点后5名的平台,需要在那些点位的值上乘以10来修正这个困难。

上面完整地表明了持仓单为多单的时机所执行的2项处理。后面空单持仓的代码大家对照观看即可。

else // go to short position

{

//--- should it be closed?

if(MacdCurrent<0 && MacdCurrent>SignalCurrent &&

MacdPrevious(MACDCloseLevel*Point))

{

//--- close order and exit

if(!OrderClose(OrderTicket(),OrderLots(),Ask,3,Violet))

Print("OrderClose error ",GetLastError());

return;

}

//--- check for trailing stop

if(TrailingStop>0)

{

if((OrderOpenPrice()-Ask)>(Point*TrailingStop))

{

if((OrderStopLoss()>(Ask+Point*TrailingStop)) || (OrderStopLoss()==0))

{

//--- modify order and exit

if(!OrderModify(OrderTicket(),OrderOpenPrice(),Ask+Point*TrailingStop,OrderTakeProfit(),0,Red))

Print("OrderModify error ",GetLastError());

return;

}

}

}

}

}

}

//---

}

//+------------------------------------------------------------------+

细心的读者会发现,上面针对空单实施移动止损的代码对比针对多单移动止损的代码多了|| (OrderStopLoss()==0)) 这一段,这是由于对空单实施首次移动止损时,假使该空单没有设置初始止损价的话,那么依照上面相似多单移动止损设置的代码编撰的话空单的移动止损就不会实施,由于OrderStopLoss()等于0,所以(OrderStopLoss()>(Ask+Point*TrailingStop)便不成立,所以,针对空单设置移动止损的代码需要增长|| (OrderStopLoss()==0)) 这一段,以防碰到空单没有设置初始止损时程序无法实施。

以上就是MT4自带EA:MACD Sample的注解,这个程序尽管比较复杂但是它却是一个很好的例子,里面涉及到了我们在写EA程序过程中经常用到的一部分功能,对于初学EA程序的人来看帮助很大,我们也可以修改这个程序的开仓、平仓部分运用我们自己的逻辑把它变成我们自己的策略逻辑。

事实上多部分EA程序的结构都和上面差不多,并没有复杂,期望通过如此的讲解,能让大家先对EA该种神秘的程序得到一个初步的框架。不要着急去想具体的语句,先把该种逻辑关系想的很清楚,后面就会越学越快!

二、基本策略

依据以上分析,可以看出该EA所运用的基本策略如下:

1、多头开仓:MACD处在0轴以下+MACD指标低点金叉+均线上升

空头开仓:MACD处在0轴上方+MACD指标高点死叉+均线下滑

2、多头平仓:MACD处在0轴上方+MACD指标高点死叉

空头平仓:MACD处在0轴以下+MACD指标低点金叉

3、多头移动止损:订单止损价>卖价+移动止损*点,修改订单止损价

空头移动止损:订单止损价<买价 - 移动止损*点,修改订单止损价

标签:

随机快审展示
加入快审,优先展示

加入VIP