MT4自带的EA :Moving Average 详解
//+------------------------------------------------------------------+
//| Moving Average.mq4 |
//| Copyright ?2005, MetaQuotes Software Corp. |
//| https://www.doczj.com/doc/e04953974.html,/ |
//+------------------------------------------------------------------+
#define MAGICMA 20050610 //定义本EA操作的订单的唯一标识号码,由此可以实现在同一账户上多系统操作,各操作EA的订单标识码不同,就不会互相误操作。凡是EA皆不可缺少,非常非常重要!!!
//宏定义命令#define用法https://www.doczj.com/doc/e04953974.html,/xyls7570/blog/item/9c9b43cfde98180b92457eb2.html
extern double Lots = 0.1;//每单的交易量
extern double MaximumRisk = 0.02;//本系统最大可以动用总资金的2%
extern double DecreaseFactor = 3;//作者定义的参数,作用要看程序中的用法
extern double MovingPeriod = 10;//EA中使用的均线的周期
extern double MovingShift =3;//EA中使用的均线向左的K线偏移量
//extern 确定从外部程序输入的变量,会直接显现输入数据窗口。数列本身不能作为外部变量。
//+------------------------------------------------------------------+
//| Calculate open positions |
//+------------------------------------------------------------------+
int CalculateCurrentOrders(string symbol)//函数作用,计算当前持仓订单的数量{
int buys=0,sells=0;//定义两个临时变量,准备用于后面的多空订单的个数计算
//----
for(int i=0;i { if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;//挑出持仓单的每一个订单位置 if(OrderSymbol()==Symbol() && OrderMagicNumber()==MAGICMA)//根据订单位置,比较是否是当前K线商品以及订单唯一标识号是否和本程序设置的一致,即判断这个订单是不是当前EA操作的。(用于避免EA误操作其他程序控制的持仓单) { if(OrderType()==OP_BUY) buys++;//找到符合条件的持仓单后,如果是多单,则临时变量buys增加1 if(OrderType()==OP_SELL) sells++;//找到符合条件的持仓单后,如果是空单,则临时变量sells增加1 } } //---- return orders volume if(buys>0) return(buys); else return(-sells);//本函数返回查询计算结束时的持仓单的个数.这种模式返回是假设不存在锁单的。 } //+------------------------------------------------------------------+ //| Calculate optimal lot size | //+------------------------------------------------------------------+ double LotsOptimized()//函数目的,根据要求计算出订单交易量 { double lot=Lots; int orders=HistoryTotal(); // history orders total 历史出场订单的个数 int losses=0; // number of losses orders without a break //---- select lot size lot=NormalizeDouble(AccountFreeMargin()*MaximumRisk/1000.0,1);//通过风险系数的计算获得当前入场单应该采用的交易量,除以1000是因为大多货币对汇价都在这个附近。 //---- calcuulate number of losses orders without a break if(DecreaseFactor>0) { for(int i=orders-1;i>=0;i--) { if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==false) { Print("Error in history!"); break; }//循环查询出场单队列 if(OrderSymbol()!=Symbol() || OrderType()>OP_SELL) continue;// //---- if(OrderProfit()>0) break; if(OrderProfit()<0) losses++;//循环计算所有出场亏损单的亏损总和 } if(losses>1) lot=NormalizeDouble(lot-lot*losses/DecreaseFactor,1);//如果亏损额大于1,则下一入场单的交易量修正为新的计算结果。 } //---- return lot size if(lot<0.1) lot=0.1;//如果计算出的交易量小于帐户最小手数0.1,则下一入场单的交易手数使用0.1作为交易量 return(lot); } //+------------------------------------------------------------------+ //| Check for open order conditions | //+------------------------------------------------------------------+ void CheckForOpen()//检查入场条件的情况并作处理 { double ma; int res; //---- go trading only for first tiks of new bar,注意下面采用的Volume[0],Open[1]等可以确保交易是在当前周期下k线收盘价走完才发生的。 if(Volume[0]>1) return;//如果当前K线持仓量(成交量)大于1,说明不是K线的开盘时间点, 即当前k线还没收盘确定,则直接返回否则是K线第一个价格,则继续下面的过程 //---- get Moving Average ma=iMA(NULL,0,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE,0);//获得当前的均线数值 //---- sell conditions if(Open[1]>ma && Close[1] { res=OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,3,0,0,"",MAGICMA,0,Red); return; } //---- buy conditions if(Open[1] { res=OrderSend(Symbol(),OP_BUY,LotsOptimized(),Ask,3,0,0,"",MAGICMA,0,Blue); return; } //---- } //+------------------------------------------------------------------+ //| Check for close order conditions | //+------------------------------------------------------------------+ void CheckForClose()//检查出场条件的情况并作处理 { double ma; //---- 只在一个k收盘另一个新出现时交易 if(Volume[0]>1) return; //---- get Moving Average ma=iMA(NULL,0,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE,0); //---- for(int i=0;i { if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break; if(OrderMagicNumber()!=MAGICMA || OrderSymbol()!=Symbol()) continue; //----确定是不是自己系统下的单子。 if(OrderType()==OP_BUY) //多单平仓 { if(Open[1]>ma && Close[1] } if(OrderType()==OP_SELL) //空单平仓 { if(Open[1] break; } } //---- } //+------------------------------------------------------------------+ //| Start function | //+------------------------------------------------------------------+ void start()//主循环过程 { //---- check for history and trading if(Bars<100 || IsTradeAllowed()==false) return; //---- calculate open orders by current symbol if(CalculateCurrentOrders(Symbol())==0) CheckForOpen(); else CheckForClose(); //---- } MT4自带EA:MACD Sample详解 //+------------------------------------------------------------------+ //| MACD Sample.mq4 | //| ... [/quote] 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 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 { 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); } MT4自带EA:MACD Sample详解-2002 步骤3 –集中程序的结果代码 让我们打开智能交易的设定:使用按钮打开”属性…”菜单。在窗口内指定运行参量的外部设定: 从先前部分集中全部代码: //+------------------------------------------------------------------+//| MACD Sample.mq4 |//| Copyright ?2005, MetaQuotes Software Corp. |//| https://www.doczj.com/doc/e04953974.html,/ |//+------------------------------------------------------------------+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;//+------------------------------------------------------------------+//| |//+------------------------------------------------------------------+int start() { double MacdCurrent, MacdPrevious, SignalCurrent; double SignalPrevious, MaCurrent, MaPrevious; int cnt, ticket, total;// 检测初始化数据// 确定智能交易在图表中运行正常非常重要// 用户在外部变量交易中不会产生任何错误// 外部变量(标准手数, 止损,赢利, // 追踪止损) 在这种情况下,我们检测图表中赢利水平要小于100 柱if(Bars<100) { Print("少于100柱"); return(0); } if(TakeProfit<10) { Print("赢利少于10"); return(0); // 检测赢利水平}// 简化代码和加速通道// 数据被放置在内部变量中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); total=OrdersTotal(); if(total<1) { // 没有指定开单if(AccountFreeMargin()<(1000*Lots)) { Print("没有资金. 自由保证金= ", AccountFreeMargin()); return(0); } // 尽可能检测看涨仓位(BUY) if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious { OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet); //平仓return(0); // 退出} // 检测追踪止损if(TrailingStop>0) { if(Bid-OrderOpenPrice()>Point*TrailingStop) { if(OrderStopLoss() return(0); } } } } else // 去卖空仓位{ // 需要平仓吗? if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious { if((OrderOpenPrice()-Ask)>(Point*TrailingStop)) { if((OrderStopLoss()>(Ask+Point*TrailingStop)) || (OrderStopLoss()==0)) { OrderModify(OrderTicket(),OrderOpenPrice(),Ask+Point*TrailingStop, OrderTakeProfit(),0,Red); return(0); } } } } } } return(0); }// 结束对于最后智能交易的确认,只需要指定外部变量值“Lots = 1″, “Stop Loss (S/L) = 0″(not used), “Take Profit (T/P) = 120″(appropriate for one-hour intervals), “Trailing Stop (T/S) = 30″. 当然,你可以使用自己的值。按“编写”按钮,如果没有任何错误信息出现(你可以从MetaEditor的列表中复制), 按“保存”键保存智能交易。 MT4编程:自带的DLL范例 俺不是编程高手,而且时间和精力都很有限,因此编程对于我来说最理想的境界是"知其然",而不必"知其所以然"。当然,如果程序出错,那就要好好研究一下"其所以然"了。所以每次编程都会经历一个预热的学习过程,看看范例--然后温故而知新......MT4自带的DLL 范例,就放在在文件夹MetaTrader 4\EXPERTS\SAMPLES中。该范例值得细细研究,是因为它展示了如何使用mq4语言来调用C++语言编写的DLL。而我们需要重点留意的,就是调用DLL函数时所展现的函数参数的传递方式;显然,针对不同类型的变量,都有其不同的传递方式,实现的结果亦各不相同。 1)变量传递。 对于mq4的double/int类型变量,与C++的通讯只需要用到值传递。 在C++里我们要定义一个函数,如func1(double x,int y){......;......;} mq4里我们必须在头文件里做一个函数声明:func1(double,int),调用的时候以相应的变量值作为参数,如func1(10.56,8)。 对于mq4的String类型,在C++里可以用指针如char *str来代替String类型。 在C++里我们要定义一个函数,如func2(char *str){......;......;} mq4里我们必须在头文件里做一个函数声明:func2(string),调用的时候以字符串作为参数,如func2("something")。 2)数组的传递。 对于mq4的double/int类型数组,C++通过指针来接收相应的参数。 关于数组与指针,在网上查阅了很多论述:其实,在C++中数据名作为函数形参时,等同于指向数组的指针! 于是,下面2个函数是等效的: double sample1(double*); //在声明中,描述参数为(指向数组的)指针:double*; ...... double sample1(double aa[]) //在函数中,以aa[](数组)来接收该指针。 { aa[4]=55.5; return(aa[4]); } double sample2(double []); //在声明中,描述参数为数组:double []; ...... double sample2(double *aa) //在函数中,以*aa(指针)来接收该数组。 { aa[4]=55.5; return(aa[4]); } 当然,2个函数的声明其实也是等效的。mq4中没有指针类型,所以传递数组的方式类似sample2。 3)行情数据的传递 mq4提供了ArrayCopyRates函数,用于复制一段走势图上的数据到一个二维数组,并返回复制柱子的总数。其第二维为固定的6个项目,从0到5分别为“时间、开盘价格、最低价格、最高价格、收盘价格、成交量”。 如: double rates[][6]; int totalRecords = ArrayCopyRates(rates,Symbol(),0); mq4调用DLL函数的时候,把该数组作为参数,向DLL函数提供二维数组的指针,这也就是就mq4程序实现行情数据传递的默认方式。 如: ArrayCopyRates(rates); price=GetRatesItemValue(rates,Bars,0,CLOSE_INDEX); 对应地,我们在C++代码中可以定义一个结构类型RateInfo: struct RateInfo { unsigned int time; //时间 double open; //开盘价格 double low; //最低价格 double high; //最高价格 double close; //收盘价格 double volume; //成交量 }; 这里的RateInfo结构定义正好对应mq4里二维数组的第二维,在DLL函数里,结构指针RateInfo*被映射为二维数组double rates[][6]。也就是说,当mq4调用DLL的时候,由操作系统根据内存指针完成了数据的访问,且结构定义中的unsigned int是从double类型转换后得到的。 需要注意的是:mq4数组顺序与DLL数组顺序完全相反。mq4数组顺序是:从Bars-1到0;而传递到DLL后,数组顺序变为0到Bars-1? MT4自带EA:MACD Sample详解-2001 MetaQuotes语言4 是需要“外部变量”辅助的。外部变量可以从外部设定,在智能交易程序源代码设定之后不可以修改。提供一个额外的灵活性。在我们的程序中,MATrendPeriod 变量作为外部变量指定。在程序开始我们插入这个变量。 检测初始数据 该代码部分通常使用在所有的智能交易中。因为是一个标准的检测: // 初始数据检测// 确认智能交易运行正常非常重要//图表和用户设置不能出现任何错误// 变量(Lots, StopLoss, TakeProfit, // TrailingStop) 我们的情况需要检测TakeProfit// 图表 中少于100 柱if(Bars<100) { Print("少于100柱"); return(0); } if(TakeProfit<10) { Print("赢利少于10"); return(0); // 检测TakeProfit }对于数据的快速通道设置内部变量 在源代码中经常需要注意指标值或计算值。简化代码和数据放置在内部变量中。 int start() { double MacdCurrent, MacdPrevious, SignalCurrent; double SignalPrevious, MaCurrent, MaPrevious; int cnt, ticket, total;// 简化代码//数据放置在内部变量中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(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,0)代替,您可以在源代码中使用MacdCurrent。 检测交易终端–是空的吗?如果是: 在我们的智能交易中,我们仅使用开单和操作挂单。不过,使更安全,我们来认识一种对于先前定单交易终端检测: total=OrdersTotal(); if(total<1) {检测: 账户上的可用保证金… 在分析市场状况之前,检测你的账户上可用的自由保证金可以开仓。 if(AccountFreeMargin()<(1000*Lots)) { Print("没有资金.自由保证金= ", AccountFreeMargin()); return(0); }可能是看涨仓位(BUY)? 进入看涨仓位的条件: MACD 低于零,向上并且穿过信号线向下。这就是我们在MQL4中描述的(注意我们在指标上的业务值保存在先前的变量中): // 尽可能检测看涨仓位(BUY) 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 开单: ",OrderOpenPrice()); } else Print("错误opening BUY order : ",GetLastError()); return(0); }附加的检验‘山丘’的大小上面已经给出了描述。MACDOpenLevel变量是一个用户指定变量,它不可能改变程序文本,但是却有很大的灵活性。在程序开始我们插入这个变量的描述。 可能是卖空仓位(SELL)? 进入卖空仓位的条件: MACD高于零,向上并且穿过信号线向下。注解如下: // 尽可能的检测卖空仓位(SELL) 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 开单: ",OrderOpenPrice()); } else Print("错误SELL定单开仓: ",GetLastError()); return(0); }return(0); }周期循环检验先前开仓 //进入市场的正确性非常重要// 但是更重要的是安全退出... for(cnt=0;cnt { OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES); if(OrderType()<=OP_SELL && // 检验开仓OrderSymbol()==Symbol()) // 检验货币对{“cnt”–”是一个循环的变量必须在程序开始指定如下: int cnt = 0;如果是看涨仓位 if(OrderType()==OP_BUY) // 打开看张仓位{应该平仓吗? 退出看涨仓位的条件: MACD 穿过信号线,MACD 高于零,向上并穿过信号线向下。 if(MacdCurrent>0 && MacdCurrentSignalPrevious && MacdCurrent>(MACDCloseLevel*Point)) { OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet); //平仓return(0); //退出}应该重设追踪止损马? 我们设定追踪止损只有在仓位盈利已经超过追踪水平点,并且新的止损水平点好于先前的水平。 // 检测追踪止损if(TrailingStop>0) { if(Bid-OrderOpenPrice()>Point*TrailingStop) { if(OrderStopLoss() { OrderModify(OrderTicket(),OrderOpenPrice(),Bid-Point*TrailingStop, OrderTakeProfit(),0,Green); return(0); } } }我们停止操作符。 }如果是卖空仓位 else //卖空仓位{应该平仓吗? 退出卖空仓位的条件: MACD穿过信号线,MACD低于零,向上并且穿过信号线向下。 if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious(MACDCloseLevel*Point)) { OrderClose(OrderTicket(),OrderLots(),Ask,3,Violet); //平仓return(0); // 退出}应该重设追踪止损吗? 我们设定追踪止损只有在仓位盈利已经超过追踪水平点,并且新的止损水平点好于先前的水平。 // 检测追踪止损if(TrailingStop>0) { if((OrderOpenPrice()-Ask)>(Point*TrailingStop)) { if((OrderStopLoss()>(Ask+Point*TrailingStop)) || (OrderStopLoss()==0)) { OrderModify(OrderTicket(),OrderOpenPrice(),Ask+Point*TrailingStop, OrderTakeProfit(),0,Red); return(0); } } }关闭所有残留开仓。 } } } return(0);} 编制自动交易系统的基本知识 (2012-02-12 12:16:04) 分类:MT4编程入门 编制自动交易系统的基本知识 Introduction介绍 鉴于许多中国的交易者对交易系统了解不多,本文解释使用MQ4语言编制自动交易系统的基本知识. Title 编制自动交易系统的基本知识 一个交易系统大致包括以下几个方面: 1 开仓策略,即什么条件满足时开仓, 如某条线和某条线上交叉或下交叉, 2 平仓策略,即什么条件满足时平仓, 包括止赢设置,止损设置,和跟踪止赢设置三个方面. 3 资金管理, 其中一个方面就是下单的大小 4 时间管理, 如持仓时间,开平仓时间间隔等 5 账户状态分析,如交易历史,当前资金/仓位/各仓为盈亏状态等. 当然一个交易系统不必包括全部内容,本文做为入门知识也仅通过实例介绍交易系统程序的基本构成. //#property copyright "Copyright 2007 , Dxd, China." #define MAGICMA 200610011231 //+------------------------------------------------------------------+ //| 注意没有指标文件那些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 && MaCurrent>MaPrevious) return (1); // 买 Ma在上升,Macd在0线上,并且两线上交叉 if(MacdCurrent>0 && MacdCurrent MacdPrevious>SignalPrevious && MaCurrent 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*Poi nt,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*Poi nt,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*Po int,0,"",MAGICMA,0,Red); break; case 3: res=OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,3,0,Bid-TakeProfi t*Point,"",MAGICMA,0,Red); break; case 4: res=OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,3,Bid+StopLoss*Po int,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框架模型,大部分地方做了注释 现在我学会了EA基本的东西,并且按照框架思路建立了EA框架模型,大部分地方做了注释。希望对大家有用; 程序代码如下: //+------------------------------------------------------------------+ //| ganendexin's 模板.mq4 | //| Copyright ?2008, MetaQuotes Software Corp. | //| https://www.doczj.com/doc/e04953974.html, //+------------------------------------------------------------------+ #property copyright "ganendexin" #property link "https://www.doczj.com/doc/e04953974.html," //---- input parameters extern double TakeProfit=250.0; extern double Lots=0.1; extern double TrailingStop=35.0; //+------------------------------------------------------------------+ //| expert initialization function | //+------------------------------------------------------------------+ int init() { //---- //---- return(0); } //+------------------------------------------------------------------+ //| expert deinitialization function | //+------------------------------------------------------------------+ int deinit() { //---- //---- return(0); } //信号部分,下面这部分给出的是买卖信号,这个信号可以是自己编写的,也可以是用iCustom来调用的。以后需要修改的大部分是在这里面改 int Crossed (double line1 , double line2) { static int last_direction = 0; static int current_direction = 0; if(line1>line2)current_direction = 1; //up if(line1 if(current_direction != last_direction) //changed { last_direction = current_direction; return (last_direction); } else { return (0); } } //+------------------------------------------------------------------+ //| expert start function | //+------------------------------------------------------------------+ int start() { //---- //程序开始前,先定义变量。 int cnt, ticket, total; //用于检查订单的个数及类型,cnt是按照索引来计算,ticket是按照ticket 来计算。在算类型之前,要先OrderSelect double shortEma, longEma; //这个地方是定义买卖信号的参数的,根据实际需要来定个数和类型。 int counted_bars; //如果需要控制最低的K线个数,可用下面的 //提示获利点,这个是有的系统对最小获利点有要求的情况下使用。例如FXDD要求为10. if(TakeProfit<10) { Print("TakeProfit less than 10"); return(0); // check TakeProfit }