EA简明教程收集以及修改

2012-02-15 12:50:27    来源:    作者:

第一篇 创建新文件
1、打开 MetaEditor (如何打开自己想办法)呵呵,如果这个都打不开,拜托下面的也不用看了。也许你不适合研究这个。
2、选择文件-->新文件 打开文件创建页面。
3、选择第二项 客户指标  然后点下一步。
  注:这个页面可以创建6种文件。我们常用的有 《客户指标》,《脚本》,《智能交易系统》三种。我们先从指标开始。
4、输入名字,作者等等。(支持中文)暂时不添加参数。
  注:这个位置可以添加用户变量以后讲解。
5、下一步 我们先建一个主窗口指标 所以这个页面什么都不用操作
  注:这个位置可以添加指标“线”。以后提及。
6、点击完成。
ok新的指标文件生成了。但还没有任何有用的代码。初始化代码齐全。

//+------------------------------------------------------------------+
//|                                                  MT4指标编辑.mq4 |
//|                                                              ldj |
//|                                        [url]http://www.metaquotes.net[/url] |
//+------------------------------------------------------------------+
#property copyright "ldj"
#property link      "http://www.metaquotes.net"

#property indicator_chart_window
//+------------------------------------------------------------------+
//| Custom indicator initialization function                        |
//+------------------------------------------------------------------+
int init()
  {
//---- indicators
//----
  return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                      |
//+------------------------------------------------------------------+
int deinit()
  {
//----
  
//----
  return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
  int    counted_bars=IndicatorCounted();
//----
  
//----
  return(0);
  }
//+------------------------------------------------------------------+
上面的就是刚刚新建的一个指标文件。
第一部分  指标注释 只是一个说明,有没有都不影响指标运行。
//+------------------------------------------------------------------+
//|                                                  MT4指标编辑.mq4 |
//|                                                              ldj |
//|                                        [url]http://www.metaquotes.net[/url] |
//+------------------------------------------------------------------+
这部分中前面的 “//” 两个斜线 说明后面的是注释语句,不参与实际运行。
第二部分  预处理语句 这部分规定了指标的窗口性质。如下:
#property copyright "ldj"
#property link      "http://www.metaquotes.net"

#property indicator_chart_window
#号表示后面是预处理语句。
property 的意思是定义mt4内部变量的性质。变量名是mt4定义好的只能用固定的变量名。
例如:版权变量 copyright 链接变量 link 以及指标窗口类型变量indicator_chart_window等等。
其中窗口类型变量有indicator_chart_window(主窗口)indicator_separate_window(副窗口)两个这里只能用一个不能两个同时用
这部分内容一般不需要修改。
第三部分  初始化函数(加载函数)
//+------------------------------------------------------------------+
//| Custom indicator initialization function                        |
//+------------------------------------------------------------------+
int init()
  {
//---- indicators
//----
  return(0);
  }
这个函数中的代码只在只在指标(EA)加载的时候执行一次。用于对一些变量的初始化。
去初注释函数体为
int init()
  {
  return(0);
  }
第三部分  卸载函数
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                      |
//+------------------------------------------------------------------+
int deinit()
  {
//----
  
//----
  return(0);
  }
当去初指标(EA)的时候执行一次。用于去除一些控件。
去除注释函数体为
int deinit()
  {
    return(0);
  }
第四部分  主函数,每当价格变化时就调用执行一次。主要执行代码都在这里。
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
  int    counted_bars=IndicatorCounted();
//----
  
//----
  return(0);
  }
第五部分 子函数。有些指标和EA含有子函数。我习惯写在后面。

华丽的分割线
===================================================================
#property indicator_buffers 3
#property indicator_separate_window
#property indicator_color1 White
#property indicator_color2 Red
#property indicator_color3 Silver
double Buffer1[];
double Buffer2[];
double Buffer3[];
extern int Fast = 10;
extern int Slow = 22;
extern int Signal = 7;
int init()
  {
  SetIndexStyle(0,DRAW_LINE,0,1);
  SetIndexStyle(1,DRAW_LINE,0,1);
  SetIndexStyle(2,DRAW_HISTOGRAM,0,1);
  SetIndexBuffer(0,Buffer1);
  SetIndexBuffer(1,Buffer2);
  SetIndexBuffer(2,Buffer3);
  IndicatorShortName("MACD("+Fast+","+Slow+","+Signal+")");
  SetIndexLabel(0,"MACD_MAIN");
  SetIndexLabel(1,"MACD_SIGNAL");
  SetIndexLabel(2,"MAIN-SIGNAL");
  IndicatorDigits(Digits+2);
  return(0);
  }
int deinit()
{
return(0);
}
int start()
  {
  int limit,counted_bars=IndicatorCounted();
  if(counted_bars<0) return(-1);
  if(counted_bars>0) counted_bars--;
  limit=Bars-counted_bars;
  for(int i=0; i<limit; i++)
    {
      Buffer1=iMACD(NULL,0,Fast,Slow,Signal,PRICE_CLOSE,MODE_MAIN,i);
      Buffer2=iMACD(NULL,0,Fast,Slow,Signal,PRICE_CLOSE,MODE_SIGNAL,i);
      Buffer3=Buffer1 - Buffer2;
    }
  return(0);
  }
MACD1
下面我们来逐步实现这个指标。
我们要形成双线MACD和一个柱状指标。
因此我们在副图上要形成3个指标线。
主指标
信号指标
柱状指标
1、第一步确认指标显示的窗口
#property indicator_separate_window
//    #property indicator_chart_window
这条代码决定了指标在副图窗口显示。下面那条注释语句表示在主图窗口也就是K线图上显示。
2、预定义3个缓冲区来显示这三个指标线
#property indicator_buffers 3
#property indicator_color1 White
#property indicator_color2 Red
#property indicator_color3 Silver
#property indicator_buffers 3 语句预定义三个指标缓存区。
#property indicator_color1 White
#property indicator_color2 Red
#property indicator_color3 Silver
这三条语句为这三个指标预定义了三种颜色。
3、定义这三个指标的数组变量。
double Buffer1[];
double Buffer2[];
double Buffer3[];
double定义一个浮点变量。因为是一组数所以要定义一个数组“[]”。
4、在init()函数中初始化这三个指标。
  SetIndexStyle(0,DRAW_LINE,0,1);
  SetIndexStyle(1,DRAW_LINE,0,1);
  SetIndexStyle(2,DRAW_HISTOGRAM,0,1);
  SetIndexBuffer(0,Buffer1);
  SetIndexBuffer(1,Buffer2);
  SetIndexBuffer(2,Buffer3);
  IndicatorShortName("MACD("+Fast+","+Slow+","+Signal+")");
  SetIndexLabel(0,"MACD_MAIN");
  SetIndexLabel(1,"MACD_SIGNAL");
  SetIndexLabel(2,"MAIN-SIGNAL");
  IndicatorDigits(Digits+2);
IndicatorBuffers(3);//定义缓冲区的数量最多八个。因为这个指标只需要三个主缓冲区。所有这个有无都可以。有些需要辅助数组就需要定义这个。以后用到的时候再提起。
SetIndexStyle(0,DRAW_LINE,0,1);//定义指标的显示形式。DRAW_LINE标示画线指标。
看下这个内置函数的定义
SetIndexStyle( int index, int type, int style=EMPTY, int width=EMPTY, color clr=CLR_NONE)
  index:索引号。0就是第一个指标线1就是第二个指标线。
  type: 指标类型 下面是可选参数都是MT4的标准常量。
      DRAW_LINE      = 0 画线
      DRAW_SECTION  = 1 画线段
      DRAW_HISTOGRAM = 2 画柱状图
      DRAW_ARROW    = 3 画箭头符号(需要设置符号代码)
      DRAW_ZIGZAG    = 4 画锯齿图
      DRAW_NONE      = 12 不画图
  style:指标线型 0~4的选择。也可以不要,默认为0。
  Width:指标线宽 1~5的选择。也可以不要,默认为1。
  clr:  指标颜色 一般用#property indicator_color1 White语句定义。前面定义了所以我们这里没有定义。
SetIndexBuffer(0,Buffer1);//为定义的指标变量数组标记索引号。就是使他们一一对应。
  0号索引对应Buffer1[]变量。依此类推
IndicatorShortName("MACD("+Fast+","+Slow+","+Signal+")");//设置指标显示的名称,内容是用+号连接的字符串。
  就是当鼠标放在指标上所看到的指标名称。与文件名不相关。
SetIndexLabel(0,"MACD_MAIN");//设置指标的标记。就是当鼠标放在指标线上显示的第三行的名称。
  这条语句的意思是0号索引对应的指标变量标记是MACD_MAIN。其他类推。
IndicatorDigits(Digits+2);//定义指标的小数点位数数值是整数。这里Digits是MT4的预定义变量。其值为当前货币兑的小数位。
主函数体
int start()
  {
  int limit,counted_bars=IndicatorCounted();
  if(counted_bars<0) return(-1);
  if(counted_bars>0) counted_bars--;
  limit=Bars-counted_bars;
  for(int i=0; i<limit; i++)
    {
      Buffer1=iMACD(NULL,0,Fast,Slow,Signal,PRICE_CLOSE,MODE_MAIN,i);
      Buffer2=iMACD(NULL,0,Fast,Slow,Signal,PRICE_CLOSE,MODE_SIGNAL,i);
      Buffer3=Buffer1 - Buffer2;
    }
  return(0);
  }
1、int limit,counted_bars=IndicatorCounted();//定义两个整形变量,并给counted_bars变量负值。
  这里面IndicatorCounted()函数是mt4内置函数不需要参数,其返回值为已经计算过的指标数组数量。
  如果指标错误则这个函数会返回一个负数。
2、if(counted_bars<0) return(-1); //如果条件成立说明指标调用运行错误。则退出程序。
3、if(counted_bars>0) counted_bars--;//从已经计算的指标中去除最后一条。
  这条语句用来修正counted_bars使得已经计算的最后一个数值可以在接下来的运算中重新计算一次。
4、limit=Bars-counted_bars;//计算需要计算的指标数据的柱数。
  这里需要说明。在mt4中指标数组的索引和K线的索引标记相同,是从后向前递增的从0开使的整数。
  也就是说,最后一条K线的索引是0同时K线所对应的指标索引也是0。
  那么倒数第2条的索引标记为1。倒数第三条的索引标记为2。
  这一点一定要理解清楚。不然写程序的时候就会发生错误。
  语句中的Bars是mt4预定义变量,其值是当前图表中K线的条数。
  这里详细说下为什么有个counted_bars--;的语句,这个语句的意思是对变量counted_bars进行自减一操作。
  因为主函数是每次价格变动就会运行一次。当运行完成后。IndicatorCounted()值应该等于Bars也就是K线的条数
  如果没有上面的自减一操作,那么当价格变动有了新的收盘价但并没有生成新的K线。这时候计算limit的值将=0.
  那么下面的for循环体将不会再计算最后一条k线相对应的指标数值。
  实际上这个是需要计算的(因为有了新的收盘价)。而有了自减一的操作就可以对最有一个,也就是当前K线对应的指标值进行运算。
  (不知道能看明白不自己慢慢捉摸捉摸)。这个自减一是必需的。
5、for(int i=0; i<limit; i++) for 循环语句(因为有了前面的自减一操作,这里limit最小等于1)
  关于for循环的运行不作解释。各位自己找资料学习。
6、Buffer1[ i ]=iMACD(NULL,0,Fast,Slow,Signal,PRICE_CLOSE,MODE_MAIN,i); //调用MACD指标函数为Buffer1数组负值。
  看下iMACD()这个内置指标函数的定义。
  iMACD( string symbol, int timeframe, int fast_ema_period, int slow_ema_period, int signal_period, int applied_price, int mode, int shift)
  symbol:          货币标识。通用指标用NULL常量。
  timeframe:        计算所依据的图表时间周期 。0表示依据当前图表周期。
  fast_ema_period: 快线周期
  slow_ema_period: 慢线周期
  signal_period:  信号线周期
  applied_price:  计算所用价格模式
  mode:            指标索引模式。MACD指标有两条线,因此这个位置有0,1两个选择。也可以用mt4预定义常量。
  shift:            索引号
  这里Buffer1取macd主线数据。Buffer2取macd信号线数据。
7、Buffer3[ i ]=Buffer1[ i ] - Buffer2[ i ];//计算MACD两条线之间的距离。
8、这里用到了外部变量。也可以叫用户自定义变量。这种变量在加载图表的时候可以修改。
extern int Fast = 10;
extern int Slow = 22;
extern int Signal = 7;
extern 关键字说明后面定义的变量是外部变量。

华丽的分割线2
=======================================================
问答题
瞬间的光辉/bull
本帖隐藏的内容需要回复才可以浏览

-------------------------------------------------------------------------------------------------------------------------------------------
瞬间的光辉questions

感激的没话说呀!牛版晚上12点还回答我的问题,而且回答的那么详细!
牛版的解释我认为是:所有论坛的高手中最无私最热心帮助别人的。
为了让更多的新手快速的入门EA,我决定做牛版帖子的追问者。牛版的帖子非常易懂,一般新手都能看懂70%,还有那30%的疑问,就由我来补问吧!

int OrderSend( string symbol, int cmd, double volume, double price, int slippage, double stoploss, double takeprofit, string comment=NULL, int magic=0, datetime expiration=0, color arrow_color=CLR_NONE)
comment参数有什么作用?A:这参数本意是用于记录这个订单的描述信息,程序只能在订单入场的时候设定他。同时系统会在这个订单发生止损 止赢或者拆单的时候自动修改这里的内容。

我一直想寻找一个函数能够返回我下的订单是否已经被止损或止赢了,问了好多人
都是同样的回答:OrdersTotal()<1就说明你下的订单平仓了,换句话说就是被止损或
止赢了。但是前提是我只能同时做一单,如果我同时做好几单呢,这怎么判断我下的其中
一单已经止损或止赢了。
今天看了牛版关于comment参数的解释,有了启发:
comment参数有什么作用?A:这参数本意是用于记录这个订单的描述信息,程序只能在订单入场的时候设定他。同时系统会在这个订单发生止损 止赢或者拆单的时候自动修改这里的内容。
既然订单发生止损 止赢或者拆单的时候自动修改这里的内容。
那我可以在下单的时候给comment赋值”on”,当订单生成后我可以用OrderComment()
函数实时获取它的comment值如果不等于”on”那就说明订单已经止损或止赢了。

MacdCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,0);
这句中你NULL是空货币吗?0代表0M吗?NULL和0有具体意思吗?我们自己用的时候需要具体化吧?A:Null表示当前图形上的货币
牛版只回答了NULL,那0呢,是不是也代表当前当前时段呢!
呵呵!给我留作业了吧!

华丽的分割线2
=======================================================

EA的基本框架

/+------------------------------------------------------------------+
//|                          Designed by bull, China                |
//|                  Copyright 2007, bull                        |
//|                                bbs.520fx.com                        |
//+------------------------------------------------------------------+
#property  copyright "Copyright 2007 , bull, China."
#property  link      "bbs.520fx.com"
#define MAGICMA
//+------------------------------------------------------------------+
//| 注意没有指标文件那些property                  |
//+------------------------------------------------------------------+
extern int whichmethod = 1;  //1~4 种下单方式  1 仅开仓, 2 有止损无止赢, 3 有止赢无止损, 4 有止赢也有止损
extern double TakeProfit = 100;  //止赢点数
extern  double StopLoss = 20;    //止损点数
extern double MaximumRisk    = 0.3; //资金控制,控制下单量
extern double TrailingStop =25;    //跟踪止赢点数设置
extern  int maxOpen = 3;  //最多开仓次数限制
extern  int maxLots = 5;  //最多单仓持仓量限制
extern int bb = 0;      //非零就允许跟踪止赢
extern double MATrendPeriod=26;//使用26均线 开仓条件参数  本例子

int i, p2, xxx,p1, res;
double Lots;
datetime lasttime;      //时间控制, 仅当一个时间周期完成才检查条件
int init()  //初始化
{
Lots = 1;
lasttime = NULL;
return(0);
}
int deinit() { return(0); } //反初始化
//主程序
int start()
{
CheckForOpen();    //开仓 平仓 条件检查 和操作
if (bb>0)  CTP();  //跟踪止赢
return(0);
}
//+------下面是各子程序--------------------------------------------+
double LotsOptimized()  //确定下单量,开仓调用 资金控制
{
double lot=Lots;
int  orders=HistoryTotal();  // history orders total
int  losses=0;            // number of losses orders without a break
//MarketInfo(Symbol(),MODE_MINLOT);    相关信息
//MarketInfo(Symbol(),MODE_MAXLOT);
//MarketInfo(Symbol(),MODE_LOTSTEP);
lot=NormalizeDouble(MaximumRisk * AccountBalance()/AccountLeverage(),1);    //开仓量计算
if(lot<0.1) lot=0.1;
if(lot>maxLots) lot=maxLots;
return(lot);
}
  
//平仓持有的买单
void CloseBuy()
{
if (OrdersTotal( ) > 0 )  
{
  for(i=OrdersTotal()-1;i>=0;i--)
  {
  if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false)    break;
  if(OrderType()==OP_BUY)
  {
    OrderClose(OrderTicket(),OrderLots(),Bid,3,White);
    Sleep(5000);
  }
  }
}
}
//平仓持有的卖单
void CloseSell()
{
if (OrdersTotal( ) > 0 )  
{
  for(i=OrdersTotal()-1;i>=0;i--)
  {
  if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false)    break;
  if(OrderType()==OP_SELL)
    {
    OrderClose(OrderTicket(),OrderLots(),Ask,3,White);
    Sleep(5000);
    }
  }
}
}
//判断是否买或卖或平仓
int buyorsell()  //在这个函数计算设置你的交易信号  这里使用MACD 和MA 做例子
{
  double MacdCurrent, MacdPrevious, SignalCurrent;
  double SignalPrevious, MaCurrent, MaPrevious;
  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);
if(MacdCurrent<0 & MacdCurrent>SignalCurrent && MacdPrevious<SignalPrevious
    & MaCurrent>MaPrevious)
  return (1); // 买 Ma在上升,Macd在0线上,并且两线上交叉
if(MacdCurrent>0 & MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious
    & MaCurrent<MaPrevious)
  return (-1); // 卖
return (0); //不交易
}
int nowbuyorsell = 0;
void CheckForOpen()
{
if (Time[0] == lasttime ) return; //每时间周期检查一次  时间控制
lasttime = Time[0];
nowbuyorsell = buyorsell(); //获取买卖信号

if (nowbuyorsell == 1) //买 先结束已卖的
  CloseSell();
if (nowbuyorsell == -1) //卖 先结束已买的
    CloseBuy();
if (TimeDayOfWeek(CurTime()) == 1)
  {
  if (TimeHour(CurTime()) < 3 ) return; //周一早8点前不做 具体决定于你的时区和服务器的时区  时间控制
  }
if (TimeDayOfWeek(CurTime()) == 5)
  {
  if (TimeHour(CurTime()) > 19 ) return; //周五晚11点后不做
  }

if (OrdersTotal( ) >= maxOpen) return ;  
//如果已持有开仓次数达到最大,不做
if (nowbuyorsell==0) return;  //不交易
TradeOK();  //去下单交易
}
void TradeOK()  //去下单交易
{
int error ;
if (nowbuyorsell == 1) //买
  {
    switch (whichmethod)
    {
    case 1:  res=OrderSend(Symbol(),OP_BUY,LotsOptimized(),Ask,3,0,0,"",MAGICMA,0,Blue);break;
    case 2:  res=OrderSend(Symbol(),OP_BUY,LotsOptimized(),Ask,3,Ask-StopLoss*Point,0,"",MAGICMA,0,Blue); break;
    case 3:  res=OrderSend(Symbol(),OP_BUY,LotsOptimized(),Ask,3,0,Ask+TakeProfit*Point,"",MAGICMA,0,Blue);break;
    case 4:  res=OrderSend(Symbol(),OP_BUY,LotsOptimized(),Ask,3,Ask-StopLoss*Point,Ask+TakeProfit*Point,"",MAGICMA,0,Blue);break;
    default : res=OrderSend(Symbol(),OP_BUY,LotsOptimized(),Ask,3,0,0,"",MAGICMA,0,Blue);break;
    }
    if (res <=0)
    {
    error=GetLastError();
    if(error==134)Print("Received 134 Error after OrderSend() !! ");        // not enough money
    if(error==135) RefreshRates();  // prices have changed
    }
    Sleep(5000);
    return ;  
  }
if (nowbuyorsell == -1) //卖
  {
    switch (whichmethod)
    {
    case 1:  res=OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,3,0,0,"",MAGICMA,0,Red); break;
    case 2:  res=OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,3,Bid+StopLoss*Point,0,"",MAGICMA,0,Red); break;
    case 3:  res=OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,3,0,Bid-TakeProfit*Point,"",MAGICMA,0,Red); break;
    case 4:  res=OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,3,Bid+StopLoss*Point,Bid-TakeProfit*Point,"",MAGICMA,0,Red); break;
    default : res=OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,3,0,0,"",MAGICMA,0,Red); break;
    }
    if (res <=0)
    {
    error=GetLastError();
    if(error==134) Print("Received 134 Error after OrderSend() !! ");        // not enough money
    if(error==135) RefreshRates();  // prices have changed
    }
    Sleep(5000);
    return ;  
  }
}
void CTP()  //跟踪止赢
{
bool bs = false;
for (int i = 0; i < OrdersTotal(); i++)
{
  if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false)    break;
  if (OrderType() == OP_BUY)
  {
    if ((Bid - OrderOpenPrice()) > (TrailingStop * MarketInfo(OrderSymbol(), MODE_POINT)))    //开仓价格 当前止损和当前价格比较判断是否要修改跟踪止赢设置
    {
    if (OrderStopLoss() < Bid - TrailingStop * MarketInfo(OrderSymbol(), MODE_POINT))
    {
      bs = OrderModify(OrderTicket(), OrderOpenPrice(), Bid - TrailingStop * MarketInfo(OrderSymbol(), MODE_POINT), OrderTakeProfit(),0, Green);
    }
    }
  }
  else if (OrderType() == OP_SELL)
  {
    if ((OrderOpenPrice() - Ask) > (TrailingStop * MarketInfo(OrderSymbol(), MODE_POINT)))  //开仓价格 当前止损和当前价格比较判断是否要修改跟踪止赢设置

    {
    if ((OrderStopLoss()) > (Ask + TrailingStop * MarketInfo(OrderSymbol(), MODE_POINT)))
    {    
      bs = OrderModify(OrderTicket(), OrderOpenPrice(),
        Ask + TrailingStop * MarketInfo(OrderSymbol(), MODE_POINT), OrderTakeProfit(),0, Tan);
}
    }
  }
}
}
华丽的分割线
=====================================================================
EA中文注释

    原帖由 白色流星 于 2007-12-1 20:58 发表
    首先我们先解读一下系统自带的MACDEA~这个相对简单~
    //+------------------------------------------------------------------+
    //| MACD Sample.mq4 |
    //| ... 

extern double TakeProfit = 50;  盈利目标点数
extern double Lots = 0.1;        每单入场的手数
extern double TrailingStop = 30; 追踪止损的点数
extern double MACDOpenLevel=3; MACD开仓的参考位置
extern double MACDCloseLevel=2; MACD出场的参考位置
extern double MATrendPeriod=26; 条件中使用的MA均线的周期数
程序最上面extern开始的这些数据都是程序参数,也就是在使用者调用的时候可以修改的部分。
这个EA是个常见的技术指标条件入场,条件出场 同时又移动止损功能的完成示意,很适合初学者研究。
先总结这个程序的基本条件的意思 以方便大家对号入座,尽快理解。
多头入场条件:
  MACD小于0 并且 小于指定的参数MACDOpenLevel  并且 MACD讯号下下穿基准线(死叉) 并且 MA向上趋势
多头出场条件:
  MACD大于0 并且 大于指定的参数MACDCloseLevel 并且 MACD信号线上传基准线(金叉)

空头入场条件:
MACD大于0 并且 大于指定的参数MACDOpenLevel  并且 MACD讯号线上穿基准线(金叉) 并且 MA向下趋势
空头出场条件:
MACD小于0 并且 小于制定的参数MACDCloseLevel  并且 MACD讯号线下穿基准线(死叉)

=============================================================
有了以上的初步了解,下面开始进行EA程序基本结构的分析:
1、start()函数是最重要的执行部分,每来一个价格 此函数都自动执行一次,所以主要的逻辑结构都在这个函数里
2、程序的基本流程都是按照以下步骤进行,我们先牢牢记住这个结构,然后再对号入座去理解程序。
    先判断当前自身的仓位状态,因为start函数式循环运行的,所以中间的每个步骤都会使用start函数,因此,当函数开始的时候我们首先要通过MT4的仓位操作函数获得当前的仓位状态,并进一步根据状态进行不同分支的计算。
    程序开始的以下两个部分不重要 简单说一下:
if(Bars<100)
    {
      Print("bars less than 100");
      return(0);  
    }
以上是说如果当前图形的K线个数少于100 则不进行运算 直接返回。这种情况一般不会出现,所以我们自己写程序的时候可以不写这部分。
  if(TakeProfit<10)
    {
      Print("TakeProfit less than 10");
      return(0);  // check TakeProfit
    }
以上这段意思是参数TakeProfit移动止损点数的设定如果小于10点,则发出报警,并返回不进行运算。这是为了防止乱设数值,引起后面计算的错误。这部分,如果程序只是我们自己使用,估计不会犯这种低级错误,所以写程序的时候也可以忽略不写。
下面这段:
  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);
这部分是变量赋值部分,等于提前计算出为后面用到的当前MACD数值以及MA数值,这样提前写出来在后面直接使用赋值后的变量就很清楚了。是很好的编程习惯。
  再下面开始最主要的程序逻辑部分,首先遇到的就是我们上面说过的通过仓位函数获得当前状态的部分。
total=OrdersTotal(); 通过函数获得当前持仓单的个数,如果持仓单个数小于1,则说明是空仓状态,那末就进行多头和空头的入场条件判断,如果满足条件则进行入场。代码如下:
if(total<1)
    {
      // no opened orders identified
      if(AccountFreeMargin()<(1000*Lots))  这句诗判断保证金余量是否够下单,如果不够则直接返回,并不进行后续入场判断
        {
        Print("We have no money. Free Margin = ", AccountFreeMargin());
        return(0);  
        }
      // check for long position (BUY) possibility
      if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious<SignalPrevious &&
        MathAbs(MacdCurrent)>(MACDOpenLevel*Point) && MaCurrent>MaPrevious) 这句就是多头入场条件的判断,可以看到2个技巧,1、交叉的数学意思是“前面再下后面在上”或反之 2、MA向上趋势 的数学意思是当前K线的MA大于上一K线的MA数值
        {
        ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,0,Ask+TakeProfit*Point,"macd sample",16384,0,Green); 这是入场语句记得一定要判断入场是否成功,因为很多服务器由于滑点或者服务器价格变动而不能入场成功,所以,要判断入场不成功后作出提示。ticket就是定单入场是否成功的标记。
        if(ticket>0) 大于0说明入场成功
          {
            if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) Print("BUY order opened : ",OrderOpenPrice());
          }
        else Print("Error opening BUY order : ",GetLastError()); 入场不成功,输出不成功的系统原因。
        return(0); 这里为什么使用了返回呢。因为一种情况是入场成功,那末直接返回等待下一个价格到来的时候再执行start函数,另一种情况是入场不成功,则返回也是等待下一个价格到来的时候在此执行入场操作。
        }
      下面就是空单入场的判断了,大家自己对照观看即可
      // check for short position (SELL) possibility
      if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious &&
        MacdCurrent>(MACDOpenLevel*Point) && MaCurrent<MaPrevious)
        {
        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());
        return(0);
        }
      return(0);
    }
华丽的分割线
===================================================================================
EA中文注释2
#property copyright "Copyright ?2007, 520FX Corp." //指标版权信息
#property link "http://www.520fx.com" //指标联系的网站链接
//=====可调参数部分==============
#define Magic 20090101 //预定义的常量 Magic用于后面程序里的开仓动作时标记在订单里面的一个符号,用于区别其他EA程序下的单 防止混乱
extern int N=50; //参数 后面程序里用它作为N根K线的数量
extern int SL=100;//参数 后面程序里下单的时候用这个设置的点数作为入场时订单的止损价格。
extern int TrailingStop=30;//参数 后面程序里用这个作为移动止损的点数设置
extern double 每单手数=0.1;//参数 表示后面下单的仓位的大小
extern int 滑点偏移点数=3;//参数 表示下单时 服务器端的价格与当前看到的价格相差的范围,如果在此范围内,则允许以服务器端的价格成交
//----全局变量===================
int Tick;//用于记录订单的唯一编号
double StopLost;//用于记录止损

//========主函数部分开始============
int start()//主函数 没来一个价格这个函数就运行一次
{
int Ticket; //局部变量 用于记录每次下单后的状态,用于判断下单动作是否成功,如果不成功则做相应处理和提示
int OrderTypeNow=GetOrderTypeHolding();//通过自定义函数得到当前持仓单的交易类型 买 卖
//自定义函数中做了处理,如果没有发现当前有持仓 则返回-1
if (OrderTypeNow==-1)//空仓阶段 -1表示没有持仓的状态
{
if (TradeOrNo(1))//多单入场条件 自定义函数TradeOrNo(1)参数1 表示针对多单的方向进行判断是否满足入场条件
{
Ticket=OrderSend(Symbol(),OP_BUY,每单手数,Ask,滑点偏移点数,Ask-SL*Point,0,"",Magic,0,0);//多单入场
//Ticket表示入场动作的执行结果,如果小于0表示入场动作失败
if(Ticket<0)
{
Print("多单入场失败"+GetLastError());
return(0); //推出本次start函数的执行
}
}else
if (TradeOrNo(2))//空单入场条件
{
Ticket=OrderSend(Symbol(),OP_SELL,每单手数,Bid,滑点偏移点数,Bid+SL*Point,0,"",Magic,0,0);
if(Ticket<0)
{
Print("空单入场失败"+GetLastError());
return(0);
}
}
return;
}else//===============持仓阶段===========================
{
switch(OrderTypeNow)
{
case OP_BUY://多单持仓情况下,满足空单入场条件
if (TradeOrNo(2))
{
if(OrderClose(Tick,OrderLots(),Bid,滑点偏移点数)==false)//平掉多单持仓单
{
Print("翻转发生 多头平仓失败"+GetLastError());
return;
}else//平仓后,反手建立空单
{
Ticket=OrderSend(Symbol(),OP_SELL,每单手数,Bid,滑点偏移点数,Bid+SL*Point,0,"",Magic,0,0);
if(Ticket<0)
{
Print("空单反手建仓失败"+GetLastError());
return(0);
}
}
}else //判断移动止损
{
if (Ask>StopLost+2*TrailingStop*Point)
{
OrderModify(Tick,OrderOpenPrice(),StopLost+TrailingStop*Point,0,0,CLR_NONE);
return;
}
}
break;
case OP_SELL:
if (TradeOrNo(1))
{
if(OrderClose(Tick,OrderLots(),Ask,滑点偏移点数)==false)//平掉空单持仓单
{
Print("翻转发生 空头平仓失败"+GetLastError());
return;
}else//平仓后,反手建立多单
{
Ticket=OrderSend(Symbol(),OP_BUY,每单手数,Ask,滑点偏移点数,Ask-SL*Point,0,"",Magic,0,0);
if(Ticket<0)
{
Print("多单反手建仓失败"+GetLastError());
return(0);
}
}
}else //判断移动止损
{
if (Bid<StopLost-2*TrailingStop*Point)
{
OrderModify(Tick,OrderOpenPrice(),StopLost-TrailingStop*Point,0,0,CLR_NONE);
return;
}
}
break;
}
return;
}

return(-1);
}
//=================自定义函数部分======================================
int GetOrderTypeHolding()//从最近持仓单提取订单类型,如果没有持仓单,则认为是止赢出场或程序刚开始运行返回-1
{int Type=-1;
//int temptime=0;
for(int i=OrdersTotal()-1;i>=0;i--)
{
OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
if(OrderSymbol()==Symbol() && OrderMagicNumber()==Magic )
{
Type=OrderType();
Tick=OrderTicket();
StopLost=OrderStopLoss();
}
}
return(Type);
}
//======================================================
bool TradeOrNo(int Type)//判断当前指定方向的入场条件是否成立
{
double NHigh=High[iHighest(Symbol(),0,MODE_HIGH,N,2)];
double NLow=Low[iLowest(Symbol(),0,MODE_LOW,N,2)];
switch(Type)
{
case 1://判断多单入场条件是否成立
if (Close[1]>NHigh)//做多条件成立
{
return(true);
}
break;
case 2:
if (Close[1]<NLow)//做空条件成立
{
return(true);
}
break;
}
return(false);
}

本文标签: